diff --git a/DEPS b/DEPS index 41b2a7e..e7f9cd5 100644 --- a/DEPS +++ b/DEPS
@@ -40,11 +40,11 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling Skia # and whatever else without interference from each other. - 'skia_revision': '370c2b304a35297d36fcee91e3b6ac516091434d', + 'skia_revision': 'e4d45bf5ba413e5a26d4f6c24886bbd104b14885', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling V8 # and whatever else without interference from each other. - 'v8_revision': '0f043477b1c8e56d871237ef0d13fe3296c15b94', + 'v8_revision': 'c5e8f7690bbb9e99851f08fdf45930da4cd62dab', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling swarming_client # and whatever else without interference from each other. @@ -64,7 +64,7 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling PDFium # and whatever else without interference from each other. - 'pdfium_revision': '1d95c68f912102dfda5d6e9ad7ca79411cda5900', + 'pdfium_revision': '4f34c64914be17966f2d91591921dec635582061', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling openmax_dl # and whatever else without interference from each other. @@ -96,7 +96,7 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling catapult # and whatever else without interference from each other. - 'catapult_revision': '4cafad75c8313d6c14b47544574a20ecc49c253f', + 'catapult_revision': 'b0384fe60f101e921782716d3a7a1881de5b37ea', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling libFuzzer # and whatever else without interference from each other. @@ -154,7 +154,7 @@ Var('chromium_git') + '/external/github.com/google/googletest.git' + '@' + '42bc671f47b122fad36db5eccbc06868afdf7862', 'src/third_party/icu': - Var('chromium_git') + '/chromium/deps/icu.git' + '@' + 'ae18d60831126f902d778541495194380ff77fd8', + Var('chromium_git') + '/chromium/deps/icu.git' + '@' + 'dfa798fe694702b43a3debc3290761f22b1acaf8', 'src/third_party/hunspell_dictionaries': Var('chromium_git') + '/chromium/deps/hunspell_dictionaries.git' + '@' + 'dc6e7c25bf47cbfb466e0701fd2728b4a12e79d5', @@ -241,7 +241,7 @@ Var('chromium_git') + '/external/github.com/open-source-parsers/jsoncpp.git' + '@' + 'f572e8e42e22cfcf5ab0aea26574f408943edfa4', # from svn 248 'src/third_party/libyuv': - Var('chromium_git') + '/libyuv/libyuv.git' + '@' + '8edd2286fdf9df2b9da806bda7ed262492f95921', # from r1655 + Var('chromium_git') + '/libyuv/libyuv.git' + '@' + '7bffe5e1c54bc22daebd57003735e61693719ac6', # from r1655 'src/third_party/smhasher/src': Var('chromium_git') + '/external/smhasher.git' + '@' + 'e87738e57558e0ec472b2fc3a643b838e5b6e88f',
diff --git a/ash/BUILD.gn b/ash/BUILD.gn index 9944a1eb..46dffa9 100644 --- a/ash/BUILD.gn +++ b/ash/BUILD.gn
@@ -306,9 +306,6 @@ "shelf/shelf_layout_manager_observer.h", "shelf/shelf_locking_manager.cc", "shelf/shelf_locking_manager.h", - "shelf/shelf_model.cc", - "shelf/shelf_model.h", - "shelf/shelf_model_observer.h", "shelf/shelf_observer.h", "shelf/shelf_tooltip_manager.cc", "shelf/shelf_tooltip_manager.h", @@ -1192,7 +1189,6 @@ "shelf/shelf_controller_unittest.cc", "shelf/shelf_layout_manager_unittest.cc", "shelf/shelf_locking_manager_unittest.cc", - "shelf/shelf_model_unittest.cc", "shelf/shelf_tooltip_manager_unittest.cc", "shelf/shelf_unittest.cc", "shelf/shelf_view_unittest.cc",
diff --git a/ash/metrics/user_metrics_recorder.cc b/ash/metrics/user_metrics_recorder.cc index 065ad0f..f89748b 100644 --- a/ash/metrics/user_metrics_recorder.cc +++ b/ash/metrics/user_metrics_recorder.cc
@@ -7,10 +7,10 @@ #include "ash/metrics/desktop_task_switch_metric_recorder.h" #include "ash/metrics/pointer_metrics_recorder.h" #include "ash/public/cpp/shelf_item.h" +#include "ash/public/cpp/shelf_model.h" #include "ash/public/cpp/shell_window_ids.h" #include "ash/session/session_controller.h" #include "ash/shelf/shelf.h" -#include "ash/shelf/shelf_model.h" #include "ash/shelf/shelf_view.h" #include "ash/shell.h" #include "ash/wm/window_state.h"
diff --git a/ash/metrics/user_metrics_recorder_unittest.cc b/ash/metrics/user_metrics_recorder_unittest.cc index d688800..1074339f4 100644 --- a/ash/metrics/user_metrics_recorder_unittest.cc +++ b/ash/metrics/user_metrics_recorder_unittest.cc
@@ -8,8 +8,8 @@ #include "ash/login_status.h" #include "ash/public/cpp/config.h" +#include "ash/public/cpp/shelf_model.h" #include "ash/session/session_controller.h" -#include "ash/shelf/shelf_model.h" #include "ash/shell.h" #include "ash/shell_port.h" #include "ash/test/ash_test_base.h"
diff --git a/ash/public/cpp/BUILD.gn b/ash/public/cpp/BUILD.gn index b8947df..054dd2e 100644 --- a/ash/public/cpp/BUILD.gn +++ b/ash/public/cpp/BUILD.gn
@@ -20,6 +20,9 @@ "shelf_item.h", "shelf_item_delegate.cc", "shelf_item_delegate.h", + "shelf_model.cc", + "shelf_model.h", + "shelf_model_observer.h", "shelf_types.cc", "shelf_types.h", "shell_window_ids.cc", @@ -55,6 +58,7 @@ source_set("unit_tests") { testonly = true sources = [ + "shelf_model_unittest.cc", "shelf_struct_traits_unittest.cc", ]
diff --git a/ash/shelf/shelf_model.cc b/ash/public/cpp/shelf_model.cc similarity index 96% rename from ash/shelf/shelf_model.cc rename to ash/public/cpp/shelf_model.cc index 3aa6ade5..73b8b42 100644 --- a/ash/shelf/shelf_model.cc +++ b/ash/public/cpp/shelf_model.cc
@@ -2,14 +2,12 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "ash/shelf/shelf_model.h" +#include "ash/public/cpp/shelf_model.h" #include <algorithm> #include "ash/public/cpp/shelf_item_delegate.h" -#include "ash/shelf/shelf_model_observer.h" -#include "ash/strings/grit/ash_strings.h" -#include "ui/base/l10n/l10n_util.h" +#include "ash/public/cpp/shelf_model_observer.h" namespace ash { @@ -48,11 +46,11 @@ const char kAppListId[] = "jlfapfmkapbjlfbpjedlinehodkccjee"; ShelfModel::ShelfModel() { - // Add the app list item. + // Add the app list item; its title and delegate are set in ShelfController. + // This avoids an ash/public dep on ash/strings, and a Chrome-side delegate. ShelfItem item; item.type = TYPE_APP_LIST; item.id = ShelfID(kAppListId); - item.title = l10n_util::GetStringUTF16(IDS_ASH_SHELF_APP_LIST_LAUNCHER_TITLE); const int index = Add(item); DCHECK_EQ(0, index); }
diff --git a/ash/shelf/shelf_model.h b/ash/public/cpp/shelf_model.h similarity index 92% rename from ash/shelf/shelf_model.h rename to ash/public/cpp/shelf_model.h index fca50d8..530f1d3 100644 --- a/ash/shelf/shelf_model.h +++ b/ash/public/cpp/shelf_model.h
@@ -2,13 +2,13 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef ASH_SHELF_SHELF_MODEL_H_ -#define ASH_SHELF_SHELF_MODEL_H_ +#ifndef ASH_PUBLIC_CPP_SHELF_MODEL_H_ +#define ASH_PUBLIC_CPP_SHELF_MODEL_H_ #include <map> #include <memory> -#include "ash/ash_export.h" +#include "ash/public/cpp/ash_public_export.h" #include "ash/public/cpp/shelf_item.h" #include "ash/public/interfaces/shelf.mojom.h" #include "base/macros.h" @@ -21,11 +21,10 @@ // An id for the AppList item, which is added in the ShelfModel constructor. // Generated as crx_file::id_util::GenerateId("org.chromium.applist") -ASH_EXPORT extern const char kAppListId[]; +ASH_PUBLIC_EXPORT extern const char kAppListId[]; // Model used for shelf items. Owns ShelfItemDelegates but does not create them. -// TODO(msw): Move this to ash/public/cpp and use ASH_PUBLIC_EXPORT. -class ASH_EXPORT ShelfModel { +class ASH_PUBLIC_EXPORT ShelfModel { public: ShelfModel(); ~ShelfModel(); @@ -110,4 +109,4 @@ } // namespace ash -#endif // ASH_SHELF_SHELF_MODEL_H_ +#endif // ASH_PUBLIC_CPP_SHELF_MODEL_H_
diff --git a/ash/shelf/shelf_model_observer.h b/ash/public/cpp/shelf_model_observer.h similarity index 79% rename from ash/shelf/shelf_model_observer.h rename to ash/public/cpp/shelf_model_observer.h index ca8f4054..581d9f1a 100644 --- a/ash/shelf/shelf_model_observer.h +++ b/ash/public/cpp/shelf_model_observer.h
@@ -2,10 +2,10 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef ASH_SHELF_SHELF_MODEL_OBSERVER_H_ -#define ASH_SHELF_SHELF_MODEL_OBSERVER_H_ +#ifndef ASH_PUBLIC_CPP_SHELF_MODEL_OBSERVER_H_ +#define ASH_PUBLIC_CPP_SHELF_MODEL_OBSERVER_H_ -#include "ash/ash_export.h" +#include "ash/public/cpp/ash_public_export.h" #include "ash/public/cpp/shelf_types.h" namespace ash { @@ -13,8 +13,8 @@ struct ShelfItem; class ShelfItemDelegate; -// TODO(msw): Move this to ash/public/cpp and use ASH_PUBLIC_EXPORT. -class ASH_EXPORT ShelfModelObserver { +// An observer interface for shelf item and delegate changes in ShelfModel. +class ASH_PUBLIC_EXPORT ShelfModelObserver { public: // Invoked after an item has been added to the model. virtual void ShelfItemAdded(int index) = 0; @@ -40,4 +40,4 @@ } // namespace ash -#endif // ASH_SHELF_SHELF_MODEL_OBSERVER_H_ +#endif // ASH_PUBLIC_CPP_SHELF_MODEL_OBSERVER_H_
diff --git a/ash/shelf/shelf_model_unittest.cc b/ash/public/cpp/shelf_model_unittest.cc similarity index 98% rename from ash/shelf/shelf_model_unittest.cc rename to ash/public/cpp/shelf_model_unittest.cc index e731c8c..d1fb6ae 100644 --- a/ash/shelf/shelf_model_unittest.cc +++ b/ash/public/cpp/shelf_model_unittest.cc
@@ -2,12 +2,12 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "ash/shelf/shelf_model.h" +#include "ash/public/cpp/shelf_model.h" #include <set> #include <string> -#include "ash/shelf/shelf_model_observer.h" +#include "ash/public/cpp/shelf_model_observer.h" #include "base/strings/stringprintf.h" #include "testing/gtest/include/gtest/gtest.h"
diff --git a/ash/shelf/app_list_shelf_item_delegate.cc b/ash/shelf/app_list_shelf_item_delegate.cc index 3783580..a8cc9bf 100644 --- a/ash/shelf/app_list_shelf_item_delegate.cc +++ b/ash/shelf/app_list_shelf_item_delegate.cc
@@ -6,7 +6,7 @@ #include <utility> -#include "ash/shelf/shelf_model.h" +#include "ash/public/cpp/shelf_model.h" #include "ash/shell.h" namespace ash {
diff --git a/ash/shelf/shelf.cc b/ash/shelf/shelf.cc index ec1b0bf..b57c791 100644 --- a/ash/shelf/shelf.cc +++ b/ash/shelf/shelf.cc
@@ -6,13 +6,13 @@ #include "ash/public/cpp/config.h" #include "ash/public/cpp/shelf_item_delegate.h" +#include "ash/public/cpp/shelf_model.h" #include "ash/public/cpp/shell_window_ids.h" #include "ash/root_window_controller.h" #include "ash/session/session_controller.h" #include "ash/shelf/shelf_bezel_event_handler.h" #include "ash/shelf/shelf_controller.h" #include "ash/shelf/shelf_layout_manager.h" -#include "ash/shelf/shelf_model.h" #include "ash/shelf/shelf_observer.h" #include "ash/shelf/shelf_widget.h" #include "ash/shell.h"
diff --git a/ash/shelf/shelf_controller.cc b/ash/shelf/shelf_controller.cc index 4b51989..16dcbb5 100644 --- a/ash/shelf/shelf_controller.cc +++ b/ash/shelf/shelf_controller.cc
@@ -11,8 +11,10 @@ #include "ash/shelf/app_list_shelf_item_delegate.h" #include "ash/shelf/shelf.h" #include "ash/shell.h" +#include "ash/strings/grit/ash_strings.h" #include "base/auto_reset.h" #include "base/strings/utf_string_conversions.h" +#include "ui/base/l10n/l10n_util.h" #include "ui/base/models/simple_menu_model.h" #include "ui/display/display.h" #include "ui/display/screen.h" @@ -32,9 +34,14 @@ } // namespace ShelfController::ShelfController() { - // Create an AppListShelfItemDelegate for the app list item. + // Set the delegate and title string for the app list item. model_.SetShelfItemDelegate(ShelfID(kAppListId), base::MakeUnique<AppListShelfItemDelegate>()); + DCHECK_EQ(0, model_.ItemIndexByID(ShelfID(kAppListId))); + ShelfItem item = model_.items()[0]; + item.title = l10n_util::GetStringUTF16(IDS_ASH_SHELF_APP_LIST_LAUNCHER_TITLE); + model_.Set(0, item); + model_.AddObserver(this); }
diff --git a/ash/shelf/shelf_controller.h b/ash/shelf/shelf_controller.h index 5b73a388..a55a9f0 100644 --- a/ash/shelf/shelf_controller.h +++ b/ash/shelf/shelf_controller.h
@@ -6,10 +6,10 @@ #define ASH_SHELF_SHELF_CONTROLLER_H_ #include "ash/public/cpp/shelf_item.h" +#include "ash/public/cpp/shelf_model.h" +#include "ash/public/cpp/shelf_model_observer.h" #include "ash/public/cpp/shelf_types.h" #include "ash/public/interfaces/shelf.mojom.h" -#include "ash/shelf/shelf_model.h" -#include "ash/shelf/shelf_model_observer.h" #include "mojo/public/cpp/bindings/binding_set.h" #include "mojo/public/cpp/bindings/interface_ptr_set.h"
diff --git a/ash/shelf/shelf_controller_unittest.cc b/ash/shelf/shelf_controller_unittest.cc index 4926ab05..879cf3c 100644 --- a/ash/shelf/shelf_controller_unittest.cc +++ b/ash/shelf/shelf_controller_unittest.cc
@@ -8,10 +8,10 @@ #include <string> #include "ash/public/cpp/config.h" +#include "ash/public/cpp/shelf_model.h" +#include "ash/public/cpp/shelf_model_observer.h" #include "ash/public/interfaces/shelf.mojom.h" #include "ash/shelf/shelf.h" -#include "ash/shelf/shelf_model.h" -#include "ash/shelf/shelf_model_observer.h" #include "ash/shell.h" #include "ash/test/ash_test_base.h" #include "mojo/public/cpp/bindings/associated_binding.h"
diff --git a/ash/shelf/shelf_tooltip_manager_unittest.cc b/ash/shelf/shelf_tooltip_manager_unittest.cc index 67cbe2e3..62501f4 100644 --- a/ash/shelf/shelf_tooltip_manager_unittest.cc +++ b/ash/shelf/shelf_tooltip_manager_unittest.cc
@@ -5,9 +5,9 @@ #include "ash/shelf/shelf_tooltip_manager.h" #include "ash/public/cpp/config.h" +#include "ash/public/cpp/shelf_model.h" #include "ash/shelf/app_list_button.h" #include "ash/shelf/shelf.h" -#include "ash/shelf/shelf_model.h" #include "ash/shelf/shelf_view.h" #include "ash/shell.h" #include "ash/test/ash_test_base.h"
diff --git a/ash/shelf/shelf_unittest.cc b/ash/shelf/shelf_unittest.cc index 233c73b..73c5d8a7 100644 --- a/ash/shelf/shelf_unittest.cc +++ b/ash/shelf/shelf_unittest.cc
@@ -4,9 +4,9 @@ #include <utility> +#include "ash/public/cpp/shelf_model.h" #include "ash/shelf/shelf.h" #include "ash/shelf/shelf_button.h" -#include "ash/shelf/shelf_model.h" #include "ash/shelf/shelf_view.h" #include "ash/shelf/shelf_widget.h" #include "ash/test/ash_test_base.h"
diff --git a/ash/shelf/shelf_view.cc b/ash/shelf/shelf_view.cc index 75efc9b4..7304bd8 100644 --- a/ash/shelf/shelf_view.cc +++ b/ash/shelf/shelf_view.cc
@@ -11,6 +11,7 @@ #include "ash/drag_drop/drag_image_view.h" #include "ash/public/cpp/config.h" #include "ash/public/cpp/shelf_item_delegate.h" +#include "ash/public/cpp/shelf_model.h" #include "ash/scoped_root_window_for_new_windows.h" #include "ash/screen_util.h" #include "ash/shelf/app_list_button.h" @@ -21,7 +22,6 @@ #include "ash/shelf/shelf_application_menu_model.h" #include "ash/shelf/shelf_button.h" #include "ash/shelf/shelf_constants.h" -#include "ash/shelf/shelf_model.h" #include "ash/shelf/shelf_widget.h" #include "ash/shell.h" #include "ash/shell_delegate.h"
diff --git a/ash/shelf/shelf_view.h b/ash/shelf/shelf_view.h index 42e45ca..8c11c9e6 100644 --- a/ash/shelf/shelf_view.h +++ b/ash/shelf/shelf_view.h
@@ -10,10 +10,10 @@ #include <utility> #include <vector> +#include "ash/public/cpp/shelf_model_observer.h" #include "ash/public/interfaces/shelf.mojom.h" #include "ash/shelf/ink_drop_button_listener.h" #include "ash/shelf/shelf_button_pressed_metric_tracker.h" -#include "ash/shelf/shelf_model_observer.h" #include "ash/shelf/shelf_tooltip_manager.h" #include "base/macros.h" #include "base/memory/weak_ptr.h"
diff --git a/ash/shelf/shelf_view_unittest.cc b/ash/shelf/shelf_view_unittest.cc index 53668a77..6b40462 100644 --- a/ash/shelf/shelf_view_unittest.cc +++ b/ash/shelf/shelf_view_unittest.cc
@@ -11,6 +11,7 @@ #include "ash/public/cpp/config.h" #include "ash/public/cpp/shelf_item_delegate.h" +#include "ash/public/cpp/shelf_model.h" #include "ash/public/cpp/shell_window_ids.h" #include "ash/root_window_controller.h" #include "ash/shelf/app_list_button.h" @@ -20,7 +21,6 @@ #include "ash/shelf/shelf.h" #include "ash/shelf/shelf_button.h" #include "ash/shelf/shelf_constants.h" -#include "ash/shelf/shelf_model.h" #include "ash/shelf/shelf_observer.h" #include "ash/shelf/shelf_tooltip_manager.h" #include "ash/shelf/shelf_widget.h"
diff --git a/ash/shelf/shelf_window_watcher.cc b/ash/shelf/shelf_window_watcher.cc index 88e000a..d52a149 100644 --- a/ash/shelf/shelf_window_watcher.cc +++ b/ash/shelf/shelf_window_watcher.cc
@@ -7,10 +7,10 @@ #include <memory> #include <utility> +#include "ash/public/cpp/shelf_model.h" #include "ash/public/cpp/shell_window_ids.h" #include "ash/public/cpp/window_properties.h" #include "ash/shelf/shelf_constants.h" -#include "ash/shelf/shelf_model.h" #include "ash/shelf/shelf_window_watcher_item_delegate.h" #include "ash/shell.h" #include "ash/shell_port.h"
diff --git a/ash/shelf/shelf_window_watcher_item_delegate.cc b/ash/shelf/shelf_window_watcher_item_delegate.cc index c10440b..17cac6b 100644 --- a/ash/shelf/shelf_window_watcher_item_delegate.cc +++ b/ash/shelf/shelf_window_watcher_item_delegate.cc
@@ -6,9 +6,9 @@ #include <utility> +#include "ash/public/cpp/shelf_model.h" #include "ash/public/cpp/window_properties.h" #include "ash/shelf/shelf_controller.h" -#include "ash/shelf/shelf_model.h" #include "ash/shell.h" #include "ash/wm/window_state.h" #include "ash/wm/window_util.h"
diff --git a/ash/shelf/shelf_window_watcher_unittest.cc b/ash/shelf/shelf_window_watcher_unittest.cc index ad97f4e0..b02928f 100644 --- a/ash/shelf/shelf_window_watcher_unittest.cc +++ b/ash/shelf/shelf_window_watcher_unittest.cc
@@ -6,11 +6,11 @@ #include "ash/public/cpp/config.h" #include "ash/public/cpp/shelf_item.h" +#include "ash/public/cpp/shelf_model.h" #include "ash/public/cpp/shell_window_ids.h" #include "ash/public/cpp/window_properties.h" #include "ash/root_window_controller.h" #include "ash/session/session_controller.h" -#include "ash/shelf/shelf_model.h" #include "ash/shell.h" #include "ash/shell_port.h" #include "ash/test/ash_test_base.h"
diff --git a/ash/shell.cc b/ash/shell.cc index 1c72b47..b9d4e76 100644 --- a/ash/shell.cc +++ b/ash/shell.cc
@@ -51,12 +51,12 @@ #include "ash/new_window_controller.h" #include "ash/palette_delegate.h" #include "ash/public/cpp/config.h" +#include "ash/public/cpp/shelf_model.h" #include "ash/public/cpp/shell_window_ids.h" #include "ash/root_window_controller.h" #include "ash/session/session_controller.h" #include "ash/shelf/shelf.h" #include "ash/shelf/shelf_controller.h" -#include "ash/shelf/shelf_model.h" #include "ash/shelf/shelf_window_watcher.h" #include "ash/shell_delegate.h" #include "ash/shell_init_params.h"
diff --git a/ash/shell/app_list.cc b/ash/shell/app_list.cc index 5f4f95f0a2..0cc998ba 100644 --- a/ash/shell/app_list.cc +++ b/ash/shell/app_list.cc
@@ -294,8 +294,6 @@ return std::vector<views::View*>(); } - views::View* GetSearchAnswerWebView() override { return nullptr; } - void CustomLauncherPageAnimationChanged(double progress) override {} void CustomLauncherPagePopSubpage() override {}
diff --git a/ash/shell/window_watcher.cc b/ash/shell/window_watcher.cc index 2fb4b4c..b3b4cda 100644 --- a/ash/shell/window_watcher.cc +++ b/ash/shell/window_watcher.cc
@@ -7,9 +7,9 @@ #include <utility> #include "ash/public/cpp/shelf_item.h" +#include "ash/public/cpp/shelf_model.h" #include "ash/public/cpp/shell_window_ids.h" #include "ash/public/cpp/window_properties.h" -#include "ash/shelf/shelf_model.h" #include "ash/shelf/shelf_widget.h" #include "ash/shell.h" #include "ash/shell/window_watcher_shelf_item_delegate.h"
diff --git a/ash/system/tray/tray_details_view.cc b/ash/system/tray/tray_details_view.cc index ea8d244f..ac448de 100644 --- a/ash/system/tray/tray_details_view.cc +++ b/ash/system/tray/tray_details_view.cc
@@ -334,12 +334,9 @@ scroll_content_ = new ScrollContentsView(); scroller_ = new views::ScrollView; scroller_->SetContents(scroll_content_); - // Make the |scroller_| have a layer to clip |scroll_content_|'s children. // TODO(varkha): Make the sticky rows work with EnableViewPortLayer(). - scroller_->SetPaintToLayer(); - scroller_->SetBackground(views::CreateThemedSolidBackground( - scroller_, ui::NativeTheme::kColorId_BubbleBackground)); - scroller_->layer()->SetMasksToBounds(true); + scroller_->SetBackgroundThemeColorId( + ui::NativeTheme::kColorId_BubbleBackground); AddChildView(scroller_); box_layout_->SetFlexForView(scroller_, 1);
diff --git a/ash/test/shelf_view_test_api.cc b/ash/test/shelf_view_test_api.cc index 35abf3d7..7601397b 100644 --- a/ash/test/shelf_view_test_api.cc +++ b/ash/test/shelf_view_test_api.cc
@@ -4,10 +4,10 @@ #include "ash/test/shelf_view_test_api.h" +#include "ash/public/cpp/shelf_model.h" #include "ash/shelf/overflow_button.h" #include "ash/shelf/shelf_button.h" #include "ash/shelf/shelf_constants.h" -#include "ash/shelf/shelf_model.h" #include "ash/shelf/shelf_view.h" #include "base/message_loop/message_loop.h" #include "base/run_loop.h"
diff --git a/ash/wm/panels/panel_layout_manager_unittest.cc b/ash/wm/panels/panel_layout_manager_unittest.cc index 30b2b1b0..6b81b1c 100644 --- a/ash/wm/panels/panel_layout_manager_unittest.cc +++ b/ash/wm/panels/panel_layout_manager_unittest.cc
@@ -5,6 +5,7 @@ #include "ash/wm/panels/panel_layout_manager.h" #include "ash/public/cpp/config.h" +#include "ash/public/cpp/shelf_model.h" #include "ash/public/cpp/shelf_types.h" #include "ash/public/cpp/shell_window_ids.h" #include "ash/public/cpp/window_properties.h" @@ -12,7 +13,6 @@ #include "ash/shelf/shelf.h" #include "ash/shelf/shelf_button.h" #include "ash/shelf/shelf_layout_manager.h" -#include "ash/shelf/shelf_model.h" #include "ash/shelf/shelf_view.h" #include "ash/shelf/shelf_widget.h" #include "ash/shell.h"
diff --git a/ash/wm/panels/panel_window_resizer_unittest.cc b/ash/wm/panels/panel_window_resizer_unittest.cc index 750f8fb..0478525 100644 --- a/ash/wm/panels/panel_window_resizer_unittest.cc +++ b/ash/wm/panels/panel_window_resizer_unittest.cc
@@ -11,7 +11,6 @@ #include "ash/root_window_controller.h" #include "ash/shelf/shelf.h" #include "ash/shelf/shelf_layout_manager.h" -#include "ash/shelf/shelf_model.h" #include "ash/shelf/shelf_widget.h" #include "ash/shell.h" #include "ash/shell_port.h"
diff --git a/ash/wm/system_gesture_event_filter_unittest.cc b/ash/wm/system_gesture_event_filter_unittest.cc index 7a2d59c..422297e 100644 --- a/ash/wm/system_gesture_event_filter_unittest.cc +++ b/ash/wm/system_gesture_event_filter_unittest.cc
@@ -7,7 +7,6 @@ #include <vector> #include "ash/accelerators/accelerator_controller.h" -#include "ash/shelf/shelf_model.h" #include "ash/shell.h" #include "ash/system/tray/system_tray_delegate.h" #include "ash/test/ash_test_base.h"
diff --git a/base/android/build_info.h b/base/android/build_info.h index e7dab56..3c4c86c1 100644 --- a/base/android/build_info.h +++ b/base/android/build_info.h
@@ -27,7 +27,8 @@ SDK_VERSION_LOLLIPOP = 21, SDK_VERSION_LOLLIPOP_MR1 = 22, SDK_VERSION_MARSHMALLOW = 23, - SDK_VERSION_NOUGAT = 24 + SDK_VERSION_NOUGAT = 24, + SDK_VERSION_NOUGAT_MR1 = 25 }; // BuildInfo is a singleton class that stores android build and device
diff --git a/base/environment_unittest.cc b/base/environment_unittest.cc index ef264cf..80e3aa6e 100644 --- a/base/environment_unittest.cc +++ b/base/environment_unittest.cc
@@ -14,11 +14,22 @@ namespace base { +namespace { + +// Fuchsia doesn't set PATH, Windows doesn't set PWD. (Fuchsia may eventually +// set PATH and then this can be removed again.) +#if defined(OS_FUCHSIA) +constexpr char kValidEnvironmentVariable[] = "PWD"; +#else +constexpr char kValidEnvironmentVariable[] = "PATH"; +#endif + +} // namespace + TEST_F(EnvironmentTest, GetVar) { - // Every setup should have non-empty PATH... std::unique_ptr<Environment> env(Environment::Create()); std::string env_value; - EXPECT_TRUE(env->GetVar("PATH", &env_value)); + EXPECT_TRUE(env->GetVar(kValidEnvironmentVariable, &env_value)); EXPECT_NE(env_value, ""); } @@ -51,9 +62,8 @@ } TEST_F(EnvironmentTest, HasVar) { - // Every setup should have PATH... std::unique_ptr<Environment> env(Environment::Create()); - EXPECT_TRUE(env->HasVar("PATH")); + EXPECT_TRUE(env->HasVar(kValidEnvironmentVariable)); } TEST_F(EnvironmentTest, SetVar) {
diff --git a/base/task_scheduler/task_tracker.cc b/base/task_scheduler/task_tracker.cc index ebf43152..4a7ca94 100644 --- a/base/task_scheduler/task_tracker.cc +++ b/base/task_scheduler/task_tracker.cc
@@ -405,12 +405,18 @@ // ordering bug. This aims to catch those early. DCHECK(shutdown_event_); if (shutdown_event_->IsSignaled()) { +#if DCHECK_IS_ON() +// clang-format off // TODO(robliao): http://crbug.com/698140. Since the service thread // doesn't stop processing its own tasks at shutdown, we may still // attempt to post a BLOCK_SHUTDOWN task in response to a - // FileDescriptorWatcher. -#if DCHECK_IS_ON() - DCHECK(IsPostingBlockShutdownTaskAfterShutdownAllowed()); + // FileDescriptorWatcher. Same is true for FilePathWatcher + // (http://crbug.com/728235). Until it's possible for such services to + // post to non-BLOCK_SHUTDOWN sequences which are themselves funneled to + // the main execution sequence (a future plan for the post_task.h API), + // this DCHECK will be flaky and must be disabled. + // DCHECK(IsPostingBlockShutdownTaskAfterShutdownAllowed()); +// clang-format on #endif state_->DecrementNumTasksBlockingShutdown(); return false;
diff --git a/base/task_scheduler/task_tracker_unittest.cc b/base/task_scheduler/task_tracker_unittest.cc index 2fbfff27..d7c7b60a 100644 --- a/base/task_scheduler/task_tracker_unittest.cc +++ b/base/task_scheduler/task_tracker_unittest.cc
@@ -412,11 +412,7 @@ std::unique_ptr<Task> task(CreateTask(GetParam())); // |task_tracker_| shouldn't allow a task to be posted after shutdown. - if (GetParam() == TaskShutdownBehavior::BLOCK_SHUTDOWN) { - EXPECT_DCHECK_DEATH({ tracker_.WillPostTask(task.get()); }); - } else { - EXPECT_FALSE(tracker_.WillPostTask(task.get())); - } + EXPECT_FALSE(tracker_.WillPostTask(task.get())); } // Verify that BLOCK_SHUTDOWN and SKIP_ON_SHUTDOWN tasks can
diff --git a/build/config/sanitizers/sanitizers.gni b/build/config/sanitizers/sanitizers.gni index 17f4d963..829bc43 100644 --- a/build/config/sanitizers/sanitizers.gni +++ b/build/config/sanitizers/sanitizers.gni
@@ -139,7 +139,7 @@ # This is intended to be used for instrumented builds. use_custom_libcxx = (is_asan && is_linux && !is_chromeos) || is_tsan || is_msan || is_ubsan || - is_ubsan_security || use_libfuzzer || use_afl + is_ubsan_security || (use_libfuzzer && !is_mac) || use_afl # Enable -fsanitize-coverage. use_sanitizer_coverage =
diff --git a/cc/input/scrollbar_animation_controller_unittest.cc b/cc/input/scrollbar_animation_controller_unittest.cc index 4632648002..b9ddce2 100644 --- a/cc/input/scrollbar_animation_controller_unittest.cc +++ b/cc/input/scrollbar_animation_controller_unittest.cc
@@ -121,6 +121,7 @@ clip_layer_->SetBounds(gfx::Size(100, 100)); scroll_layer_ptr->SetBounds(gfx::Size(200, 200)); host_impl_.active_tree()->BuildLayerListAndPropertyTreesForTesting(); + host_impl_.active_tree()->UpdateScrollbarGeometries(); scrollbar_controller_ = ScrollbarAnimationController:: CreateScrollbarAnimationControllerAuraOverlay( @@ -1261,6 +1262,8 @@ clip_layer_->SetBounds(gfx::Size(100, 100)); scroll_layer_ptr->SetBounds(gfx::Size(200, 200)); host_impl_.active_tree()->BuildLayerListAndPropertyTreesForTesting(); + DCHECK(host_impl_.active_tree()->ScrollbarGeometriesNeedUpdate()); + host_impl_.active_tree()->UpdateScrollbarGeometries(); scrollbar_controller_ = ScrollbarAnimationController::CreateScrollbarAnimationControllerAndroid(
diff --git a/cc/input/single_scrollbar_animation_controller_thinning_unittest.cc b/cc/input/single_scrollbar_animation_controller_thinning_unittest.cc index 0faa8d3..8df33897 100644 --- a/cc/input/single_scrollbar_animation_controller_thinning_unittest.cc +++ b/cc/input/single_scrollbar_animation_controller_thinning_unittest.cc
@@ -96,6 +96,7 @@ scrollbar_layer_->test_properties()->opacity_can_animate = true; clip_layer_->SetBounds(gfx::Size(100, 100)); scroll_layer_ptr->SetBounds(gfx::Size(200, 200)); + host_impl_.active_tree()->UpdateScrollbarGeometries(); host_impl_.active_tree()->BuildLayerListAndPropertyTreesForTesting(); scrollbar_controller_ = SingleScrollbarAnimationControllerThinning::Create(
diff --git a/cc/layers/layer_impl.cc b/cc/layers/layer_impl.cc index 57cb1b4..be6cf82 100644 --- a/cc/layers/layer_impl.cc +++ b/cc/layers/layer_impl.cc
@@ -94,7 +94,6 @@ LayerImpl::~LayerImpl() { DCHECK_EQ(DRAW_MODE_NONE, current_draw_mode_); - layer_tree_impl_->UnregisterScrollLayer(this); layer_tree_impl_->UnregisterLayer(this); layer_tree_impl_->RemoveFromElementMap(this); @@ -275,10 +274,12 @@ void LayerImpl::SetScrollClipLayer(int scroll_clip_layer_id) { if (scroll_clip_layer_id_ == scroll_clip_layer_id) return; - - layer_tree_impl()->UnregisterScrollLayer(this); scroll_clip_layer_id_ = scroll_clip_layer_id; + layer_tree_impl()->RegisterScrollLayer(this); + + // The scrolling bounds are determined from the scroll clip layer's bounds. + layer_tree_impl()->SetScrollbarGeometriesNeedUpdate(); } LayerImpl* LayerImpl::scroll_clip_layer() const { @@ -516,7 +517,8 @@ bounds_ = bounds; - layer_tree_impl()->DidUpdateScrollState(id()); + // Scrollbar positions depend on scrolling bounds and scroll clip bounds. + layer_tree_impl()->SetScrollbarGeometriesNeedUpdate(); NoteLayerPropertyChanged(); } @@ -543,7 +545,9 @@ NOTREACHED(); } - layer_tree_impl()->DidUpdateScrollState(id()); + // Viewport scrollbar positions are determined using the viewport bounds + // delta. + layer_tree_impl()->SetScrollbarGeometriesNeedUpdate(); if (masks_to_bounds()) { // If layer is clipping, then update the clip node using the new bounds. @@ -986,4 +990,26 @@ return GetPropertyTrees()->transform_tree; } +bool LayerImpl::HasValidPropertyTreeIndices() const { + // TODO(crbug.com/726423): LayerImpls should never have invalid PropertyTree + // indices. + const bool has_valid_transform_node = + !!GetTransformTree().Node(transform_tree_index()); + DCHECK(has_valid_transform_node); + + const bool has_valid_effect_node = + !!GetEffectTree().Node(effect_tree_index()); + DCHECK(has_valid_effect_node); + + const bool has_valid_clip_node = !!GetClipTree().Node(clip_tree_index()); + DCHECK(has_valid_clip_node); + + const bool has_valid_scroll_node = + !!GetScrollTree().Node(scroll_tree_index()); + DCHECK(has_valid_scroll_node); + + return has_valid_transform_node && has_valid_effect_node && + has_valid_clip_node && has_valid_scroll_node; +} + } // namespace cc
diff --git a/cc/layers/layer_impl.h b/cc/layers/layer_impl.h index 35a155de..cd791ca 100644 --- a/cc/layers/layer_impl.h +++ b/cc/layers/layer_impl.h
@@ -448,6 +448,8 @@ } bool raster_even_if_not_drawn() const { return raster_even_if_not_drawn_; } + bool HasValidPropertyTreeIndices() const; + protected: LayerImpl(LayerTreeImpl* layer_impl, int id,
diff --git a/cc/layers/layer_impl_unittest.cc b/cc/layers/layer_impl_unittest.cc index d2744ee..b12d3a3 100644 --- a/cc/layers/layer_impl_unittest.cc +++ b/cc/layers/layer_impl_unittest.cc
@@ -141,6 +141,7 @@ root->test_properties()->force_render_surface = true; root->SetMasksToBounds(true); + root->SetScrollClipLayer(root_clip->id()); root->layer_tree_impl()->ResetAllChangeTracking(); root->test_properties()->AddChild(
diff --git a/cc/layers/painted_scrollbar_layer_impl_unittest.cc b/cc/layers/painted_scrollbar_layer_impl_unittest.cc index 2dd6d0b7..3932b0e 100644 --- a/cc/layers/painted_scrollbar_layer_impl_unittest.cc +++ b/cc/layers/painted_scrollbar_layer_impl_unittest.cc
@@ -57,6 +57,9 @@ scrollbar_layer_impl->set_thumb_ui_resource_id(thumb_uid); scrollbar_layer_impl->set_thumb_opacity(thumb_opacity); + DCHECK(impl.host_impl()->active_tree()->ScrollbarGeometriesNeedUpdate()); + impl.host_impl()->active_tree()->UpdateScrollbarGeometries(); + impl.CalcDrawProps(viewport_size); gfx::Rect thumb_rect = scrollbar_layer_impl->ComputeThumbQuadRect();
diff --git a/cc/layers/scrollbar_layer_impl_base.cc b/cc/layers/scrollbar_layer_impl_base.cc index 5070c84..7c51ea9e 100644 --- a/cc/layers/scrollbar_layer_impl_base.cc +++ b/cc/layers/scrollbar_layer_impl_base.cc
@@ -59,6 +59,26 @@ return true; } +float ScrollbarLayerImplBase::current_pos() const { + DCHECK(!layer_tree_impl()->ScrollbarGeometriesNeedUpdate()); + return current_pos_; +} + +float ScrollbarLayerImplBase::clip_layer_length() const { + DCHECK(!layer_tree_impl()->ScrollbarGeometriesNeedUpdate()); + return clip_layer_length_; +} + +float ScrollbarLayerImplBase::scroll_layer_length() const { + DCHECK(!layer_tree_impl()->ScrollbarGeometriesNeedUpdate()); + return scroll_layer_length_; +} + +float ScrollbarLayerImplBase::vertical_adjust() const { + DCHECK(!layer_tree_impl()->ScrollbarGeometriesNeedUpdate()); + return vertical_adjust_; +} + bool ScrollbarLayerImplBase::CanScrollOrientation() const { // TODO(pdr): Refactor this to not depend on layers by using the associated // scroll node's user_scrollable values. @@ -67,44 +87,47 @@ if (!scroll_layer) return false; + // Ensure the clip_layer_length and scroll_layer_length values are up-to-date. + // TODO(pdr): Instead of using the clip and scroll layer lengths which require + // an update, refactor to use the scroll tree (ScrollTree::MaxScrollOffset + // as in LayerTreeHostImpl::TryScroll). + layer_tree_impl()->UpdateScrollbarGeometries(); + return scroll_layer->user_scrollable(orientation()) && - // Ensure clip_layer_length_ smaller than scroll_layer_length_ not - // caused by floating error. - !MathUtil::IsFloatNearlyTheSame(clip_layer_length_, - scroll_layer_length_) && - clip_layer_length_ < scroll_layer_length_; + // Ensure clip_layer_length is smaller than scroll_layer_length, not + // including small deltas due to floating point error. + !MathUtil::IsFloatNearlyTheSame(clip_layer_length(), + scroll_layer_length()) && + clip_layer_length() < scroll_layer_length(); } -bool ScrollbarLayerImplBase::SetVerticalAdjust(float vertical_adjust) { +void ScrollbarLayerImplBase::SetVerticalAdjust(float vertical_adjust) { if (vertical_adjust_ == vertical_adjust) - return false; + return; vertical_adjust_ = vertical_adjust; NoteLayerPropertyChanged(); - return true; } -bool ScrollbarLayerImplBase::SetClipLayerLength(float clip_layer_length) { +void ScrollbarLayerImplBase::SetClipLayerLength(float clip_layer_length) { if (clip_layer_length_ == clip_layer_length) - return false; + return; clip_layer_length_ = clip_layer_length; NoteLayerPropertyChanged(); - return true; } -bool ScrollbarLayerImplBase::SetScrollLayerLength(float scroll_layer_length) { +void ScrollbarLayerImplBase::SetScrollLayerLength(float scroll_layer_length) { if (scroll_layer_length_ == scroll_layer_length) - return false; + return; scroll_layer_length_ = scroll_layer_length; NoteLayerPropertyChanged(); - return true; + return; } -bool ScrollbarLayerImplBase::SetThumbThicknessScaleFactor(float factor) { +void ScrollbarLayerImplBase::SetThumbThicknessScaleFactor(float factor) { if (thumb_thickness_scale_factor_ == factor) - return false; + return; thumb_thickness_scale_factor_ = factor; NoteLayerPropertyChanged(); - return true; } gfx::Rect ScrollbarLayerImplBase::ComputeThumbQuadRectWithThumbThicknessScale( @@ -173,10 +196,10 @@ float track_length = TrackLength(); int thumb_length = ThumbLength(); int thumb_thickness = ThumbThickness(); - float maximum = scroll_layer_length_ - clip_layer_length_; + float maximum = scroll_layer_length() - clip_layer_length(); // With the length known, we can compute the thumb's position. - float clamped_current_pos = std::min(std::max(current_pos_, 0.f), maximum); + float clamped_current_pos = std::min(std::max(current_pos(), 0.f), maximum); int thumb_offset = TrackStart(); if (maximum > 0) {
diff --git a/cc/layers/scrollbar_layer_impl_base.h b/cc/layers/scrollbar_layer_impl_base.h index 7becd72..644557a 100644 --- a/cc/layers/scrollbar_layer_impl_base.h +++ b/cc/layers/scrollbar_layer_impl_base.h
@@ -21,15 +21,17 @@ ElementId scroll_element_id() const { return scroll_element_id_; } void SetScrollElementId(ElementId scroll_element_id); - float current_pos() const { return current_pos_; } + // The following setters should be called when updating scrollbar geometries + // (see: LayerTreeImpl::UpdateScrollbarGeometries). bool SetCurrentPos(float current_pos); - bool SetClipLayerLength(float clip_layer_length); - bool SetScrollLayerLength(float scroll_layer_length); - bool SetVerticalAdjust(float vertical_adjust); + void SetClipLayerLength(float clip_layer_length); + void SetScrollLayerLength(float scroll_layer_length); + void SetVerticalAdjust(float vertical_adjust); - float clip_layer_length() const { return clip_layer_length_; } - float scroll_layer_length() const { return scroll_layer_length_; } - float vertical_adjust() const { return vertical_adjust_; } + float current_pos() const; + float clip_layer_length() const; + float scroll_layer_length() const; + float vertical_adjust() const; bool is_overlay_scrollbar() const { return is_overlay_scrollbar_; } void set_is_overlay_scrollbar(bool is_overlay) { @@ -53,7 +55,7 @@ float thumb_thickness_scale_factor() { return thumb_thickness_scale_factor_; } - bool SetThumbThicknessScaleFactor(float thumb_thickness_scale_factor); + void SetThumbThicknessScaleFactor(float thumb_thickness_scale_factor); virtual int ThumbThickness() const = 0;
diff --git a/cc/layers/scrollbar_layer_unittest.cc b/cc/layers/scrollbar_layer_unittest.cc index ff5d38a5..f33fab5 100644 --- a/cc/layers/scrollbar_layer_unittest.cc +++ b/cc/layers/scrollbar_layer_unittest.cc
@@ -315,6 +315,7 @@ static_cast<PaintedScrollbarLayerImpl*>( layer_impl_tree_root->layer_tree_impl()->LayerById( scrollbar_layer->id())); + layer_impl_tree_root->layer_tree_impl()->UpdateScrollbarGeometries(); EXPECT_EQ(10.f, cc_scrollbar_layer->current_pos()); EXPECT_EQ(30, cc_scrollbar_layer->scroll_layer_length() - @@ -327,6 +328,7 @@ layer_tree_host_->UpdateLayers(); layer_impl_tree_root = layer_tree_host_->CommitAndCreateLayerImplTree(); + layer_impl_tree_root->layer_tree_impl()->UpdateScrollbarGeometries(); EXPECT_EQ(100.f, cc_scrollbar_layer->current_pos()); EXPECT_EQ(300, cc_scrollbar_layer->scroll_layer_length() - @@ -335,6 +337,7 @@ LayerImpl* scroll_layer_impl = layer_impl_tree_root->layer_tree_impl()->LayerById(scroll_layer->id()); scroll_layer_impl->ScrollBy(gfx::Vector2d(12, 34)); + layer_impl_tree_root->layer_tree_impl()->UpdateScrollbarGeometries(); EXPECT_EQ(112.f, cc_scrollbar_layer->current_pos()); EXPECT_EQ(300, cc_scrollbar_layer->scroll_layer_length() - @@ -346,6 +349,7 @@ scrollbar_layer->UpdateInternalContentScale(); \ scrollbar_layer->UpdateThumbAndTrackGeometry(); \ root_clip_layer_impl = layer_tree_host_->CommitAndCreateLayerImplTree(); \ + root_clip_layer_impl->layer_tree_impl()->UpdateScrollbarGeometries(); \ scrollbar_layer_impl = static_cast<PaintedScrollbarLayerImpl*>( \ root_clip_layer_impl->layer_tree_impl()->LayerById( \ scrollbar_layer->id())); \ @@ -538,6 +542,9 @@ scrollbar_layer_impl->SetClipLayerLength(200 / 3.f); scrollbar_layer_impl->SetScrollLayerLength(100 + 200 / 3.f); + DCHECK(layer_tree_host_->active_tree()->ScrollbarGeometriesNeedUpdate()); + layer_tree_host_->active_tree()->UpdateScrollbarGeometries(); + // Thickness should be overridden to 3. { std::unique_ptr<RenderPass> render_pass = RenderPass::Create(); @@ -622,6 +629,9 @@ scrollbar_layer_impl->SetBounds(gfx::Size(kTrackLength, kThumbThickness)); scrollbar_layer_impl->SetCurrentPos(4.f); + DCHECK(layer_tree_host_->active_tree()->ScrollbarGeometriesNeedUpdate()); + layer_tree_host_->active_tree()->UpdateScrollbarGeometries(); + { std::unique_ptr<RenderPass> render_pass = RenderPass::Create(); @@ -782,6 +792,9 @@ clip_layer->SetBounds(gfx::Size(980, 980)); scroll_layer->SetBounds(gfx::Size(980, 980)); + DCHECK(impl.host_impl()->active_tree()->ScrollbarGeometriesNeedUpdate()); + impl.host_impl()->active_tree()->UpdateScrollbarGeometries(); + impl.CalcDrawProps(viewport_size); // Fake clip layer length to scrollbar to mock rounding error. @@ -795,6 +808,57 @@ EXPECT_TRUE(scrollbar_layer->CanScrollOrientation()); } +TEST_F(ScrollbarLayerTest, LayerChangesAffectingScrollbarGeometries) { + gfx::Size viewport_size(980, 980); + + LayerTestCommon::LayerImplTest impl; + + LayerImpl* clip_layer = impl.AddChildToRoot<LayerImpl>(); + LayerImpl* scroll_layer = impl.AddChild<LayerImpl>(clip_layer); + scroll_layer->SetElementId(LayerIdToElementIdForTesting(scroll_layer->id())); + + // Make clip_layer the inner viewport container layer. This ensures the later + // call to |SetViewportBoundsDelta| will be on a viewport layer. + LayerTreeImpl::ViewportLayerIds viewport_ids; + viewport_ids.inner_viewport_container = clip_layer->id(); + impl.host_impl()->active_tree()->SetViewportLayersFromIds(viewport_ids); + + const int kTrackStart = 0; + const int kThumbThickness = 10; + const bool kIsLeftSideVerticalScrollbar = false; + const bool kIsOverlayScrollbar = false; + SolidColorScrollbarLayerImpl* scrollbar_layer = + impl.AddChild<SolidColorScrollbarLayerImpl>( + scroll_layer, HORIZONTAL, kThumbThickness, kTrackStart, + kIsLeftSideVerticalScrollbar, kIsOverlayScrollbar); + scrollbar_layer->SetScrollElementId(scroll_layer->element_id()); + DCHECK(impl.host_impl()->active_tree()->ScrollbarGeometriesNeedUpdate()); + impl.host_impl()->active_tree()->UpdateScrollbarGeometries(); + + scroll_layer->SetScrollClipLayer(clip_layer->id()); + DCHECK(impl.host_impl()->active_tree()->ScrollbarGeometriesNeedUpdate()); + impl.host_impl()->active_tree()->UpdateScrollbarGeometries(); + + clip_layer->SetBounds(gfx::Size(900, 900)); + DCHECK(impl.host_impl()->active_tree()->ScrollbarGeometriesNeedUpdate()); + impl.host_impl()->active_tree()->UpdateScrollbarGeometries(); + + scroll_layer->SetBounds(gfx::Size(980, 980)); + DCHECK(impl.host_impl()->active_tree()->ScrollbarGeometriesNeedUpdate()); + impl.host_impl()->active_tree()->UpdateScrollbarGeometries(); + + clip_layer->SetViewportBoundsDelta(gfx::Vector2dF(1, 2)); + DCHECK(impl.host_impl()->active_tree()->ScrollbarGeometriesNeedUpdate()); + impl.host_impl()->active_tree()->UpdateScrollbarGeometries(); + + // Not changing the current value should not require an update. + scroll_layer->SetScrollClipLayer(clip_layer->id()); + clip_layer->SetBounds(gfx::Size(900, 900)); + scroll_layer->SetBounds(gfx::Size(980, 980)); + clip_layer->SetViewportBoundsDelta(gfx::Vector2dF(1, 2)); + DCHECK(!impl.host_impl()->active_tree()->ScrollbarGeometriesNeedUpdate()); +} + class ScrollbarLayerSolidColorThumbTest : public testing::Test { public: ScrollbarLayerSolidColorThumbTest() { @@ -841,6 +905,8 @@ horizontal_scrollbar_layer_->SetClipLayerLength(5.f); horizontal_scrollbar_layer_->SetScrollLayerLength(15.f); horizontal_scrollbar_layer_->SetBounds(gfx::Size(100, 3)); + DCHECK(host_impl_->active_tree()->ScrollbarGeometriesNeedUpdate()); + host_impl_->active_tree()->UpdateScrollbarGeometries(); EXPECT_EQ(33, horizontal_scrollbar_layer_->ComputeThumbQuadRect().width()); // The thumb's length should never be less than its thickness. @@ -852,6 +918,8 @@ TEST_F(ScrollbarLayerSolidColorThumbTest, SolidColorThumbPosition) { horizontal_scrollbar_layer_->SetBounds(gfx::Size(100, 3)); + DCHECK(host_impl_->active_tree()->ScrollbarGeometriesNeedUpdate()); + host_impl_->active_tree()->UpdateScrollbarGeometries(); horizontal_scrollbar_layer_->SetCurrentPos(0.f); horizontal_scrollbar_layer_->SetClipLayerLength(12.f); @@ -881,6 +949,9 @@ layers[0]->SetBounds(gfx::Size(100, 3)); layers[1]->SetBounds(gfx::Size(3, 100)); + DCHECK(host_impl_->active_tree()->ScrollbarGeometriesNeedUpdate()); + host_impl_->active_tree()->UpdateScrollbarGeometries(); + EXPECT_EQ(gfx::Rect(20, 0, 20, 3), horizontal_scrollbar_layer_->ComputeThumbQuadRect()); EXPECT_EQ(gfx::Rect(0, 20, 3, 20),
diff --git a/cc/layers/solid_color_scrollbar_layer_impl_unittest.cc b/cc/layers/solid_color_scrollbar_layer_impl_unittest.cc index a2b24303..4cff576 100644 --- a/cc/layers/solid_color_scrollbar_layer_impl_unittest.cc +++ b/cc/layers/solid_color_scrollbar_layer_impl_unittest.cc
@@ -39,6 +39,9 @@ // SolidColorScrollbarLayers construct with opacity = 0.f, so override. scrollbar_layer_impl->test_properties()->opacity = 1.f; + DCHECK(impl.host_impl()->active_tree()->ScrollbarGeometriesNeedUpdate()); + impl.host_impl()->active_tree()->UpdateScrollbarGeometries(); + impl.CalcDrawProps(viewport_size); gfx::Rect thumb_rect = scrollbar_layer_impl->ComputeThumbQuadRect();
diff --git a/cc/test/fake_external_begin_frame_source.cc b/cc/test/fake_external_begin_frame_source.cc index 8398dcfc..a2a0b3d 100644 --- a/cc/test/fake_external_begin_frame_source.cc +++ b/cc/test/fake_external_begin_frame_source.cc
@@ -18,11 +18,11 @@ : tick_automatically_(tick_automatically), milliseconds_per_frame_(1000.0 / refresh_rate), weak_ptr_factory_(this) { - DetachFromThread(); + DETACH_FROM_SEQUENCE(sequence_checker_); } FakeExternalBeginFrameSource::~FakeExternalBeginFrameSource() { - DCHECK(CalledOnValidThread()); + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); } void FakeExternalBeginFrameSource::SetPaused(bool paused) { @@ -87,7 +87,7 @@ void FakeExternalBeginFrameSource::TestOnBeginFrame( const BeginFrameArgs& args) { - DCHECK(CalledOnValidThread()); + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); current_args_ = args; std::set<BeginFrameObserver*> observers(observers_); for (auto* obs : observers)
diff --git a/cc/test/fake_external_begin_frame_source.h b/cc/test/fake_external_begin_frame_source.h index 0a03149c..9ab8f6e 100644 --- a/cc/test/fake_external_begin_frame_source.h +++ b/cc/test/fake_external_begin_frame_source.h
@@ -9,7 +9,7 @@ #include "base/cancelable_callback.h" #include "base/memory/weak_ptr.h" -#include "base/threading/non_thread_safe.h" +#include "base/sequence_checker.h" #include "cc/output/begin_frame_args.h" #include "cc/scheduler/begin_frame_source.h" @@ -19,9 +19,7 @@ namespace cc { -class FakeExternalBeginFrameSource - : public BeginFrameSource, - public NON_EXPORTED_BASE(base::NonThreadSafe) { +class FakeExternalBeginFrameSource : public BeginFrameSource { public: class Client { public: @@ -63,6 +61,9 @@ uint64_t next_begin_frame_number_ = BeginFrameArgs::kStartingFrameNumber; std::set<BeginFrameObserver*> observers_; base::CancelableCallback<void(const BeginFrameArgs&)> begin_frame_task_; + + SEQUENCE_CHECKER(sequence_checker_); + base::WeakPtrFactory<FakeExternalBeginFrameSource> weak_ptr_factory_; };
diff --git a/cc/test/fake_layer_tree_host.cc b/cc/test/fake_layer_tree_host.cc index 96ce656..2a81e0e0 100644 --- a/cc/test/fake_layer_tree_host.cc +++ b/cc/test/fake_layer_tree_host.cc
@@ -69,6 +69,8 @@ void FakeLayerTreeHost::SetNeedsCommit() { needs_commit_ = true; } LayerImpl* FakeLayerTreeHost::CommitAndCreateLayerImplTree() { + // TODO(pdr): Update the LayerTreeImpl lifecycle states here so lifecycle + // violations can be caught. TreeSynchronizer::SynchronizeTrees(root_layer(), active_tree()); active_tree()->SetPropertyTrees(property_trees()); TreeSynchronizer::PushLayerProperties(root_layer()->layer_tree_host(),
diff --git a/cc/trees/draw_property_utils.cc b/cc/trees/draw_property_utils.cc index bd0375f..db42684 100644 --- a/cc/trees/draw_property_utils.cc +++ b/cc/trees/draw_property_utils.cc
@@ -458,15 +458,6 @@ transform_tree.Node(layer->transform_tree_index()); const EffectNode* effect_node = effect_tree.Node(layer->effect_tree_index()); - DCHECK(effect_node); - DCHECK(transform_node); - // TODO(crbug.com/726423) : This is a workaround for crbug.com/726225 to - // avoid crashing when there is no effect or transform node. Effect node and - // transform node should always exist here and this workaround should be - // removed. - if (!transform_node || !effect_node) - return true; - if (effect_node->has_render_surface && effect_node->subtree_has_copy_request) return false; @@ -857,7 +848,7 @@ // TODO(crbug.com/726423) : This is a workaround for crbug.com/725851 to // avoid crashing when layer_impl is nullptr. This workaround should be // removed as layer_impl should not be nullptr here. - if (!layer_impl) + if (!layer_impl || !layer_impl->HasValidPropertyTreeIndices()) continue; if (!IsRootLayer(layer_impl) && LayerShouldBeSkippedForDrawPropertiesComputation(
diff --git a/cc/trees/layer_tree_host_impl.cc b/cc/trees/layer_tree_host_impl.cc index 679fb2ae..3dfcae27 100644 --- a/cc/trees/layer_tree_host_impl.cc +++ b/cc/trees/layer_tree_host_impl.cc
@@ -1090,6 +1090,8 @@ if (input_handler_client_) input_handler_client_->ReconcileElasticOverscrollAndRootScroll(); + active_tree_->UpdateScrollbarGeometries(); + if (const char* client_name = GetClientNameForMetrics()) { size_t total_memory = 0; for (const PictureLayerImpl* layer : active_tree()->picture_layers())
diff --git a/cc/trees/layer_tree_host_impl_unittest.cc b/cc/trees/layer_tree_host_impl_unittest.cc index 4d12ca12..1d526b4 100644 --- a/cc/trees/layer_tree_host_impl_unittest.cc +++ b/cc/trees/layer_tree_host_impl_unittest.cc
@@ -3226,6 +3226,8 @@ horiz_scrollbar->SetScrollElementId(root_scroll->element_id()); + host_impl_->active_tree()->UpdateScrollbarGeometries(); + EXPECT_EQ(300, horiz_scrollbar->clip_layer_length()); } @@ -4344,6 +4346,99 @@ host_impl_->ScrollEnd(EndState().get()); } +// Tests that browser controls affect the position of horizontal scrollbars. +TEST_F(LayerTreeHostImplBrowserControlsTest, + HidingBrowserControlsAdjustsScrollbarPosition) { + SetupBrowserControlsAndScrollLayerWithVirtualViewport( + gfx::Size(50, 50), gfx::Size(50, 50), gfx::Size(50, 50)); + + LayerTreeImpl* active_tree = host_impl_->active_tree(); + + // Create a horizontal scrollbar. + const int scrollbar_id = 23; + gfx::Size scrollbar_size(gfx::Size(50, 15)); + std::unique_ptr<SolidColorScrollbarLayerImpl> scrollbar = + SolidColorScrollbarLayerImpl::Create(host_impl_->active_tree(), + scrollbar_id, HORIZONTAL, 3, 20, + false, true); + scrollbar->SetScrollElementId( + host_impl_->OuterViewportScrollLayer()->element_id()); + scrollbar->SetDrawsContent(true); + scrollbar->SetBounds(scrollbar_size); + scrollbar->SetTouchEventHandlerRegion(gfx::Rect(scrollbar_size)); + scrollbar->SetCurrentPos(0); + scrollbar->SetPosition(gfx::PointF(0, 35)); + host_impl_->active_tree() + ->InnerViewportContainerLayer() + ->test_properties() + ->AddChild(std::move(scrollbar)); + host_impl_->active_tree()->BuildPropertyTreesForTesting(); + host_impl_->active_tree()->UpdateScrollbarGeometries(); + + DrawFrame(); + + LayerImpl* inner_container = active_tree->InnerViewportContainerLayer(); + LayerImpl* outer_container = active_tree->OuterViewportContainerLayer(); + SolidColorScrollbarLayerImpl* scrollbar_layer = + static_cast<SolidColorScrollbarLayerImpl*>( + active_tree->LayerById(scrollbar_id)); + + // The browser controls should start off showing so the viewport should be + // shrunk. + EXPECT_EQ(gfx::Size(50, 50), inner_container->bounds()); + EXPECT_EQ(gfx::Size(50, 50), outer_container->bounds()); + EXPECT_EQ(gfx::SizeF(50, 50), active_tree->ScrollableSize()); + EXPECT_EQ(gfx::Size(50, 15), scrollbar_layer->bounds()); + EXPECT_EQ(gfx::Rect(20, 0, 10, 3), scrollbar_layer->ComputeThumbQuadRect()); + + EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, + host_impl_ + ->ScrollBegin(BeginState(gfx::Point()).get(), + InputHandler::TOUCHSCREEN) + .thread); + + host_impl_->browser_controls_manager()->ScrollBegin(); + + // Hide the browser controls by a bit, the scrollable size should increase but + // the actual content bounds shouldn't. + { + host_impl_->browser_controls_manager()->ScrollBy(gfx::Vector2dF(0.f, 25.f)); + host_impl_->active_tree()->UpdateScrollbarGeometries(); + ASSERT_EQ(gfx::Size(50, 75), inner_container->bounds()); + ASSERT_EQ(gfx::Size(50, 75), outer_container->bounds()); + EXPECT_EQ(gfx::SizeF(50, 75), active_tree->ScrollableSize()); + EXPECT_EQ(gfx::Size(50, 15), scrollbar_layer->bounds()); + EXPECT_EQ(gfx::Rect(20, 25, 10, 3), + scrollbar_layer->ComputeThumbQuadRect()); + } + + // Fully hide the browser controls. + { + host_impl_->browser_controls_manager()->ScrollBy(gfx::Vector2dF(0.f, 25.f)); + host_impl_->active_tree()->UpdateScrollbarGeometries(); + ASSERT_EQ(gfx::Size(50, 100), inner_container->bounds()); + ASSERT_EQ(gfx::Size(50, 100), outer_container->bounds()); + EXPECT_EQ(gfx::SizeF(50, 100), active_tree->ScrollableSize()); + EXPECT_EQ(gfx::Size(50, 15), scrollbar_layer->bounds()); + EXPECT_EQ(gfx::Rect(20, 50, 10, 3), + scrollbar_layer->ComputeThumbQuadRect()); + } + + // Additional scrolling shouldn't have any effect. + { + host_impl_->browser_controls_manager()->ScrollBy(gfx::Vector2dF(0.f, 25.f)); + ASSERT_EQ(gfx::Size(50, 100), inner_container->bounds()); + ASSERT_EQ(gfx::Size(50, 100), outer_container->bounds()); + EXPECT_EQ(gfx::SizeF(50, 100), active_tree->ScrollableSize()); + EXPECT_EQ(gfx::Size(50, 15), scrollbar_layer->bounds()); + EXPECT_EQ(gfx::Rect(20, 50, 10, 3), + scrollbar_layer->ComputeThumbQuadRect()); + } + + host_impl_->browser_controls_manager()->ScrollEnd(); + host_impl_->ScrollEnd(EndState().get()); +} + TEST_F(LayerTreeHostImplBrowserControlsTest, ScrollBrowserControlsByFractionalAmount) { SetupBrowserControlsAndScrollLayerWithVirtualViewport( @@ -12121,6 +12216,7 @@ ->AddChild(std::move(scrollbar_1)); host_impl_->active_tree()->BuildPropertyTreesForTesting(); + host_impl_->active_tree()->UpdateScrollbarGeometries(); host_impl_->active_tree()->DidBecomeActive(); DrawFrame(); @@ -12229,6 +12325,7 @@ root_scroll->test_properties()->AddChild(std::move(child_clip)); host_impl_->active_tree()->BuildPropertyTreesForTesting(); + host_impl_->active_tree()->UpdateScrollbarGeometries(); host_impl_->active_tree()->DidBecomeActive(); ScrollbarAnimationController* scrollbar_2_animation_controller =
diff --git a/cc/trees/layer_tree_impl.cc b/cc/trees/layer_tree_impl.cc index 999efbf..8f1158a4 100644 --- a/cc/trees/layer_tree_impl.cc +++ b/cc/trees/layer_tree_impl.cc
@@ -89,6 +89,7 @@ layers_(new OwnedLayerImplList), viewport_size_invalid_(false), needs_update_draw_properties_(true), + scrollbar_geometries_need_update_(false), needs_full_tree_sync_(true), needs_surface_ids_sync_(false), next_activation_forces_redraw_(false), @@ -169,7 +170,9 @@ } void LayerTreeImpl::DidUpdateScrollOffset(int layer_id) { - DidUpdateScrollState(layer_id); + // Scrollbar positions depend on the current scroll offset. + SetScrollbarGeometriesNeedUpdate(); + DCHECK(lifecycle().AllowsPropertyTreeAccess()); TransformTree& transform_tree = property_trees()->transform_tree; ScrollTree& scroll_tree = property_trees()->scroll_tree; @@ -204,85 +207,82 @@ layer_tree_host_impl_->pending_tree()->DidUpdateScrollOffset(layer_id); } -void LayerTreeImpl::DidUpdateScrollState(int layer_id) { +void LayerTreeImpl::UpdateScrollbarGeometries() { if (!IsActiveTree()) return; DCHECK(lifecycle().AllowsPropertyTreeAccess()); - // The scroll_clip_layer Layer properties should be up-to-date. - // TODO(pdr): This DCHECK fails on existing tests but should be enabled. - // DCHECK(lifecycle().AllowsLayerPropertyAccess()); + // Layer properties such as bounds should be up-to-date. + DCHECK(lifecycle().AllowsLayerPropertyAccess()); - if (layer_id == Layer::INVALID_ID) + if (!scrollbar_geometries_need_update_) return; - int scroll_layer_id, clip_layer_id; - if (IsViewportLayerId(layer_id)) { - // For scrollbar purposes, a change to any of the four viewport layers - // should affect the scrollbars tied to the outermost layers, which express - // the sum of the entire viewport. - scroll_layer_id = viewport_layer_ids_.outer_viewport_scroll; - clip_layer_id = viewport_layer_ids_.inner_viewport_container; - } else { - // If the clip layer id was passed in, then look up the scroll layer, or - // vice versa. - auto i = clip_scroll_map_.find(layer_id); - if (i != clip_scroll_map_.end()) { - scroll_layer_id = i->second; - clip_layer_id = layer_id; - } else { - scroll_layer_id = layer_id; - clip_layer_id = LayerById(scroll_layer_id)->scroll_clip_layer_id(); + for (auto& pair : element_id_to_scrollbar_layer_ids_) { + ElementId scrolling_element_id = pair.first; + + LayerImpl* scrolling_layer = LayerByElementId(scrolling_element_id); + if (!scrolling_layer) + continue; + + LayerImpl* bounds_layer = scrolling_layer->scroll_clip_layer(); + if (!bounds_layer) + continue; + + // The viewport scrollbars are special because all viewport layers can + // affect the scrollbars. Begin with the inner container and outer scroll. + bool is_viewport_scrollbar = scrolling_layer->is_viewport_layer_type(); + if (is_viewport_scrollbar) { + bounds_layer = InnerViewportContainerLayer(); + scrolling_layer = OuterViewportScrollLayer(); + if (!bounds_layer || !scrolling_layer) + continue; } - } - UpdateScrollbars(scroll_layer_id, clip_layer_id); -} -void LayerTreeImpl::UpdateScrollbars(int scroll_layer_id, int clip_layer_id) { - DCHECK(IsActiveTree()); + gfx::SizeF scrolling_size(scrolling_layer->BoundsForScrolling()); + if (scrolling_size.IsEmpty()) + continue; - LayerImpl* clip_layer = LayerById(clip_layer_id); - LayerImpl* scroll_layer = LayerById(scroll_layer_id); + gfx::ScrollOffset current_offset = scrolling_layer->CurrentScrollOffset(); + gfx::SizeF bounds_size(bounds_layer->BoundsForScrolling()); + float viewport_vertical_adjust = 0; - if (!clip_layer || !scroll_layer) - return; + // Viewport adjustments to account for the inner scroll layer and outer + // container layer. + if (is_viewport_scrollbar) { + // The offset is the combination of the outer and inner scroll offsets. + current_offset += InnerViewportScrollLayer()->CurrentScrollOffset(); - gfx::SizeF clip_size(clip_layer->BoundsForScrolling()); - gfx::SizeF scroll_size(scroll_layer->BoundsForScrolling()); + // The bounds are set using the intersection of the two viewport clip + // layers, adjusted for the page scale factor. + if (auto* outer_viewport_container = OuterViewportContainerLayer()) + bounds_size.SetToMin(outer_viewport_container->BoundsForScrolling()); + bounds_size.Scale(1 / current_page_scale_factor()); - if (scroll_size.IsEmpty()) - return; - - gfx::ScrollOffset current_offset = scroll_layer->CurrentScrollOffset(); - float viewport_vertical_adjust = 0; - - bool is_viewport_scrollbar = scroll_layer->is_viewport_layer_type(); - if (is_viewport_scrollbar) { - current_offset += InnerViewportScrollLayer()->CurrentScrollOffset(); - if (OuterViewportContainerLayer()) - clip_size.SetToMin(OuterViewportContainerLayer()->BoundsForScrolling()); - clip_size.Scale(1 / current_page_scale_factor()); - viewport_vertical_adjust = clip_layer->ViewportBoundsDelta().y(); - } - - bool y_offset_did_change = false; - for (auto* scrollbar : ScrollbarsFor(scroll_layer->element_id())) { - if (scrollbar->orientation() == HORIZONTAL) { - scrollbar->SetCurrentPos(current_offset.x()); - scrollbar->SetClipLayerLength(clip_size.width()); - scrollbar->SetScrollLayerLength(scroll_size.width()); - } else { - y_offset_did_change = scrollbar->SetCurrentPos(current_offset.y()); - scrollbar->SetClipLayerLength(clip_size.height()); - scrollbar->SetScrollLayerLength(scroll_size.height()); + viewport_vertical_adjust = bounds_layer->ViewportBoundsDelta().y(); } - scrollbar->SetVerticalAdjust(viewport_vertical_adjust); + + bool y_offset_did_change = false; + for (auto* scrollbar : ScrollbarsFor(scrolling_element_id)) { + if (scrollbar->orientation() == HORIZONTAL) { + scrollbar->SetCurrentPos(current_offset.x()); + scrollbar->SetClipLayerLength(bounds_size.width()); + scrollbar->SetScrollLayerLength(scrolling_size.width()); + } else { + y_offset_did_change = scrollbar->SetCurrentPos(current_offset.y()); + scrollbar->SetClipLayerLength(bounds_size.height()); + scrollbar->SetScrollLayerLength(scrolling_size.height()); + } + scrollbar->SetVerticalAdjust(viewport_vertical_adjust); + } + + if (y_offset_did_change && is_viewport_scrollbar) + TRACE_COUNTER_ID1("cc", "scroll_offset_y", scrolling_layer->id(), + current_offset.y()); } - if (y_offset_did_change && is_viewport_scrollbar) - TRACE_COUNTER_ID1("cc", "scroll_offset_y", scroll_layer->id(), - current_offset.y()); + scrollbar_geometries_need_update_ = false; } const RenderSurfaceImpl* LayerTreeImpl::RootRenderSurface() const { @@ -925,7 +925,9 @@ ClampPageScaleFactorToLimits(current_page_scale_factor())); set_needs_update_draw_properties(); - DidUpdateScrollState(viewport_layer_ids_.inner_viewport_scroll); + + // Viewport scrollbar sizes depend on the page scale factor. + SetScrollbarGeometriesNeedUpdate(); if (IsActiveTree() && layer_tree_host_impl_->ViewportMainScrollLayer()) { if (ScrollbarAnimationController* controller = @@ -1710,9 +1712,8 @@ scroll_element_id, scrollbar_layer->Opacity()); } - // TODO(pdr): Refactor DidUpdateScrollState to use ElementIds instead of - // layer ids and remove this use of LayerIdByElementId. - DidUpdateScrollState(LayerIdByElementId(scroll_element_id)); + // The new scrollbar's geometries need to be initialized. + SetScrollbarGeometriesNeedUpdate(); } void LayerTreeImpl::UnregisterScrollbar( @@ -1754,22 +1755,10 @@ if (layer->scroll_clip_layer_id() == Layer::INVALID_ID) return; - clip_scroll_map_.insert( - std::pair<int, int>(layer->scroll_clip_layer_id(), layer->id())); - - DidUpdateScrollState(layer->id()); - if (settings().scrollbar_animator == LayerTreeSettings::AURA_OVERLAY) layer->set_needs_show_scrollbars(true); } -void LayerTreeImpl::UnregisterScrollLayer(LayerImpl* layer) { - if (layer->scroll_clip_layer_id() == Layer::INVALID_ID) - return; - - clip_scroll_map_.erase(layer->scroll_clip_layer_id()); -} - static bool PointHitsRect( const gfx::PointF& screen_space_point, const gfx::Transform& local_space_to_screen_space_transform,
diff --git a/cc/trees/layer_tree_impl.h b/cc/trees/layer_tree_impl.h index 3bf4e0ad..7f05e43 100644 --- a/cc/trees/layer_tree_impl.h +++ b/cc/trees/layer_tree_impl.h
@@ -453,7 +453,6 @@ ScrollbarSet ScrollbarsFor(ElementId scroll_element_id) const; void RegisterScrollLayer(LayerImpl* layer); - void UnregisterScrollLayer(LayerImpl* layer); LayerImpl* FindFirstScrollingLayerOrDrawnScrollbarThatIsHitByPoint( const gfx::PointF& screen_space_point); @@ -490,7 +489,20 @@ std::unique_ptr<PendingPageScaleAnimation> TakePendingPageScaleAnimation(); void DidUpdateScrollOffset(int layer_id); - void DidUpdateScrollState(int layer_id); + + // Mark the scrollbar geometries (e.g., thumb size and position) as needing an + // update. + void SetScrollbarGeometriesNeedUpdate() { + if (IsActiveTree()) + scrollbar_geometries_need_update_ = true; + } + bool ScrollbarGeometriesNeedUpdate() const { + return scrollbar_geometries_need_update_; + } + // Update the geometries of all scrollbars (e.g., thumb size and position). An + // update only occurs if a scroll-related layer has changed (see: + // SetScrollbarGeometriesNeedUpdate). + void UpdateScrollbarGeometries(); bool have_scroll_event_handlers() const { return have_scroll_event_handlers_; @@ -531,7 +543,6 @@ bool SetPageScaleFactorLimits(float min_page_scale_factor, float max_page_scale_factor); bool IsViewportLayerId(int id) const; - void UpdateScrollbars(int scroll_layer_id, int clip_layer_id); void DidUpdatePageScale(); void PushBrowserControls(const float* top_controls_shown_ratio); bool ClampBrowserControlsShownRatio(); @@ -579,11 +590,6 @@ std::unordered_map<ElementId, FilterOperations, ElementIdHash> element_id_to_filter_animations_; - // Maps from clip layer ids to scroll layer ids. Note that this only includes - // the subset of clip layers that act as scrolling containers. (This is - // derived from LayerImpl::scroll_clip_layer_ and exists to avoid O(n) walks.) - std::unordered_map<int, int> clip_scroll_map_; - struct ScrollbarLayerIds { int horizontal = Layer::INVALID_ID; int vertical = Layer::INVALID_ID; @@ -606,6 +612,10 @@ bool viewport_size_invalid_; bool needs_update_draw_properties_; + // True if a scrollbar geometry value has changed. For example, if the scroll + // offset changes, scrollbar thumb positions need to be updated. + bool scrollbar_geometries_need_update_; + // In impl-side painting mode, this is true when the tree may contain // structural differences relative to the active tree. bool needs_full_tree_sync_;
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 faea5d9..384e420 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java
@@ -1742,6 +1742,12 @@ // exit Chrome on top of closing the tab final boolean minimizeApp = !shouldCloseTab || currentTab.isCreatedForExternalApp(); if (minimizeApp) { + // TODO(mthiesse): We never want to close Chrome through the in-vr back button (but we + // want to reuse CTA logic for how the back button should otherwise behave). We should + // refactor the behaviour in this function so that we can either re-use the parts of + // this behaviour we want, or be able to know in advance whether or not clicking the + // back button would close Chrome so that we can disable it. + if (VrShellDelegate.isInVr()) return true; if (shouldCloseTab) { recordBackPressedUma("Minimized and closed tab", BACK_PRESSED_MINIMIZED_TAB_CLOSED); mActivityStopMetrics.setStopReason(ActivityStopMetrics.STOP_REASON_BACK_BUTTON);
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 d5aa628..44556c8 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
@@ -58,6 +58,7 @@ import org.chromium.chrome.browser.tabmodel.TabModelUtils; import org.chromium.chrome.browser.util.FeatureUtilities; import org.chromium.chrome.browser.util.UrlUtilities; +import org.chromium.chrome.browser.vr_shell.VrShellDelegate; import org.chromium.content_public.browser.NavigationController; import org.chromium.content_public.browser.NavigationEntry; import org.chromium.net.NetworkChangeNotifier; @@ -228,6 +229,7 @@ @Override public void focusSearchBox(boolean beginVoiceSearch, String pastedText) { if (mIsDestroyed) return; + if (VrShellDelegate.isInVr()) return; if (mFakeboxDelegate != null) { if (beginVoiceSearch) { mFakeboxDelegate.startVoiceRecognition();
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/vr_shell/VrShellImpl.java b/chrome/android/java/src/org/chromium/chrome/browser/vr_shell/VrShellImpl.java index a6f0500..8bc205a 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/vr_shell/VrShellImpl.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/vr_shell/VrShellImpl.java
@@ -25,8 +25,10 @@ import org.chromium.base.annotations.CalledByNative; import org.chromium.base.annotations.JNINamespace; import org.chromium.chrome.browser.ChromeActivity; +import org.chromium.chrome.browser.ChromeTabbedActivity; import org.chromium.chrome.browser.NativePage; import org.chromium.chrome.browser.UrlConstants; +import org.chromium.chrome.browser.ntp.NewTabPage; import org.chromium.chrome.browser.tab.EmptyTabObserver; import org.chromium.chrome.browser.tab.Tab; import org.chromium.chrome.browser.tab.TabObserver; @@ -61,15 +63,15 @@ // a way to compute good values for any screen size/scaling ratio. // Increasing DPR any more than this doesn't appear to increase text quality. - private static final float DEFAULT_DPR = 1.2f; + private static final float DEFAULT_DPR = 1.4f; // For WebVR we just create a DPR 1.0 display that matches the physical display size. private static final float WEBVR_DPR = 1.0f; // Fairly arbitrary values that put a good amount of content on the screen without making the // text too small to read. @VisibleForTesting - public static final float DEFAULT_CONTENT_WIDTH = 960f; + public static final float DEFAULT_CONTENT_WIDTH = 800f; @VisibleForTesting - public static final float DEFAULT_CONTENT_HEIGHT = 640f; + public static final float DEFAULT_CONTENT_HEIGHT = 533f; // Make full screen 16:9 until we get exact dimensions from playing video. private static final float FULLSCREEN_CONTENT_WIDTH = 1024f; @@ -585,14 +587,27 @@ @CalledByNative public void navigateBack() { - mActivity.getToolbarManager().back(); + if (mActivity instanceof ChromeTabbedActivity) { + // TODO(mthiesse): We should do this for custom tabs as well, as back for custom tabs + // is also expected to close tabs. + ((ChromeTabbedActivity) mActivity).handleBackPressed(); + } else { + mActivity.getToolbarManager().back(); + } updateHistoryButtonsVisibility(); } private void updateHistoryButtonsVisibility() { - boolean canGoBack = mTab != null && mTab.canGoBack(); - boolean canGoForward = mTab != null && mTab.canGoForward(); - nativeSetHistoryButtonsEnabled(mNativeVrShell, canGoBack, canGoForward); + if (mTab == null) { + nativeSetHistoryButtonsEnabled(mNativeVrShell, false, false); + return; + } + // Hitting back when on the NTP usually closes Chrome, which we don't allow in VR, so we + // just disable the back button. + boolean shouldAlwaysGoBack = mActivity instanceof ChromeTabbedActivity + && (mNativePage == null || !(mNativePage instanceof NewTabPage)); + boolean canGoBack = mTab.canGoBack() || shouldAlwaysGoBack; + nativeSetHistoryButtonsEnabled(mNativeVrShell, canGoBack, mTab.canGoForward()); } @CalledByNative
diff --git a/chrome/browser/accessibility/accessibility_extension_api.cc b/chrome/browser/accessibility/accessibility_extension_api.cc index 62abc25..4e975f3 100644 --- a/chrome/browser/accessibility/accessibility_extension_api.cc +++ b/chrome/browser/accessibility/accessibility_extension_api.cc
@@ -27,6 +27,7 @@ #include "extensions/common/error_utils.h" #include "extensions/common/image_util.h" #include "extensions/common/manifest_handlers/background_info.h" +#include "ui/events/keycodes/keyboard_codes.h" #if defined(OS_CHROMEOS) #include "chrome/browser/chromeos/accessibility/accessibility_manager.h" @@ -164,3 +165,29 @@ return RespondNow(Error(kErrorNotSupported)); } + +#if defined(OS_CHROMEOS) +ExtensionFunction::ResponseAction +AccessibilityPrivateSetSwitchAccessKeysFunction::Run() { + std::unique_ptr<accessibility_private::SetSwitchAccessKeys::Params> params = + accessibility_private::SetSwitchAccessKeys::Params::Create(*args_); + EXTENSION_FUNCTION_VALIDATE(params); + + // For now, only accept key code if it represents an alphanumeric character. + std::set<int> key_codes; + for (auto key_code : params->key_codes) { + EXTENSION_FUNCTION_VALIDATE(key_code >= ui::VKEY_0 && + key_code <= ui::VKEY_Z); + key_codes.insert(key_code); + } + + chromeos::AccessibilityManager* manager = + chromeos::AccessibilityManager::Get(); + + // AccessibilityManager can be null during system shut down, but no need to + // return error in this case, so just check that manager is not null. + if (manager) + manager->SetSwitchAccessKeys(key_codes); + return RespondNow(NoArguments()); +} +#endif // defined (OS_CHROMEOS)
diff --git a/chrome/browser/accessibility/accessibility_extension_api.h b/chrome/browser/accessibility/accessibility_extension_api.h index 3784ec4e..c12e868 100644 --- a/chrome/browser/accessibility/accessibility_extension_api.h +++ b/chrome/browser/accessibility/accessibility_extension_api.h
@@ -50,4 +50,15 @@ ACCESSIBILITY_PRIVATE_DARKENSCREEN) }; +// API function that sets the keys to be captured by Switch Access. +#if defined(OS_CHROMEOS) +class AccessibilityPrivateSetSwitchAccessKeysFunction + : public UIThreadExtensionFunction { + ~AccessibilityPrivateSetSwitchAccessKeysFunction() override {} + ResponseAction Run() override; + DECLARE_EXTENSION_FUNCTION("accessibilityPrivate.setSwitchAccessKeys", + ACCESSIBILITY_PRIVATE_SETSWITCHACCESSKEYS) +}; +#endif // defined (OS_CHROMEOS) + #endif // CHROME_BROWSER_ACCESSIBILITY_ACCESSIBILITY_EXTENSION_API_H_
diff --git a/chrome/browser/android/vr_shell/color_scheme.cc b/chrome/browser/android/vr_shell/color_scheme.cc index 49432770d..c15cc11a 100644 --- a/chrome/browser/android/vr_shell/color_scheme.cc +++ b/chrome/browser/android/vr_shell/color_scheme.cc
@@ -18,47 +18,50 @@ return; ColorScheme& normal_scheme = kColorSchemes[ColorScheme::kModeNormal]; - normal_scheme.horizon = 0xFFE3E3E3; - normal_scheme.floor = 0xFFCFCFCF; - normal_scheme.ceiling = 0xFFDBDBDB; - normal_scheme.floor_grid = SK_ColorWHITE; - normal_scheme.background = 0x66EBEBEB; - normal_scheme.background_hover = 0xFFEAEAEA; - normal_scheme.background_down = 0xFFFAFAFA; + normal_scheme.horizon = 0xFF999999; + normal_scheme.floor = 0xFF8C8C8C; + normal_scheme.ceiling = normal_scheme.floor; + normal_scheme.floor_grid = 0x26FFFFFF; + normal_scheme.background = 0xCCB3B3B3; + normal_scheme.background_hover = 0xFFCCCCCC; + normal_scheme.background_down = 0xFFF3F3F3; normal_scheme.foreground = 0xFF333333; normal_scheme.emphasized = 0xFF000000; normal_scheme.deemphasized = 0xFF5A5A5A; - normal_scheme.separator = 0x33000000; + normal_scheme.separator = 0xFF9E9E9E; normal_scheme.secure = gfx::kGoogleGreen700; normal_scheme.insecure = gfx::kGoogleRed700; normal_scheme.warning = normal_scheme.deemphasized; normal_scheme.disabled = 0x33333333; + normal_scheme.loading_foreground = normal_scheme.foreground; + normal_scheme.loading_background = normal_scheme.floor; kColorSchemes[ColorScheme::kModeFullscreen] = kColorSchemes[ColorScheme::kModeNormal]; ColorScheme& fullscreen_scheme = kColorSchemes[ColorScheme::kModeFullscreen]; - fullscreen_scheme.horizon = 0xFF0A0015; + fullscreen_scheme.horizon = 0xFF000714; fullscreen_scheme.floor = 0xFF070F1C; fullscreen_scheme.ceiling = 0xFF04080F; - fullscreen_scheme.floor_grid = 0x80A3E0FF; + fullscreen_scheme.floor_grid = 0x40A3E0FF; - // TODO(joshcarpenter): Update these per spec. ColorScheme& incognito_scheme = kColorSchemes[ColorScheme::kModeIncognito]; incognito_scheme.horizon = 0xFF2E2E2E; incognito_scheme.floor = 0xFF282828; incognito_scheme.ceiling = 0xFF2F2F2F; - incognito_scheme.floor_grid = 0xFF595959; - incognito_scheme.foreground = 0xFFE6E6E6; - incognito_scheme.emphasized = 0xFFFFFFFF; - incognito_scheme.deemphasized = incognito_scheme.foreground; - incognito_scheme.background = 0xB9454545; - incognito_scheme.background_hover = 0xD9454545; - incognito_scheme.background_down = 0xFF454545; - incognito_scheme.separator = 0xDD595959; - incognito_scheme.secure = incognito_scheme.foreground; - incognito_scheme.insecure = incognito_scheme.foreground; - incognito_scheme.warning = incognito_scheme.foreground; + incognito_scheme.floor_grid = 0xCC595959; + incognito_scheme.foreground = 0xFFBCBCBC; + incognito_scheme.emphasized = 0xFFEDEDED; + incognito_scheme.deemphasized = 0xFF878787; + incognito_scheme.background = 0xCC454545; + incognito_scheme.background_hover = 0xCC505050; + incognito_scheme.background_down = 0xCC888888; + incognito_scheme.separator = 0xFF474747; + incognito_scheme.secure = incognito_scheme.emphasized; + incognito_scheme.insecure = incognito_scheme.emphasized; + incognito_scheme.warning = incognito_scheme.emphasized; incognito_scheme.disabled = 0x33E6E6E6; + normal_scheme.loading_foreground = 0xFF454545; + normal_scheme.loading_background = 0xFF8A8A8A; initialized = true; }
diff --git a/chrome/browser/android/vr_shell/color_scheme.h b/chrome/browser/android/vr_shell/color_scheme.h index 9f14c5ac..ebbed05 100644 --- a/chrome/browser/android/vr_shell/color_scheme.h +++ b/chrome/browser/android/vr_shell/color_scheme.h
@@ -48,6 +48,10 @@ // The color used for disabled icons. SkColor disabled; + + // Colors used for the loading progress bar indicator. + SkColor loading_background; + SkColor loading_foreground; }; } // namespace vr_shell
diff --git a/chrome/browser/android/vr_shell/textures/loading_indicator_texture.cc b/chrome/browser/android/vr_shell/textures/loading_indicator_texture.cc index 2fcf2f2..d330387 100644 --- a/chrome/browser/android/vr_shell/textures/loading_indicator_texture.cc +++ b/chrome/browser/android/vr_shell/textures/loading_indicator_texture.cc
@@ -13,8 +13,8 @@ namespace { -static constexpr SkColor kBackground = 0xCCAAAAAA; -static constexpr SkColor kForeground = 0xCC444444; +static constexpr SkColor kBackground = 0xFF8C8C8C; +static constexpr SkColor kForeground = 0xFF333333; static constexpr float kWidth = 0.24; static constexpr float kHeight = 0.008;
diff --git a/chrome/browser/android/vr_shell/textures/url_bar_texture_unittest.cc b/chrome/browser/android/vr_shell/textures/url_bar_texture_unittest.cc index c89c3102..80d73a23f 100644 --- a/chrome/browser/android/vr_shell/textures/url_bar_texture_unittest.cc +++ b/chrome/browser/android/vr_shell/textures/url_bar_texture_unittest.cc
@@ -22,15 +22,17 @@ namespace vr_shell { +// TODO(cjgrant): Use ColorScheme instead of hardcoded values +// where it makes sense. static const SkColor kEmphasizedColor = 0xFF000000; static const SkColor kDeemphasizedColor = 0xFF5A5A5A; static const SkColor kSecureColor = gfx::kGoogleGreen700; static const SkColor kWarningColor = gfx::kGoogleRed700; -static const SkColor kIncognitoDeemphasizedColor = 0xFFE6E6E6; -static const SkColor kIncognitoEmphasizedColor = 0xFFFFFFFF; -static const SkColor kIncognitoSecureColor = 0xFFE6E6E6; -static const SkColor kIncognitoWarningColor = 0xFFE6E6E6; +static const SkColor kIncognitoDeemphasizedColor = 0xFF878787; +static const SkColor kIncognitoEmphasizedColor = 0xFFEDEDED; +static const SkColor kIncognitoSecureColor = 0xFFEDEDED; +static const SkColor kIncognitoWarningColor = 0xFFEDEDED; static constexpr int kUrlWidth = 400; static constexpr int kUrlHeight = 30;
diff --git a/chrome/browser/android/vr_shell/ui_elements/url_bar.cc b/chrome/browser/android/vr_shell/ui_elements/url_bar.cc index 72dcf1c..34ab3538 100644 --- a/chrome/browser/android/vr_shell/ui_elements/url_bar.cc +++ b/chrome/browser/android/vr_shell/ui_elements/url_bar.cc
@@ -57,7 +57,7 @@ void UrlBar::OnButtonUp(const gfx::PointF& position) { down_ = false; OnStateUpdated(position); - if (texture_->HitsBackButton(position)) + if (can_go_back_ && texture_->HitsBackButton(position)) back_button_callback_.Run(); } @@ -84,7 +84,8 @@ } void UrlBar::SetHistoryButtonsEnabled(bool can_go_back) { - texture_->SetHistoryButtonsEnabled(can_go_back); + can_go_back_ = can_go_back; + texture_->SetHistoryButtonsEnabled(can_go_back_); } void UrlBar::SetSecurityLevel(security_state::SecurityLevel level) {
diff --git a/chrome/browser/android/vr_shell/ui_elements/url_bar.h b/chrome/browser/android/vr_shell/ui_elements/url_bar.h index feeaa4c..5c28acb8 100644 --- a/chrome/browser/android/vr_shell/ui_elements/url_bar.h +++ b/chrome/browser/android/vr_shell/ui_elements/url_bar.h
@@ -48,6 +48,7 @@ std::unique_ptr<UrlBarTexture> texture_; base::Callback<void()> back_button_callback_; bool enabled_ = false; + bool can_go_back_ = false; bool down_ = false; base::TimeTicks last_begin_frame_time_; base::TimeTicks last_update_time_;
diff --git a/chrome/browser/android/vr_shell/ui_scene_manager.cc b/chrome/browser/android/vr_shell/ui_scene_manager.cc index 4a6f4511..2ef910a 100644 --- a/chrome/browser/android/vr_shell/ui_scene_manager.cc +++ b/chrome/browser/android/vr_shell/ui_scene_manager.cc
@@ -50,11 +50,16 @@ static constexpr float kUrlBarWidth = 0.672 * kUrlBarDistance; static constexpr float kUrlBarHeight = 0.088 * kUrlBarDistance; static constexpr float kUrlBarVerticalOffset = -0.516 * kUrlBarDistance; +static constexpr float kUrlBarRotationRad = -0.175; static constexpr float kLoadingIndicatorWidth = 0.24 * kUrlBarDistance; static constexpr float kLoadingIndicatorHeight = 0.008 * kUrlBarDistance; -static constexpr float kLoadingIndicatorOffset = - -0.016 * kUrlBarDistance - kLoadingIndicatorHeight / 2; +static constexpr float kLoadingIndicatorVerticalOffset = + (-kUrlBarVerticalOffset + kContentVerticalOffset - kContentHeight / 2 - + kUrlBarHeight / 2) / + 2; +static constexpr float kLoadingIndicatorDepthOffset = + (kUrlBarDistance - kContentDistance) / 2; static constexpr float kSceneSize = 25.0; static constexpr float kSceneHeight = 4.0; @@ -260,6 +265,7 @@ url_bar->set_debug_id(kUrlBar); url_bar->set_id(AllocateId()); url_bar->set_translation({0, kUrlBarVerticalOffset, -kUrlBarDistance}); + url_bar->set_rotation({1.0, 0.0, 0.0, kUrlBarRotationRad}); url_bar->set_size({kUrlBarWidth, kUrlBarHeight, 1}); url_bar->SetBackButtonCallback( base::Bind(&UiSceneManager::OnBackButtonClicked, base::Unretained(this))); @@ -270,7 +276,8 @@ auto indicator = base::MakeUnique<LoadingIndicator>(256); indicator->set_debug_id(kLoadingIndicator); indicator->set_id(AllocateId()); - indicator->set_translation({0, 0, kLoadingIndicatorOffset}); + indicator->set_translation( + {0, kLoadingIndicatorVerticalOffset, kLoadingIndicatorDepthOffset}); indicator->set_size({kLoadingIndicatorWidth, kLoadingIndicatorHeight, 1}); indicator->set_parent_id(url_bar_->id()); indicator->set_y_anchoring(YAnchoring::YTOP);
diff --git a/chrome/browser/browsing_data/chrome_browsing_data_remover_delegate_unittest.cc b/chrome/browser/browsing_data/chrome_browsing_data_remover_delegate_unittest.cc index 127397c..e097b551 100644 --- a/chrome/browser/browsing_data/chrome_browsing_data_remover_delegate_unittest.cc +++ b/chrome/browser/browsing_data/chrome_browsing_data_remover_delegate_unittest.cc
@@ -78,8 +78,6 @@ #if defined(OS_CHROMEOS) #include "chrome/browser/chromeos/login/users/mock_user_manager.h" #include "chrome/browser/chromeos/login/users/scoped_user_manager_enabler.h" -#include "chrome/browser/chromeos/settings/cros_settings.h" -#include "chrome/browser/chromeos/settings/device_settings_service.h" #include "chromeos/dbus/dbus_thread_manager.h" #include "chromeos/dbus/mock_cryptohome_client.h" #include "components/signin/core/account_id/account_id.h" @@ -1367,8 +1365,6 @@ #if defined(OS_CHROMEOS) TEST_F(ChromeBrowsingDataRemoverDelegateTest, ContentProtectionPlatformKeysRemoval) { - chromeos::ScopedTestDeviceSettingsService test_device_settings_service; - chromeos::ScopedTestCrosSettings test_cros_settings; chromeos::MockUserManager* mock_user_manager = new testing::NiceMock<chromeos::MockUserManager>(); mock_user_manager->SetActiveUser(
diff --git a/chrome/browser/budget_service/budget_manager_browsertest.cc b/chrome/browser/budget_service/budget_manager_browsertest.cc index 65e56f76..954e4d59 100644 --- a/chrome/browser/budget_service/budget_manager_browsertest.cc +++ b/chrome/browser/budget_service/budget_manager_browsertest.cc
@@ -8,12 +8,16 @@ #include "build/build_config.h" #include "chrome/browser/budget_service/budget_manager.h" #include "chrome/browser/budget_service/budget_manager_factory.h" +#include "chrome/browser/content_settings/host_content_settings_map_factory.h" +#include "chrome/browser/engagement/site_engagement_score.h" #include "chrome/browser/engagement/site_engagement_service.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/ui/browser.h" #include "chrome/browser/ui/tabs/tab_strip_model.h" #include "chrome/test/base/in_process_browser_test.h" #include "chrome/test/base/ui_test_utils.h" +#include "components/content_settings/core/browser/host_content_settings_map.h" +#include "components/content_settings/core/common/content_settings_types.h" #include "content/public/browser/browser_context.h" #include "content/public/browser/web_contents.h" #include "content/public/common/content_switches.h" @@ -44,6 +48,15 @@ // InProcessBrowserTest: void SetUpOnMainThread() override { + SiteEngagementScore::SetParamValuesForTesting(); + + // Grant Notification permission for these tests. See the privacy + // requirement for this outlined in https://crbug.com/710809. + HostContentSettingsMapFactory::GetForProfile(browser()->profile()) + ->SetContentSettingDefaultScope(https_server_->base_url(), GURL(), + CONTENT_SETTINGS_TYPE_NOTIFICATIONS, + std::string(), CONTENT_SETTING_ALLOW); + LoadTestPage(); InProcessBrowserTest::SetUpOnMainThread(); budget_manager_ = BudgetManagerFactory::GetForProfile(browser()->profile()); @@ -57,10 +70,21 @@ InProcessBrowserTest::SetUpCommandLine(command_line); } + // Sets the absolute Site Engagement |score| for the testing origin, assuming + // that notification permission has been granted. + // The |score| must be higher than the bonus points awarded to an origin for + // having the Notification permission granted. Should be wrapped in the + // ASSERT_NO_FATAL_FAILURE macro because it contains an ASSERT_GE. void SetSiteEngagementScore(double score) { SiteEngagementService* service = SiteEngagementService::Get(browser()->profile()); - service->ResetBaseScoreForURL(https_server_->GetURL(kTestURL), score); + + double notification_permission_bonus = + SiteEngagementScore::GetNotificationPermissionPoints(); + ASSERT_GE(score, notification_permission_bonus); + + service->ResetBaseScoreForURL(https_server_->GetURL(kTestURL), + score - notification_permission_bonus); } bool RunScript(const std::string& script, std::string* result) { @@ -102,7 +126,7 @@ IN_PROC_BROWSER_TEST_F(BudgetManagerBrowserTest, BudgetInDocument) { std::string script_result; - SetSiteEngagementScore(5); + ASSERT_NO_FATAL_FAILURE(SetSiteEngagementScore(5)); // Site Engagement score of 5 gives a budget of 2. ASSERT_TRUE(RunScript("documentGetBudget()", &script_result)); @@ -135,7 +159,7 @@ ASSERT_EQ("ok - service worker registered", script_result); LoadTestPage(); // Reload to become controlled. - SetSiteEngagementScore(12); + ASSERT_NO_FATAL_FAILURE(SetSiteEngagementScore(12)); ASSERT_TRUE(RunScript("isControlled()", &script_result)); ASSERT_EQ("true - is controlled", script_result);
diff --git a/chrome/browser/budget_service/budget_service_impl.cc b/chrome/browser/budget_service/budget_service_impl.cc index 5bbb9b4..2db176cb 100644 --- a/chrome/browser/budget_service/budget_service_impl.cc +++ b/chrome/browser/budget_service/budget_service_impl.cc
@@ -7,7 +7,10 @@ #include "base/memory/ptr_util.h" #include "chrome/browser/budget_service/budget_manager.h" #include "chrome/browser/budget_service/budget_manager_factory.h" +#include "chrome/browser/permissions/permission_manager.h" +#include "chrome/browser/permissions/permission_manager_factory.h" #include "chrome/browser/profiles/profile.h" +#include "content/public/browser/permission_type.h" #include "content/public/browser/render_process_host.h" #include "mojo/public/cpp/bindings/strong_binding.h" @@ -50,9 +53,33 @@ content::RenderProcessHost::FromID(render_process_id_); DCHECK(host); + Profile* profile = Profile::FromBrowserContext(host->GetBrowserContext()); + + PermissionManager* permission_manager = + PermissionManagerFactory::GetForProfile(profile); + DCHECK(permission_manager); + + // By request of the Privacy Team, we only communicate the budget buckets with + // the developer when the notification permission has been granted. This is + // something the impact of which has to be reconsidered when the feature is + // ready to ship for real. See https://crbug.com/710809 for context. + if (permission_manager->GetPermissionStatus( + content::PermissionType::NOTIFICATIONS, origin.GetURL(), GURL()) != + blink::mojom::PermissionStatus::GRANTED) { + blink::mojom::BudgetStatePtr empty_state(blink::mojom::BudgetState::New()); + empty_state->budget_at = 0; + empty_state->time = base::Time::Now().ToDoubleT(); + + std::vector<blink::mojom::BudgetStatePtr> predictions; + predictions.push_back(std::move(empty_state)); + + callback.Run(blink::mojom::BudgetServiceErrorType::NONE, + std::move(predictions)); + return; + } + // Query the BudgetManager for the budget. - content::BrowserContext* context = host->GetBrowserContext(); - BudgetManagerFactory::GetForProfile(context)->GetBudget(origin, callback); + BudgetManagerFactory::GetForProfile(profile)->GetBudget(origin, callback); } void BudgetServiceImpl::Reserve(const url::Origin& origin,
diff --git a/chrome/browser/chromeos/BUILD.gn b/chrome/browser/chromeos/BUILD.gn index 0074d39..0e1a8ff4 100644 --- a/chrome/browser/chromeos/BUILD.gn +++ b/chrome/browser/chromeos/BUILD.gn
@@ -1541,6 +1541,8 @@ "login/screens/mock_network_screen.h", "login/screens/mock_update_screen.cc", "login/screens/mock_update_screen.h", + "scoped_set_running_on_chromeos_for_testing.cc", + "scoped_set_running_on_chromeos_for_testing.h", ] deps = [ @@ -1841,6 +1843,7 @@ ":device_policy_proto", ":test_support", "//ash/resources", + "//base", "//components/cryptauth:test_support", "//components/drive", "//components/drive:test_support_chromeos",
diff --git a/chrome/browser/chromeos/accessibility/accessibility_manager.cc b/chrome/browser/chromeos/accessibility/accessibility_manager.cc index dcad19e4..d6d1cc3 100644 --- a/chrome/browser/chromeos/accessibility/accessibility_manager.cc +++ b/chrome/browser/chromeos/accessibility/accessibility_manager.cc
@@ -1531,4 +1531,9 @@ extension_registry_observer_.Add(registry); } +void AccessibilityManager::SetSwitchAccessKeys(const std::set<int>& key_codes) { + if (switch_access_enabled_) + switch_access_event_handler_->SetKeysToCapture(key_codes); +} + } // namespace chromeos
diff --git a/chrome/browser/chromeos/accessibility/accessibility_manager.h b/chrome/browser/chromeos/accessibility/accessibility_manager.h index 38f6bca..1553049 100644 --- a/chrome/browser/chromeos/accessibility/accessibility_manager.h +++ b/chrome/browser/chromeos/accessibility/accessibility_manager.h
@@ -311,6 +311,9 @@ } bool keyboard_listener_capture() { return keyboard_listener_capture_; } + // Set the keys to be captured by Switch Access. + void SetSwitchAccessKeys(const std::set<int>& key_codes); + protected: AccessibilityManager(); ~AccessibilityManager() override;
diff --git a/chrome/browser/chromeos/accessibility/switch_access_event_handler.cc b/chrome/browser/chromeos/accessibility/switch_access_event_handler.cc index 3f01698..c9b9cde 100644 --- a/chrome/browser/chromeos/accessibility/switch_access_event_handler.cc +++ b/chrome/browser/chromeos/accessibility/switch_access_event_handler.cc
@@ -24,15 +24,16 @@ ash::Shell::Get()->RemovePreTargetHandler(this); } +void SwitchAccessEventHandler::SetKeysToCapture( + const std::set<int>& key_codes) { + captured_keys_ = key_codes; +} + void SwitchAccessEventHandler::OnKeyEvent(ui::KeyEvent* event) { DCHECK(event); ui::KeyboardCode key_code = event->key_code(); - if (key_code == ui::VKEY_1 || key_code == ui::VKEY_2 || - key_code == ui::VKEY_3 || key_code == ui::VKEY_4 || - key_code == ui::VKEY_5 || key_code == ui::VKEY_6 || - key_code == ui::VKEY_7 || key_code == ui::VKEY_8 || - key_code == ui::VKEY_9) { + if (captured_keys_.find(key_code) != captured_keys_.end()) { CancelEvent(event); DispatchKeyEventToSwitchAccess(*event); }
diff --git a/chrome/browser/chromeos/accessibility/switch_access_event_handler.h b/chrome/browser/chromeos/accessibility/switch_access_event_handler.h index 331f836..e52af0cc 100644 --- a/chrome/browser/chromeos/accessibility/switch_access_event_handler.h +++ b/chrome/browser/chromeos/accessibility/switch_access_event_handler.h
@@ -5,6 +5,8 @@ #ifndef CHROME_BROWSER_CHROMEOS_ACCESSIBILITY_SWITCH_ACCESS_EVENT_HANDLER_H_ #define CHROME_BROWSER_CHROMEOS_ACCESSIBILITY_SWITCH_ACCESS_EVENT_HANDLER_H_ +#include <set> + #include "base/macros.h" #include "ui/events/event_handler.h" @@ -22,6 +24,8 @@ SwitchAccessEventHandler(); ~SwitchAccessEventHandler() override; + void SetKeysToCapture(const std::set<int>& key_codes); + private: // EventHandler: void OnKeyEvent(ui::KeyEvent* event) override; @@ -29,6 +33,8 @@ void CancelEvent(ui::Event* event); void DispatchKeyEventToSwitchAccess(const ui::KeyEvent& event); + std::set<int> captured_keys_; + DISALLOW_COPY_AND_ASSIGN(SwitchAccessEventHandler); };
diff --git a/chrome/browser/chromeos/customization/customization_document_unittest.cc b/chrome/browser/chromeos/customization/customization_document_unittest.cc index 6922a29..1a94c747 100644 --- a/chrome/browser/chromeos/customization/customization_document_unittest.cc +++ b/chrome/browser/chromeos/customization/customization_document_unittest.cc
@@ -10,6 +10,7 @@ #include "base/run_loop.h" #include "base/strings/stringprintf.h" #include "chrome/browser/chromeos/net/network_portal_detector_test_impl.h" +#include "chrome/browser/chromeos/settings/scoped_cros_settings_test_helper.h" #include "chrome/browser/extensions/external_provider_impl.h" #include "chrome/browser/prefs/browser_prefs.h" #include "chrome/browser/ui/app_list/app_list_syncable_service.h" @@ -293,6 +294,7 @@ private: system::ScopedFakeStatisticsProvider fake_statistics_provider_; + ScopedCrosSettingsTestHelper scoped_cros_settings_test_helper_; content::TestBrowserThreadBundle thread_bundle_; TestingPrefServiceSimple local_state_; TestURLFetcherCallback url_callback_;
diff --git a/chrome/browser/chromeos/extensions/active_tab_permission_granter_delegate_chromeos_unittest.cc b/chrome/browser/chromeos/extensions/active_tab_permission_granter_delegate_chromeos_unittest.cc index 9cca475..869863d4 100644 --- a/chrome/browser/chromeos/extensions/active_tab_permission_granter_delegate_chromeos_unittest.cc +++ b/chrome/browser/chromeos/extensions/active_tab_permission_granter_delegate_chromeos_unittest.cc
@@ -4,6 +4,7 @@ #include "chrome/browser/chromeos/extensions/active_tab_permission_granter_delegate_chromeos.h" +#include <memory> #include <string> #include "base/run_loop.h" @@ -41,14 +42,16 @@ void TearDown() override; ActiveTabPermissionGranterDelegateChromeOS delegate_; - chromeos::ScopedTestPublicSessionLoginState login_state_; + std::unique_ptr<chromeos::ScopedTestPublicSessionLoginState> login_state_; }; void ActiveTabPermissionGranterDelegateChromeOSTest::SetUp() { ChromeRenderViewHostTestHarness::SetUp(); + login_state_.reset(new chromeos::ScopedTestPublicSessionLoginState()); } void ActiveTabPermissionGranterDelegateChromeOSTest::TearDown() { + login_state_.reset(); permission_helper::ResetPermissionsForTesting(); ChromeRenderViewHostTestHarness::TearDown(); }
diff --git a/chrome/browser/chromeos/extensions/public_session_permission_helper_unittest.cc b/chrome/browser/chromeos/extensions/public_session_permission_helper_unittest.cc index 56b71b1..4539fa2 100644 --- a/chrome/browser/chromeos/extensions/public_session_permission_helper_unittest.cc +++ b/chrome/browser/chromeos/extensions/public_session_permission_helper_unittest.cc
@@ -119,7 +119,7 @@ std::vector<PermissionIDSet> allowed_permissions_; - chromeos::ScopedTestPublicSessionLoginState login_state_; + std::unique_ptr<chromeos::ScopedTestPublicSessionLoginState> login_state_; private: DISALLOW_COPY_AND_ASSIGN(PublicSessionPermissionHelperTest); @@ -127,11 +127,13 @@ void PublicSessionPermissionHelperTest::SetUp() { ChromeRenderViewHostTestHarness::SetUp(); + login_state_.reset(new chromeos::ScopedTestPublicSessionLoginState()); extension_a_ = LoadManifestHelper("extension_a"); extension_b_ = LoadManifestHelper("extension_b"); } void PublicSessionPermissionHelperTest::TearDown() { + login_state_.reset(); ResetPermissionsForTesting(); ChromeRenderViewHostTestHarness::TearDown(); }
diff --git a/chrome/browser/chromeos/file_manager/path_util_unittest.cc b/chrome/browser/chromeos/file_manager/path_util_unittest.cc index f7ad121..351f450 100644 --- a/chrome/browser/chromeos/file_manager/path_util_unittest.cc +++ b/chrome/browser/chromeos/file_manager/path_util_unittest.cc
@@ -5,9 +5,11 @@ #include "chrome/browser/chromeos/file_manager/path_util.h" #include "base/files/file_path.h" +#include "base/sys_info.h" #include "chrome/browser/chromeos/login/users/fake_chrome_user_manager.h" #include "chrome/browser/chromeos/login/users/scoped_user_manager_enabler.h" #include "chrome/browser/chromeos/profiles/profile_helper.h" +#include "chrome/browser/chromeos/scoped_set_running_on_chromeos_for_testing.h" #include "chrome/browser/download/download_prefs.h" #include "chrome/test/base/testing_browser_process.h" #include "chrome/test/base/testing_profile.h" @@ -20,9 +22,17 @@ namespace util { namespace { +const char kLsbRelease[] = + "CHROMEOS_RELEASE_NAME=Chrome OS\n" + "CHROMEOS_RELEASE_VERSION=1.2.3.4\n"; + TEST(FileManagerPathUtilTest, MultiProfileDownloadsFolderMigration) { content::TestBrowserThreadBundle thread_bundle; TestingProfile profile; + // MigratePathFromOldFormat is explicitly disabled on Linux build. + // So we need to fake that this is real ChromeOS system. + chromeos::ScopedSetRunningOnChromeOSForTesting fake_release(kLsbRelease, + base::Time()); // This looks like "/home/chronos/u-hash/Downloads" in the production // environment.
diff --git a/chrome/browser/chromeos/login/auth/cryptohome_authenticator_unittest.cc b/chrome/browser/chromeos/login/auth/cryptohome_authenticator_unittest.cc index 81b85d51..e33eb0e 100644 --- a/chrome/browser/chromeos/login/auth/cryptohome_authenticator_unittest.cc +++ b/chrome/browser/chromeos/login/auth/cryptohome_authenticator_unittest.cc
@@ -140,15 +140,20 @@ mock_caller_(NULL), mock_homedir_methods_(NULL), owner_key_util_(new ownership::MockOwnerKeyUtil()) { + // Testing profile must be initialized after user_manager_ + + // user_manager_enabler_, because it will create another UserManager + // instance if UserManager instance has not been registed before. + profile_.reset(new TestingProfile); OwnerSettingsServiceChromeOSFactory::GetInstance() ->SetOwnerKeyUtilForTesting(owner_key_util_); user_context_.SetKey(Key("fakepass")); user_context_.SetUserIDHash("me_nowhere_com_hash"); const user_manager::User* user = user_manager_->AddUser(user_context_.GetAccountId()); - profile_.set_profile_name(user_context_.GetAccountId().GetUserEmail()); + profile_->set_profile_name(user_context_.GetAccountId().GetUserEmail()); - ProfileHelper::Get()->SetUserToProfileMappingForTesting(user, &profile_); + ProfileHelper::Get()->SetUserToProfileMappingForTesting(user, + profile_.get()); CreateTransformedKey(Key::KEY_TYPE_SALTED_SHA256_TOP_HALF, SystemSaltGetter::ConvertRawSaltToHexString( @@ -325,9 +330,9 @@ ScopedDeviceSettingsTestHelper device_settings_test_helper_; ScopedTestCrosSettings test_cros_settings_; - TestingProfile profile_; - std::unique_ptr<TestingProfileManager> profile_manager_; chromeos::FakeChromeUserManager* user_manager_; + std::unique_ptr<TestingProfile> profile_; + std::unique_ptr<TestingProfileManager> profile_manager_; ScopedUserManagerEnabler user_manager_enabler_; cryptohome::MockAsyncMethodCaller* mock_caller_;
diff --git a/chrome/browser/chromeos/login/hwid_checker_unittest.cc b/chrome/browser/chromeos/login/hwid_checker_unittest.cc index 6badad8..e7d8e13 100644 --- a/chrome/browser/chromeos/login/hwid_checker_unittest.cc +++ b/chrome/browser/chromeos/login/hwid_checker_unittest.cc
@@ -2,15 +2,15 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include "chrome/browser/chromeos/login/hwid_checker.h" #include "base/sys_info.h" #include "base/test/scoped_command_line.h" #include "base/time/time.h" -#include "chrome/browser/chromeos/login/hwid_checker.h" +#include "chrome/browser/chromeos/scoped_set_running_on_chromeos_for_testing.h" #include "chromeos/system/fake_statistics_provider.h" #include "content/public/common/content_switches.h" #include "testing/gtest/include/gtest/gtest.h" - namespace chromeos { TEST(HWIDCheckerTest, EmptyHWID) { @@ -128,14 +128,9 @@ } #if defined(GOOGLE_CHROME_BUILD) - -// Sets a valid Chrome OS version info so IsRunningOnChromeOS() returns true. -void SetRunningOnChromeOS() { - const char kLsbRelease[] = - "CHROMEOS_RELEASE_NAME=Chrome OS\n" - "CHROMEOS_RELEASE_VERSION=1.2.3.4\n"; - base::SysInfo::SetChromeOSVersionInfoForTest(kLsbRelease, base::Time()); -} +const char kLsbRelease[] = + "CHROMEOS_RELEASE_NAME=Chrome OS\n" + "CHROMEOS_RELEASE_VERSION=1.2.3.4\n"; // Test logic for command line "test-type" switch. TEST(MachineHWIDCheckerTest, TestSwitch) { @@ -146,7 +141,7 @@ // THEN IsMachineHWIDCorrect() is always true. EXPECT_TRUE(IsMachineHWIDCorrect()); - SetRunningOnChromeOS(); + ScopedSetRunningOnChromeOSForTesting fake_release(kLsbRelease, base::Time()); EXPECT_TRUE(IsMachineHWIDCorrect()); system::ScopedFakeStatisticsProvider fake_statistics_provider; @@ -160,7 +155,7 @@ // Test logic when not running on Chrome OS. TEST(MachineHWIDCheckerTest, NotOnChromeOS) { // GIVEN the OS is not Chrome OS. - base::SysInfo::SetChromeOSVersionInfoForTest("", base::Time()); + ScopedSetRunningOnChromeOSForTesting fake_release("", base::Time()); // THEN IsMachineHWIDCorrect() is always true. EXPECT_TRUE(IsMachineHWIDCorrect()); @@ -176,7 +171,7 @@ // Test logic when running on Chrome OS but the HWID is not present. TEST(MachineHWIDCheckerTest, OnCrosNoHWID) { // GIVEN the OS is Chrome OS. - SetRunningOnChromeOS(); + ScopedSetRunningOnChromeOSForTesting fake_release(kLsbRelease, base::Time()); // GIVEN the HWID is not present. system::ScopedFakeStatisticsProvider fake_statistics_provider; @@ -204,7 +199,7 @@ "DELL HORIZON MAGENTA DVT 4770"); // THEN IsMachineHWIDCorrect() is always true. - SetRunningOnChromeOS(); + ScopedSetRunningOnChromeOSForTesting fake_release(kLsbRelease, base::Time()); EXPECT_TRUE(IsMachineHWIDCorrect()); fake_statistics_provider.SetMachineStatistic(system::kIsVmKey, system::kIsVmValueFalse); @@ -222,7 +217,7 @@ system::kIsVmValueTrue); // GIVEN the OS is Chrome OS. - SetRunningOnChromeOS(); + ScopedSetRunningOnChromeOSForTesting fake_release(kLsbRelease, base::Time()); // THEN IsMachineHWIDCorrect() is always true. fake_statistics_provider.SetMachineStatistic(system::kHardwareClassKey, "INVALID_HWID"); @@ -239,7 +234,7 @@ // Test logic when HWID is invalid and we're not in a VM. TEST(MachineHWIDCheckerTest, InvalidHWIDInVMNotTrue) { // GIVEN the OS is Chrome OS. - SetRunningOnChromeOS(); + ScopedSetRunningOnChromeOSForTesting fake_release(kLsbRelease, base::Time()); // GIVEN the HWID is invalid. system::ScopedFakeStatisticsProvider fake_statistics_provider;
diff --git a/chrome/browser/chromeos/login/signin/merge_session_load_page_unittest.cc b/chrome/browser/chromeos/login/signin/merge_session_load_page_unittest.cc index 4de94d8..08c13c5 100644 --- a/chrome/browser/chromeos/login/signin/merge_session_load_page_unittest.cc +++ b/chrome/browser/chromeos/login/signin/merge_session_load_page_unittest.cc
@@ -10,7 +10,6 @@ #include "chrome/browser/chromeos/login/signin/merge_session_load_page.h" #include "chrome/browser/chromeos/login/signin/oauth2_login_manager.h" #include "chrome/browser/chromeos/login/signin/oauth2_login_manager_factory.h" -#include "chrome/browser/chromeos/login/users/scoped_test_user_manager.h" #include "chrome/browser/chromeos/settings/cros_settings.h" #include "chrome/browser/chromeos/settings/device_settings_service.h" #include "chrome/test/base/chrome_render_view_host_test_harness.h" @@ -52,19 +51,7 @@ class MergeSessionLoadPageTest : public ChromeRenderViewHostTestHarness { protected: - void SetUp() override { - ChromeRenderViewHostTestHarness::SetUp(); -#if defined OS_CHROMEOS - test_user_manager_.reset(new chromeos::ScopedTestUserManager()); -#endif - } - void TearDown() override { -#if defined OS_CHROMEOS - // Clean up pending tasks that might depend on the user manager. - base::RunLoop().RunUntilIdle(); - test_user_manager_.reset(); -#endif ChromeRenderViewHostTestHarness::TearDown(); } @@ -118,7 +105,6 @@ private: ScopedTestDeviceSettingsService test_device_settings_service_; ScopedTestCrosSettings test_cros_settings_; - std::unique_ptr<chromeos::ScopedTestUserManager> test_user_manager_; }; TEST_F(MergeSessionLoadPageTest, MergeSessionPageNotShown) {
diff --git a/chrome/browser/chromeos/login/users/chrome_user_manager_impl.cc b/chrome/browser/chromeos/login/users/chrome_user_manager_impl.cc index aca917c..b3fdb4a 100644 --- a/chrome/browser/chromeos/login/users/chrome_user_manager_impl.cc +++ b/chrome/browser/chromeos/login/users/chrome_user_manager_impl.cc
@@ -192,7 +192,9 @@ } ChromeUserManagerImpl::ChromeUserManagerImpl() - : ChromeUserManager(base::ThreadTaskRunnerHandle::Get()), + : ChromeUserManager(base::ThreadTaskRunnerHandle::IsSet() + ? base::ThreadTaskRunnerHandle::Get() + : scoped_refptr<base::TaskRunner>()), cros_settings_(CrosSettings::Get()), device_local_account_policy_service_(NULL), supervised_user_manager_(new SupervisedUserManagerImpl(this)), @@ -201,7 +203,10 @@ UpdateNumberOfUsers(); // UserManager instance should be used only on UI thread. - DCHECK_CURRENTLY_ON(BrowserThread::UI); + // (or in unit tests) + if (base::ThreadTaskRunnerHandle::IsSet()) + DCHECK_CURRENTLY_ON(BrowserThread::UI); + registrar_.Add(this, chrome::NOTIFICATION_OWNERSHIP_STATUS_CHANGED, content::NotificationService::AllSources());
diff --git a/chrome/browser/chromeos/login/users/supervised_user_manager_impl.cc b/chrome/browser/chromeos/login/users/supervised_user_manager_impl.cc index 16a8f5b6..e745b54 100644 --- a/chrome/browser/chromeos/login/users/supervised_user_manager_impl.cc +++ b/chrome/browser/chromeos/login/users/supervised_user_manager_impl.cc
@@ -134,7 +134,9 @@ ChromeUserManagerImpl* owner) : owner_(owner), cros_settings_(CrosSettings::Get()) { // SupervisedUserManager instance should be used only on UI thread. - DCHECK_CURRENTLY_ON(BrowserThread::UI); + // (or in unit_tests) + if (base::ThreadTaskRunnerHandle::IsSet()) + DCHECK_CURRENTLY_ON(BrowserThread::UI); authentication_.reset(new SupervisedUserAuthentication(this)); }
diff --git a/chrome/browser/chromeos/policy/device_cloud_policy_store_chromeos.cc b/chrome/browser/chromeos/policy/device_cloud_policy_store_chromeos.cc index 91c3678..c744172 100644 --- a/chrome/browser/chromeos/policy/device_cloud_policy_store_chromeos.cc +++ b/chrome/browser/chromeos/policy/device_cloud_policy_store_chromeos.cc
@@ -40,7 +40,8 @@ } DeviceCloudPolicyStoreChromeOS::~DeviceCloudPolicyStoreChromeOS() { - device_settings_service_->RemoveObserver(this); + if (device_settings_service_) + device_settings_service_->RemoveObserver(this); } void DeviceCloudPolicyStoreChromeOS::Store( @@ -107,6 +108,7 @@ } void DeviceCloudPolicyStoreChromeOS::OnDeviceSettingsServiceShutdown() { + device_settings_service_->RemoveObserver(this); device_settings_service_ = nullptr; }
diff --git a/chrome/browser/chromeos/scoped_set_running_on_chromeos_for_testing.cc b/chrome/browser/chromeos/scoped_set_running_on_chromeos_for_testing.cc new file mode 100644 index 0000000..55121cc --- /dev/null +++ b/chrome/browser/chromeos/scoped_set_running_on_chromeos_for_testing.cc
@@ -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. + +#include "chrome/browser/chromeos/scoped_set_running_on_chromeos_for_testing.h" + +#include "base/sys_info.h" + +namespace chromeos { + +ScopedSetRunningOnChromeOSForTesting::ScopedSetRunningOnChromeOSForTesting( + const std::string& lsb_release, + const base::Time& lsb_release_time) { + base::SysInfo::SetChromeOSVersionInfoForTest(lsb_release, lsb_release_time); +} + +ScopedSetRunningOnChromeOSForTesting::~ScopedSetRunningOnChromeOSForTesting() { + base::SysInfo::SetChromeOSVersionInfoForTest("", base::Time()); +} + +} // namespace chromeos
diff --git a/chrome/browser/chromeos/scoped_set_running_on_chromeos_for_testing.h b/chrome/browser/chromeos/scoped_set_running_on_chromeos_for_testing.h new file mode 100644 index 0000000..d58b6b67 --- /dev/null +++ b/chrome/browser/chromeos/scoped_set_running_on_chromeos_for_testing.h
@@ -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. + +#ifndef CHROME_BROWSER_CHROMEOS_SCOPED_SET_RUNNING_ON_CHROMEOS_FOR_TESTING_H_ +#define CHROME_BROWSER_CHROMEOS_SCOPED_SET_RUNNING_ON_CHROMEOS_FOR_TESTING_H_ + +#include <string> + +#include "base/time/time.h" + +namespace chromeos { + +// unit_tests must always reset status of modified global singletons, +// otherwise later tests will fail, because they are run in the same process. +// +// This object resets LSB-Release to empty string on destruction, forcing +// is_running_on_chromeos() to return false. +class ScopedSetRunningOnChromeOSForTesting { + public: + ScopedSetRunningOnChromeOSForTesting(const std::string& lsb_release, + const base::Time& lsb_release_time); + ~ScopedSetRunningOnChromeOSForTesting(); + + private: + DISALLOW_COPY_AND_ASSIGN(ScopedSetRunningOnChromeOSForTesting); +}; + +} // namespace chromeos + +#endif // CHROME_BROWSER_CHROMEOS_SCOPED_SET_RUNNING_ON_CHROMEOS_FOR_TESTING_H_
diff --git a/chrome/browser/extensions/active_tab_unittest.cc b/chrome/browser/extensions/active_tab_unittest.cc index 5b732a5..46f4d91 100644 --- a/chrome/browser/extensions/active_tab_unittest.cc +++ b/chrome/browser/extensions/active_tab_unittest.cc
@@ -37,10 +37,8 @@ #if defined(OS_CHROMEOS) #include "base/run_loop.h" #include "chrome/browser/chromeos/login/users/fake_chrome_user_manager.h" -#include "chrome/browser/chromeos/login/users/scoped_test_user_manager.h" #include "chrome/browser/chromeos/login/users/wallpaper/wallpaper_manager.h" #include "chrome/browser/chromeos/profiles/profile_helper.h" -#include "chrome/browser/chromeos/settings/device_settings_service.h" #include "chrome/test/base/scoped_testing_local_state.h" #include "chrome/test/base/testing_browser_process.h" #include "chromeos/login/scoped_test_public_session_login_state.h" @@ -451,10 +449,7 @@ AccountId account_id = AccountId::FromUserEmailGaiaId(user_email, user_id); std::string user_id_hash = chromeos::ProfileHelper::Get()-> GetUserIdHashByUserIdForTesting(user_id); - chromeos::ScopedTestDeviceSettingsService test_device_settings_service_; - chromeos::ScopedTestCrosSettings test_cros_settings_; ScopedTestingLocalState local_state(TestingBrowserProcess::GetGlobal()); - chromeos::ScopedTestUserManager test_user_manager_; chromeos::WallpaperManager::Initialize(); g_browser_process->local_state()->SetString( "PublicAccountPendingDataRemoval", user_email); @@ -491,6 +486,7 @@ // Cleanup. chromeos::WallpaperManager::Shutdown(); delete ActiveTabPermissionGranter::SetPlatformDelegate(nullptr); + chromeos::ChromeUserManager::Get()->Shutdown(); } #endif // defined(OS_CHROMEOS)
diff --git a/chrome/browser/extensions/activity_log/activity_database_unittest.cc b/chrome/browser/extensions/activity_log/activity_database_unittest.cc index 71cb5954..cdd65787 100644 --- a/chrome/browser/extensions/activity_log/activity_database_unittest.cc +++ b/chrome/browser/extensions/activity_log/activity_database_unittest.cc
@@ -30,14 +30,6 @@ #include "sql/statement.h" #include "testing/gtest/include/gtest/gtest.h" -#if defined(OS_CHROMEOS) -#include "chrome/browser/chromeos/login/users/mock_user_manager.h" -#include "chrome/browser/chromeos/login/users/scoped_test_user_manager.h" -#include "chrome/browser/chromeos/settings/cros_settings.h" -#include "chrome/browser/chromeos/settings/device_settings_service.h" -#include "chromeos/chromeos_switches.h" -#endif - using content::BrowserThread; namespace constants = activity_log_constants; @@ -113,18 +105,12 @@ protected: void SetUp() override { ChromeRenderViewHostTestHarness::SetUp(); -#if defined OS_CHROMEOS - test_user_manager_.reset(new chromeos::ScopedTestUserManager()); -#endif base::CommandLine command_line(base::CommandLine::NO_PROGRAM); base::CommandLine::ForCurrentProcess()->AppendSwitch( switches::kEnableExtensionActivityLogTesting); } void TearDown() override { -#if defined OS_CHROMEOS - test_user_manager_.reset(); -#endif ChromeRenderViewHostTestHarness::TearDown(); } @@ -163,12 +149,6 @@ } private: -#if defined OS_CHROMEOS - chromeos::ScopedTestDeviceSettingsService test_device_settings_service_; - chromeos::ScopedTestCrosSettings test_cros_settings_; - std::unique_ptr<chromeos::ScopedTestUserManager> test_user_manager_; -#endif - ActivityDatabaseTestPolicy* db_delegate_; };
diff --git a/chrome/browser/extensions/activity_log/activity_log_enabled_unittest.cc b/chrome/browser/extensions/activity_log/activity_log_enabled_unittest.cc index 87356ec4..4432214 100644 --- a/chrome/browser/extensions/activity_log/activity_log_enabled_unittest.cc +++ b/chrome/browser/extensions/activity_log/activity_log_enabled_unittest.cc
@@ -17,12 +17,6 @@ #include "extensions/browser/uninstall_reason.h" #include "extensions/common/extension_builder.h" -#if defined OS_CHROMEOS -#include "chrome/browser/chromeos/login/users/scoped_test_user_manager.h" -#include "chrome/browser/chromeos/settings/cros_settings.h" -#include "chrome/browser/chromeos/settings/device_settings_service.h" -#endif - namespace extensions { const char kExtensionID[] = "eplckmlabaanikjjcgnigddmagoglhmp"; @@ -31,23 +25,11 @@ protected: void SetUp() override { ChromeRenderViewHostTestHarness::SetUp(); -#if defined OS_CHROMEOS - test_user_manager_.reset(new chromeos::ScopedTestUserManager()); -#endif } void TearDown() override { -#if defined OS_CHROMEOS - test_user_manager_.reset(); -#endif ChromeRenderViewHostTestHarness::TearDown(); } - -#if defined OS_CHROMEOS - chromeos::ScopedTestDeviceSettingsService test_device_settings_service_; - chromeos::ScopedTestCrosSettings test_cros_settings_; - std::unique_ptr<chromeos::ScopedTestUserManager> test_user_manager_; -#endif }; TEST_F(ActivityLogEnabledTest, NoSwitch) {
diff --git a/chrome/browser/extensions/activity_log/activity_log_unittest.cc b/chrome/browser/extensions/activity_log/activity_log_unittest.cc index d0aa3a4..cf22b31 100644 --- a/chrome/browser/extensions/activity_log/activity_log_unittest.cc +++ b/chrome/browser/extensions/activity_log/activity_log_unittest.cc
@@ -33,12 +33,6 @@ #include "extensions/common/test_util.h" #include "testing/gtest/include/gtest/gtest.h" -#if defined(OS_CHROMEOS) -#include "chrome/browser/chromeos/login/users/scoped_test_user_manager.h" -#include "chrome/browser/chromeos/settings/cros_settings.h" -#include "chrome/browser/chromeos/settings/device_settings_service.h" -#endif - namespace { const char kExtensionId[] = "abc"; @@ -65,9 +59,6 @@ virtual bool enable_activity_logging_switch() const { return true; } void SetUp() override { ChromeRenderViewHostTestHarness::SetUp(); -#if defined OS_CHROMEOS - test_user_manager_.reset(new chromeos::ScopedTestUserManager()); -#endif base::CommandLine command_line(base::CommandLine::NO_PROGRAM); if (enable_activity_logging_switch()) { base::CommandLine::ForCurrentProcess()->AppendSwitch( @@ -82,9 +73,6 @@ } void TearDown() override { -#if defined OS_CHROMEOS - test_user_manager_.reset(); -#endif base::RunLoop().RunUntilIdle(); ChromeRenderViewHostTestHarness::TearDown(); } @@ -198,12 +186,6 @@ } ExtensionService* extension_service_; - -#if defined OS_CHROMEOS - chromeos::ScopedTestDeviceSettingsService test_device_settings_service_; - chromeos::ScopedTestCrosSettings test_cros_settings_; - std::unique_ptr<chromeos::ScopedTestUserManager> test_user_manager_; -#endif }; TEST_F(ActivityLogTest, Construct) {
diff --git a/chrome/browser/extensions/api/image_writer_private/operation_manager_unittest.cc b/chrome/browser/extensions/api/image_writer_private/operation_manager_unittest.cc index 22297d9..5580e87 100644 --- a/chrome/browser/extensions/api/image_writer_private/operation_manager_unittest.cc +++ b/chrome/browser/extensions/api/image_writer_private/operation_manager_unittest.cc
@@ -18,12 +18,6 @@ #include "extensions/browser/event_router.h" #include "extensions/browser/event_router_factory.h" -#if defined(OS_CHROMEOS) -#include "chrome/browser/chromeos/login/users/scoped_test_user_manager.h" -#include "chrome/browser/chromeos/settings/cros_settings.h" -#include "chrome/browser/chromeos/settings/device_settings_service.h" -#endif - namespace extensions { namespace image_writer { @@ -85,12 +79,6 @@ TestingProfile test_profile_; FakeEventRouter* event_router_; - -#if defined(OS_CHROMEOS) - chromeos::ScopedTestDeviceSettingsService test_device_settings_service_; - chromeos::ScopedTestCrosSettings test_cros_settings_; - chromeos::ScopedTestUserManager test_user_manager_; -#endif }; TEST_F(ImageWriterOperationManagerTest, WriteFromFile) {
diff --git a/chrome/browser/extensions/bookmark_app_helper.cc b/chrome/browser/extensions/bookmark_app_helper.cc index 671c980..1119372 100644 --- a/chrome/browser/extensions/bookmark_app_helper.cc +++ b/chrome/browser/extensions/bookmark_app_helper.cc
@@ -76,8 +76,8 @@ #endif // defined(OS_WIN) #if defined(USE_ASH) -#include "ash/shelf/shelf_model.h" // nogncheck -#include "ash/shell.h" // nogncheck +#include "ash/public/cpp/shelf_model.h" // nogncheck +#include "ash/shell.h" // nogncheck #endif namespace {
diff --git a/chrome/browser/extensions/chrome_app_icon.cc b/chrome/browser/extensions/chrome_app_icon.cc index 1b526d2..6c012f73 100644 --- a/chrome/browser/extensions/chrome_app_icon.cc +++ b/chrome/browser/extensions/chrome_app_icon.cc
@@ -90,7 +90,8 @@ void ChromeAppIcon::Reload() { const Extension* extension = GetExtension(); icon_ = base::MakeUnique<IconImage>( - browser_context_, extension, IconsInfo::GetIcons(extension), + browser_context_, extension, + extension ? IconsInfo::GetIcons(extension) : ExtensionIconSet(), resource_size_in_dip_, util::GetDefaultAppIcon(), this); UpdateIcon(); }
diff --git a/chrome/browser/extensions/extension_install_ui_browsertest.cc b/chrome/browser/extensions/extension_install_ui_browsertest.cc index 3941ca78..8902bd59 100644 --- a/chrome/browser/extensions/extension_install_ui_browsertest.cc +++ b/chrome/browser/extensions/extension_install_ui_browsertest.cc
@@ -26,6 +26,7 @@ #include "content/public/browser/web_contents.h" #include "content/public/test/browser_test_utils.h" #include "extensions/browser/app_sorting.h" +#include "extensions/browser/extension_registry.h" #include "extensions/common/constants.h" using content::WebContents; @@ -34,6 +35,9 @@ class ExtensionInstallUIBrowserTest : public ExtensionBrowserTest { public: + ExtensionInstallUIBrowserTest() {} + ~ExtensionInstallUIBrowserTest() override {} + // Checks that a theme info bar is currently visible and issues an undo to // revert to the previous theme. void VerifyThemeInfoBarAndUndoInstall() { @@ -47,18 +51,29 @@ infobar_service->infobar_at(0)->delegate()->AsConfirmInfoBarDelegate(); ASSERT_TRUE(delegate); delegate->Cancel(); + WaitForThemeChange(); ASSERT_EQ(0U, infobar_service->infobar_count()); } // Install the given theme from the data dir and verify expected name. void InstallThemeAndVerify(const char* theme_name, const std::string& expected_name) { - // If there is already a theme installed, the current theme should be - // disabled and the new one installed + enabled. - int expected_change = GetTheme() ? 0 : 1; const base::FilePath theme_path = test_data_dir_.AppendASCII(theme_name); - ASSERT_TRUE(InstallExtensionWithUIAutoConfirm(theme_path, expected_change, - browser())); + const bool theme_exists = GetTheme(); + // Themes install asynchronously so we must check the number of enabled + // extensions after theme install completes. + size_t num_before = extensions::ExtensionRegistry::Get(profile()) + ->enabled_extensions() + .size(); + ASSERT_TRUE(InstallExtensionWithUIAutoConfirm(theme_path, 1, browser())); + WaitForThemeChange(); + size_t num_after = extensions::ExtensionRegistry::Get(profile()) + ->enabled_extensions() + .size(); + // If a theme was already installed, we're just swapping one for another, so + // no change in extension count. + EXPECT_EQ(num_before + (theme_exists ? 0 : 1), num_after); + const Extension* theme = GetTheme(); ASSERT_TRUE(theme); ASSERT_EQ(theme->name(), expected_name); @@ -67,6 +82,17 @@ const Extension* GetTheme() const { return ThemeServiceFactory::GetThemeForProfile(browser()->profile()); } + + void WaitForThemeChange() { + content::WindowedNotificationObserver theme_change_observer( + chrome::NOTIFICATION_BROWSER_THEME_CHANGED, + content::Source<ThemeService>( + ThemeServiceFactory::GetForProfile(browser()->profile()))); + theme_change_observer.Wait(); + } + + private: + DISALLOW_COPY_AND_ASSIGN(ExtensionInstallUIBrowserTest); }; // Fails on Linux and Windows (http://crbug.com/580907). @@ -75,6 +101,7 @@ // Install theme once and undo to verify we go back to default theme. base::FilePath theme_crx = PackExtension(test_data_dir_.AppendASCII("theme")); ASSERT_TRUE(InstallExtensionWithUIAutoConfirm(theme_crx, 1, browser())); + WaitForThemeChange(); const Extension* theme = GetTheme(); ASSERT_TRUE(theme); std::string theme_id = theme->id(); @@ -83,10 +110,12 @@ // Set the same theme twice and undo to verify we go back to default theme. ASSERT_TRUE(InstallExtensionWithUIAutoConfirm(theme_crx, 0, browser())); + WaitForThemeChange(); theme = GetTheme(); ASSERT_TRUE(theme); ASSERT_EQ(theme_id, theme->id()); ASSERT_TRUE(InstallExtensionWithUIAutoConfirm(theme_crx, 0, browser())); + WaitForThemeChange(); theme = GetTheme(); ASSERT_TRUE(theme); ASSERT_EQ(theme_id, theme->id()); @@ -104,7 +133,7 @@ // Then install second theme. InstallThemeAndVerify("theme2", "snowflake theme"); const Extension* theme2 = GetTheme(); - EXPECT_FALSE(theme_id == theme2->id()); + EXPECT_NE(theme_id, theme2->id()); // Undo second theme will revert to first theme. VerifyThemeInfoBarAndUndoInstall();
diff --git a/chrome/browser/extensions/extension_service_sync_unittest.cc b/chrome/browser/extensions/extension_service_sync_unittest.cc index 1b810fa..8d91faa8 100644 --- a/chrome/browser/extensions/extension_service_sync_unittest.cc +++ b/chrome/browser/extensions/extension_service_sync_unittest.cc
@@ -18,6 +18,7 @@ #include "base/metrics/field_trial.h" #include "base/test/mock_entropy_provider.h" #include "base/test/scoped_feature_list.h" +#include "chrome/browser/chrome_notification_types.h" #include "chrome/browser/extensions/api/webstore_private/webstore_private_api.h" #include "chrome/browser/extensions/component_loader.h" #include "chrome/browser/extensions/extension_service.h" @@ -28,6 +29,8 @@ #include "chrome/browser/extensions/scripting_permissions_modifier.h" #include "chrome/browser/extensions/updater/extension_updater.h" #include "chrome/browser/sync/profile_sync_service_factory.h" +#include "chrome/browser/themes/theme_service.h" +#include "chrome/browser/themes/theme_service_factory.h" #include "chrome/common/chrome_constants.h" #include "chrome/common/chrome_switches.h" #include "chrome/common/extensions/sync_helper.h" @@ -1563,6 +1566,11 @@ // Installing a theme should not result in a sync change (themes are handled // separately by ThemeSyncableService). InstallCRX(data_dir().AppendASCII("theme.crx"), INSTALL_NEW); + content::WindowedNotificationObserver theme_change_observer( + chrome::NOTIFICATION_BROWSER_THEME_CHANGED, + content::Source<ThemeService>( + ThemeServiceFactory::GetForProfile(profile()))); + theme_change_observer.Wait(); EXPECT_TRUE(processor->changes().empty()); }
diff --git a/chrome/browser/extensions/extension_service_unittest.cc b/chrome/browser/extensions/extension_service_unittest.cc index 6e3e7e3..04fcdd5a 100644 --- a/chrome/browser/extensions/extension_service_unittest.cc +++ b/chrome/browser/extensions/extension_service_unittest.cc
@@ -146,12 +146,6 @@ #include "ui/base/l10n/l10n_util.h" #include "url/gurl.h" -#if defined(OS_CHROMEOS) -#include "chrome/browser/chromeos/login/users/scoped_test_user_manager.h" -#include "chrome/browser/chromeos/settings/cros_settings.h" -#include "chrome/browser/chromeos/settings/device_settings_service.h" -#endif - // The blacklist tests rely on the safe-browsing database. #if defined(SAFE_BROWSING_DB_LOCAL) #define ENABLE_BLACKLIST_TESTS @@ -5564,12 +5558,6 @@ ExtensionErrorReporter::Init(false); // no noisy errors ExtensionsReadyRecorder recorder; std::unique_ptr<TestingProfile> profile(new TestingProfile()); -#if defined OS_CHROMEOS - chromeos::ScopedTestDeviceSettingsService device_settings_service; - chromeos::ScopedTestCrosSettings cros_settings; - std::unique_ptr<chromeos::ScopedTestUserManager> user_manager( - new chromeos::ScopedTestUserManager); -#endif std::unique_ptr<base::CommandLine> command_line; base::FilePath install_dir = profile->GetPath() .AppendASCII(extensions::kInstallDirectoryName); @@ -5586,9 +5574,6 @@ service->Init(); content::RunAllBlockingPoolTasksUntilIdle(); EXPECT_TRUE(recorder.ready()); -#if defined OS_CHROMEOS - user_manager.reset(); -#endif // If either the command line or pref is set, we are disabled. recorder.set_ready(false);
diff --git a/chrome/browser/extensions/test_extension_system.cc b/chrome/browser/extensions/test_extension_system.cc index f775635..e0453fec 100644 --- a/chrome/browser/extensions/test_extension_system.cc +++ b/chrome/browser/extensions/test_extension_system.cc
@@ -28,6 +28,9 @@ #include "extensions/browser/state_store.h" #include "extensions/browser/value_store/test_value_store_factory.h" #include "extensions/browser/value_store/testing_value_store.h" +#if defined(OS_CHROMEOS) +#include "components/user_manager/user_manager.h" +#endif using content::BrowserThread; @@ -38,7 +41,12 @@ store_factory_(new TestValueStoreFactory()), info_map_(new InfoMap()), quota_service_(new QuotaService()), - app_sorting_(new ChromeAppSorting(profile_)) {} + app_sorting_(new ChromeAppSorting(profile_)) { +#if defined(OS_CHROMEOS) + if (!user_manager::UserManager::IsInitialized()) + test_user_manager_.reset(new chromeos::ScopedTestUserManager); +#endif +} TestExtensionSystem::~TestExtensionSystem() { }
diff --git a/chrome/browser/extensions/test_extension_system.h b/chrome/browser/extensions/test_extension_system.h index 0a54e6c7..6b1c8008 100644 --- a/chrome/browser/extensions/test_extension_system.h +++ b/chrome/browser/extensions/test_extension_system.h
@@ -10,6 +10,10 @@ #include "extensions/browser/extension_system.h" #include "extensions/common/one_shot_event.h" +#if defined(OS_CHROMEOS) +#include "chrome/browser/chromeos/login/users/scoped_test_user_manager.h" +#endif + class Profile; class TestingValueStore; @@ -91,6 +95,10 @@ std::unique_ptr<QuotaService> quota_service_; std::unique_ptr<AppSorting> app_sorting_; OneShotEvent ready_; + +#if defined(OS_CHROMEOS) + std::unique_ptr<chromeos::ScopedTestUserManager> test_user_manager_; +#endif }; } // namespace extensions
diff --git a/chrome/browser/extensions/theme_installed_infobar_delegate.cc b/chrome/browser/extensions/theme_installed_infobar_delegate.cc index 16d349d..e432bbdc 100644 --- a/chrome/browser/extensions/theme_installed_infobar_delegate.cc +++ b/chrome/browser/extensions/theme_installed_infobar_delegate.cc
@@ -144,7 +144,9 @@ const extensions::Extension* previous_theme = extension_service_->GetExtensionById(previous_theme_id_, true); if (previous_theme) { - theme_service_->SetTheme(previous_theme); + theme_service_->RevertToTheme(previous_theme); + // TODO(estade): while we're waiting to close, it would be nice to + // indicate that the theme is busy reverting. return false; // The theme change will close us. } }
diff --git a/chrome/browser/infobars/infobars_browsertest.cc b/chrome/browser/infobars/infobars_browsertest.cc index 090f91b..a887674 100644 --- a/chrome/browser/infobars/infobars_browsertest.cc +++ b/chrome/browser/infobars/infobars_browsertest.cc
@@ -76,8 +76,8 @@ chrome::NOTIFICATION_TAB_CONTENTS_INFOBAR_REMOVED, content::NotificationService::AllSources()); InstallExtension("theme2.crx"); - infobar_added_2.Wait(); infobar_removed_1.Wait(); + infobar_added_2.Wait(); EXPECT_EQ( 0u, InfoBarService::FromWebContents(
diff --git a/chrome/browser/media_galleries/media_file_system_registry_unittest.cc b/chrome/browser/media_galleries/media_file_system_registry_unittest.cc index a12384f..a7723003 100644 --- a/chrome/browser/media_galleries/media_file_system_registry_unittest.cc +++ b/chrome/browser/media_galleries/media_file_system_registry_unittest.cc
@@ -52,7 +52,6 @@ #include "testing/gtest/include/gtest/gtest.h" #if defined(OS_CHROMEOS) -#include "chrome/browser/chromeos/login/users/scoped_test_user_manager.h" #include "chrome/browser/chromeos/settings/cros_settings.h" #include "chrome/browser/chromeos/settings/device_settings_service.h" #endif @@ -379,7 +378,6 @@ #if defined(OS_CHROMEOS) chromeos::ScopedTestDeviceSettingsService test_device_settings_service_; chromeos::ScopedTestCrosSettings test_cros_settings_; - std::unique_ptr<chromeos::ScopedTestUserManager> test_user_manager_; #endif MockProfileSharedRenderProcessHostFactory rph_factory_; @@ -777,10 +775,6 @@ test_file_system_context_ = new TestMediaFileSystemContext( g_browser_process->media_file_system_registry()); -#if defined(OS_CHROMEOS) - test_user_manager_.reset(new chromeos::ScopedTestUserManager()); -#endif - ASSERT_TRUE(galleries_dir_.CreateUniqueTempDir()); empty_dir_ = galleries_dir_.GetPath().AppendASCII("empty"); ASSERT_TRUE(base::CreateDirectory(empty_dir_)); @@ -796,10 +790,6 @@ g_browser_process->media_file_system_registry(); EXPECT_EQ(0U, GetExtensionGalleriesHostCount(registry)); -#if defined(OS_CHROMEOS) - test_user_manager_.reset(); -#endif - // The TestingProfile must be destroyed before the TestingBrowserProcess // because it uses it in its destructor. ChromeRenderViewHostTestHarness::TearDown();
diff --git a/chrome/browser/notifications/extension_welcome_notification_unittest.cc b/chrome/browser/notifications/extension_welcome_notification_unittest.cc index a46d881..acaf8e8 100644 --- a/chrome/browser/notifications/extension_welcome_notification_unittest.cc +++ b/chrome/browser/notifications/extension_welcome_notification_unittest.cc
@@ -139,6 +139,7 @@ task_runner_ = new base::TestSimpleTaskRunner(); base::MessageLoop::current()->SetTaskRunner(task_runner_); profile_.reset(new TestingProfile()); + task_runner()->RunUntilIdle(); delegate_ = new WelcomeNotificationDelegate(); welcome_notification_.reset( ExtensionWelcomeNotification::Create(profile_.get(), delegate_));
diff --git a/chrome/browser/notifications/platform_notification_service_unittest.cc b/chrome/browser/notifications/platform_notification_service_unittest.cc index d0a79e4..7e34a6b0 100644 --- a/chrome/browser/notifications/platform_notification_service_unittest.cc +++ b/chrome/browser/notifications/platform_notification_service_unittest.cc
@@ -48,12 +48,6 @@ #include "extensions/common/value_builder.h" #endif -#if BUILDFLAG(ENABLE_EXTENSIONS) && defined(OS_CHROMEOS) -#include "chrome/browser/chromeos/login/users/scoped_test_user_manager.h" -#include "chrome/browser/chromeos/settings/cros_settings.h" -#include "chrome/browser/chromeos/settings/device_settings_service.h" -#endif - using content::NotificationResources; using content::PlatformNotificationData; @@ -344,13 +338,6 @@ } TEST_F(PlatformNotificationServiceTest, ExtensionPermissionChecks) { -#if defined(OS_CHROMEOS) - // The ExtensionService on Chrome OS requires these objects to be initialized. - chromeos::ScopedTestDeviceSettingsService test_device_settings_service; - chromeos::ScopedTestCrosSettings test_cros_settings; - chromeos::ScopedTestUserManager test_user_manager; -#endif - base::CommandLine command_line(base::CommandLine::NO_PROGRAM); extensions::TestExtensionSystem* test_extension_system = static_cast<extensions::TestExtensionSystem*>(
diff --git a/chrome/browser/resources/chromeos/switch_access/compiled_resources2.gyp b/chrome/browser/resources/chromeos/switch_access/compiled_resources2.gyp index 1846c41..1b127ee 100644 --- a/chrome/browser/resources/chromeos/switch_access/compiled_resources2.gyp +++ b/chrome/browser/resources/chromeos/switch_access/compiled_resources2.gyp
@@ -40,6 +40,7 @@ { 'target_name': 'keyboard_handler', 'dependencies': [ + '<(EXTERNS_GYP):accessibility_private', 'switch_access_interface', ], 'includes': ['../../../../../third_party/closure_compiler/compile_js2.gypi'],
diff --git a/chrome/browser/resources/chromeos/switch_access/keyboard_handler.js b/chrome/browser/resources/chromeos/switch_access/keyboard_handler.js index 901690f..7231a6b 100644 --- a/chrome/browser/resources/chromeos/switch_access/keyboard_handler.js +++ b/chrome/browser/resources/chromeos/switch_access/keyboard_handler.js
@@ -28,6 +28,10 @@ * @private */ init_: function() { + // Capture keycodes for keys 1 through 4, and 6 through 9. + let keyCodes = ['1', '2', '3', '4', '6', '7', '8', '9'].map( + key => key.charCodeAt(0)); + chrome.accessibilityPrivate.setSwitchAccessKeys(keyCodes); document.addEventListener('keyup', this.handleKeyEvent_.bind(this)); },
diff --git a/chrome/browser/safe_browsing/safe_browsing_service_browsertest.cc b/chrome/browser/safe_browsing/safe_browsing_service_browsertest.cc index 1baa562b..4c9f799 100644 --- a/chrome/browser/safe_browsing/safe_browsing_service_browsertest.cc +++ b/chrome/browser/safe_browsing/safe_browsing_service_browsertest.cc
@@ -2095,6 +2095,9 @@ // START: These tests use SafeBrowsingService::Client to directly interact with // SafeBrowsingService. /////////////////////////////////////////////////////////////////////////////// +#if defined(GOOGLE_CHROME_BUILD) +// This test is only enabled when GOOGLE_CHROME_BUILD is true because the store +// that this test uses is only populated on GOOGLE_CHROME_BUILD builds. IN_PROC_BROWSER_TEST_F(V4SafeBrowsingServiceTest, CheckDownloadUrl) { GURL badbin_url = embedded_test_server()->GetURL(kMalwareFile); std::vector<GURL> badbin_urls(1, badbin_url); @@ -2112,6 +2115,7 @@ // Now, the badbin_url is not safe since it is added to download database. EXPECT_EQ(SB_THREAT_TYPE_BINARY_MALWARE_URL, client->GetThreatType()); } +#endif // defined(GOOGLE_CHROME_BUILD) IN_PROC_BROWSER_TEST_F(V4SafeBrowsingServiceTest, CheckUnwantedSoftwareUrl) { const GURL bad_url = embedded_test_server()->GetURL(kMalwareFile); @@ -2186,6 +2190,9 @@ } } +#if defined(GOOGLE_CHROME_BUILD) +// This test is only enabled when GOOGLE_CHROME_BUILD is true because the store +// that this test uses is only populated on GOOGLE_CHROME_BUILD builds. IN_PROC_BROWSER_TEST_F(V4SafeBrowsingServiceTest, CheckDownloadUrlRedirects) { GURL original_url = embedded_test_server()->GetURL(kEmptyPage); GURL badbin_url = embedded_test_server()->GetURL(kMalwareFile); @@ -2208,6 +2215,7 @@ // Now, the badbin_url is not safe since it is added to download database. EXPECT_EQ(SB_THREAT_TYPE_BINARY_MALWARE_URL, client->GetThreatType()); } +#endif // defined(GOOGLE_CHROME_BUILD) #if defined(GOOGLE_CHROME_BUILD) // This test is only enabled when GOOGLE_CHROME_BUILD is true because the store @@ -2242,7 +2250,7 @@ client->CheckResourceUrl(embedded_test_server()->GetURL(kEmptyPage)); EXPECT_EQ(SB_THREAT_TYPE_SAFE, client->GetThreatType()); } -#endif +#endif // defined(GOOGLE_CHROME_BUILD) /////////////////////////////////////////////////////////////////////////////// // END: These tests use SafeBrowsingService::Client to directly interact with // SafeBrowsingService.
diff --git a/chrome/browser/signin/easy_unlock_service_regular.cc b/chrome/browser/signin/easy_unlock_service_regular.cc index 83b58ffe..0c3dabce 100644 --- a/chrome/browser/signin/easy_unlock_service_regular.cc +++ b/chrome/browser/signin/easy_unlock_service_regular.cc
@@ -586,6 +586,9 @@ const cryptauth::ToggleEasyUnlockResponse& response) { cryptauth_client_.reset(); + GetCryptAuthDeviceManager()->ForceSyncNow( + cryptauth::InvocationReason::INVOCATION_REASON_FEATURE_TOGGLED); + EasyUnlockService::ResetLocalStateForUser(GetAccountId()); SetRemoteDevices(base::ListValue()); SetTurnOffFlowStatus(IDLE); ReloadAppAndLockScreen();
diff --git a/chrome/browser/spellchecker/spellcheck_custom_dictionary.cc b/chrome/browser/spellchecker/spellcheck_custom_dictionary.cc index ed77bc7..4f2c183 100644 --- a/chrome/browser/spellchecker/spellcheck_custom_dictionary.cc +++ b/chrome/browser/spellchecker/spellcheck_custom_dictionary.cc
@@ -6,8 +6,10 @@ #include <stddef.h> +#include <algorithm> #include <functional> #include <utility> +#include <vector> #include "base/files/file_util.h" #include "base/files/important_file_writer.h" @@ -15,6 +17,8 @@ #include "base/strings/string_number_conversions.h" #include "base/strings/string_split.h" #include "base/strings/string_util.h" +#include "base/task_runner_util.h" +#include "base/task_scheduler/post_task.h" #include "chrome/common/chrome_constants.h" #include "components/spellcheck/browser/spellcheck_host_metrics.h" #include "components/spellcheck/common/spellcheck_common.h" @@ -59,7 +63,6 @@ // invalid checksum, then returns ChecksumStatus::INVALID and clears |words|. ChecksumStatus LoadFile(const base::FilePath& file_path, std::set<std::string>* words) { - DCHECK_CURRENTLY_ON(BrowserThread::FILE); DCHECK(words); words->clear(); std::string contents; @@ -118,7 +121,6 @@ // called on the file thread. std::unique_ptr<SpellcheckCustomDictionary::LoadFileResult> LoadDictionaryFileReliably(const base::FilePath& path) { - DCHECK_CURRENTLY_ON(BrowserThread::FILE); // Load the contents and verify the checksum. std::unique_ptr<SpellcheckCustomDictionary::LoadFileResult> result( new SpellcheckCustomDictionary::LoadFileResult); @@ -140,7 +142,6 @@ // the custom spellcheck dictionary at |path|. void SaveDictionaryFileReliably(const base::FilePath& path, const std::set<std::string>& custom_words) { - DCHECK_CURRENTLY_ON(BrowserThread::FILE); std::stringstream content; for (const std::string& word : custom_words) content << word << '\n'; @@ -155,7 +156,6 @@ const base::FilePath& path, std::unique_ptr<SpellcheckCustomDictionary::LoadFileResult> load_file_result) { - DCHECK_CURRENTLY_ON(BrowserThread::FILE); DCHECK(load_file_result); SaveDictionaryFileReliably(path, load_file_result->words); } @@ -212,19 +212,21 @@ : custom_dictionary_path_( dictionary_directory_name.Append(chrome::kCustomDictionaryFileName)), is_loaded_(false), - weak_ptr_factory_(this) { -} + task_runner_( + base::CreateSequencedTaskRunnerWithTraits({base::MayBlock()})), + weak_ptr_factory_(this) {} SpellcheckCustomDictionary::~SpellcheckCustomDictionary() { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); } const std::set<std::string>& SpellcheckCustomDictionary::GetWords() const { - DCHECK_CURRENTLY_ON(BrowserThread::UI); + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); return words_; } bool SpellcheckCustomDictionary::AddWord(const std::string& word) { - DCHECK_CURRENTLY_ON(BrowserThread::UI); + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); std::unique_ptr<Change> dictionary_change(new Change); dictionary_change->AddWord(word); int result = dictionary_change->Sanitize(GetWords()); @@ -236,7 +238,7 @@ } bool SpellcheckCustomDictionary::RemoveWord(const std::string& word) { - DCHECK_CURRENTLY_ON(BrowserThread::UI); + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); std::unique_ptr<Change> dictionary_change(new Change); dictionary_change->RemoveWord(word); int result = dictionary_change->Sanitize(GetWords()); @@ -252,36 +254,36 @@ } void SpellcheckCustomDictionary::AddObserver(Observer* observer) { - DCHECK_CURRENTLY_ON(BrowserThread::UI); + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); DCHECK(observer); observers_.AddObserver(observer); } void SpellcheckCustomDictionary::RemoveObserver(Observer* observer) { - DCHECK_CURRENTLY_ON(BrowserThread::UI); + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); DCHECK(observer); observers_.RemoveObserver(observer); } bool SpellcheckCustomDictionary::IsLoaded() { - DCHECK_CURRENTLY_ON(BrowserThread::UI); + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); return is_loaded_; } bool SpellcheckCustomDictionary::IsSyncing() { - DCHECK_CURRENTLY_ON(BrowserThread::UI); + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); return !!sync_processor_.get(); } void SpellcheckCustomDictionary::Load() { - DCHECK_CURRENTLY_ON(BrowserThread::UI); - BrowserThread::PostTaskAndReplyWithResult( - BrowserThread::FILE, - FROM_HERE, - base::Bind(&SpellcheckCustomDictionary::LoadDictionaryFile, - custom_dictionary_path_), - base::Bind(&SpellcheckCustomDictionary::OnLoaded, - weak_ptr_factory_.GetWeakPtr())); + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + + base::PostTaskAndReplyWithResult( + task_runner_.get(), FROM_HERE, + base::BindOnce(&SpellcheckCustomDictionary::LoadDictionaryFile, + custom_dictionary_path_), + base::BindOnce(&SpellcheckCustomDictionary::OnLoaded, + weak_ptr_factory_.GetWeakPtr())); } syncer::SyncMergeResult SpellcheckCustomDictionary::MergeDataAndStartSyncing( @@ -289,7 +291,7 @@ const syncer::SyncDataList& initial_sync_data, std::unique_ptr<syncer::SyncChangeProcessor> sync_processor, std::unique_ptr<syncer::SyncErrorFactory> sync_error_handler) { - DCHECK_CURRENTLY_ON(BrowserThread::UI); + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); DCHECK(!sync_processor_.get()); DCHECK(!sync_error_handler_.get()); DCHECK(sync_processor.get()); @@ -323,7 +325,7 @@ } void SpellcheckCustomDictionary::StopSyncing(syncer::ModelType type) { - DCHECK_CURRENTLY_ON(BrowserThread::UI); + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); DCHECK_EQ(syncer::DICTIONARY, type); sync_processor_.reset(); sync_error_handler_.reset(); @@ -331,7 +333,7 @@ syncer::SyncDataList SpellcheckCustomDictionary::GetAllSyncData( syncer::ModelType type) const { - DCHECK_CURRENTLY_ON(BrowserThread::UI); + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); DCHECK_EQ(syncer::DICTIONARY, type); syncer::SyncDataList data; size_t i = 0; @@ -348,7 +350,7 @@ syncer::SyncError SpellcheckCustomDictionary::ProcessSyncChanges( const tracked_objects::Location& from_here, const syncer::SyncChangeList& change_list) { - DCHECK_CURRENTLY_ON(BrowserThread::UI); + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); std::unique_ptr<Change> dictionary_change(new Change); for (const syncer::SyncChange& change : change_list) { DCHECK(change.IsValid()); @@ -387,7 +389,6 @@ // static std::unique_ptr<SpellcheckCustomDictionary::LoadFileResult> SpellcheckCustomDictionary::LoadDictionaryFile(const base::FilePath& path) { - DCHECK_CURRENTLY_ON(BrowserThread::FILE); std::unique_ptr<LoadFileResult> result = LoadDictionaryFileReliably(path); SpellCheckHostMetrics::RecordCustomWordCountStats(result->words.size()); return result; @@ -397,7 +398,6 @@ void SpellcheckCustomDictionary::UpdateDictionaryFile( std::unique_ptr<Change> dictionary_change, const base::FilePath& path) { - DCHECK_CURRENTLY_ON(BrowserThread::FILE); DCHECK(dictionary_change); if (dictionary_change->empty()) @@ -417,7 +417,7 @@ void SpellcheckCustomDictionary::OnLoaded( std::unique_ptr<LoadFileResult> result) { - DCHECK_CURRENTLY_ON(BrowserThread::UI); + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); DCHECK(result); Change dictionary_change; dictionary_change.AddWords(result->words); @@ -439,7 +439,7 @@ } void SpellcheckCustomDictionary::Apply(const Change& dictionary_change) { - DCHECK_CURRENTLY_ON(BrowserThread::UI); + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); if (!dictionary_change.to_add().empty()) { words_.insert(dictionary_change.to_add().begin(), dictionary_change.to_add().end()); @@ -450,26 +450,28 @@ void SpellcheckCustomDictionary::FixInvalidFile( std::unique_ptr<LoadFileResult> load_file_result) { - DCHECK_CURRENTLY_ON(BrowserThread::UI); - BrowserThread::PostTask( - BrowserThread::FILE, FROM_HERE, - base::Bind(&SavePassedWordsToDictionaryFileReliably, - custom_dictionary_path_, base::Passed(&load_file_result))); + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + + task_runner_->PostTask( + FROM_HERE, + base::BindOnce(&SavePassedWordsToDictionaryFileReliably, + custom_dictionary_path_, std::move(load_file_result))); } void SpellcheckCustomDictionary::Save( std::unique_ptr<Change> dictionary_change) { - DCHECK_CURRENTLY_ON(BrowserThread::UI); + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); fix_invalid_file_.Cancel(); - BrowserThread::PostTask( - BrowserThread::FILE, FROM_HERE, - base::Bind(&SpellcheckCustomDictionary::UpdateDictionaryFile, - base::Passed(&dictionary_change), custom_dictionary_path_)); + + task_runner_->PostTask( + FROM_HERE, + base::BindOnce(&SpellcheckCustomDictionary::UpdateDictionaryFile, + std::move(dictionary_change), custom_dictionary_path_)); } syncer::SyncError SpellcheckCustomDictionary::Sync( const Change& dictionary_change) { - DCHECK_CURRENTLY_ON(BrowserThread::UI); + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); syncer::SyncError error; if (!IsSyncing() || dictionary_change.empty()) return error; @@ -520,7 +522,7 @@ } void SpellcheckCustomDictionary::Notify(const Change& dictionary_change) { - DCHECK_CURRENTLY_ON(BrowserThread::UI); + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); if (!IsLoaded() || dictionary_change.empty()) return; for (Observer& observer : observers_)
diff --git a/chrome/browser/spellchecker/spellcheck_custom_dictionary.h b/chrome/browser/spellchecker/spellcheck_custom_dictionary.h index d1da70ae..43a8f84 100644 --- a/chrome/browser/spellchecker/spellcheck_custom_dictionary.h +++ b/chrome/browser/spellchecker/spellcheck_custom_dictionary.h
@@ -12,8 +12,11 @@ #include "base/cancelable_callback.h" #include "base/files/file_path.h" #include "base/macros.h" +#include "base/memory/ref_counted.h" #include "base/memory/weak_ptr.h" #include "base/observer_list.h" +#include "base/sequence_checker.h" +#include "base/sequenced_task_runner.h" #include "components/spellcheck/browser/spellcheck_dictionary.h" #include "components/sync/model/sync_data.h" #include "components/sync/model/sync_error.h" @@ -217,6 +220,10 @@ // A post-startup task to fix the invalid custom dictionary file. base::CancelableClosure fix_invalid_file_; + scoped_refptr<base::SequencedTaskRunner> task_runner_; + + SEQUENCE_CHECKER(sequence_checker_); + // Used to create weak pointers for an instance of this class. base::WeakPtrFactory<SpellcheckCustomDictionary> weak_ptr_factory_;
diff --git a/chrome/browser/spellchecker/spellcheck_hunspell_dictionary.cc b/chrome/browser/spellchecker/spellcheck_hunspell_dictionary.cc index 32e04b8..9eff2b3 100644 --- a/chrome/browser/spellchecker/spellcheck_hunspell_dictionary.cc +++ b/chrome/browser/spellchecker/spellcheck_hunspell_dictionary.cc
@@ -13,6 +13,8 @@ #include "base/logging.h" #include "base/path_service.h" #include "base/single_thread_task_runner.h" +#include "base/task_runner_util.h" +#include "base/task_scheduler/post_task.h" #include "base/threading/thread_task_runner_handle.h" #include "build/build_config.h" #include "chrome/browser/spellchecker/spellcheck_service.h" @@ -21,7 +23,6 @@ #include "components/spellcheck/browser/spellcheck_platform.h" #include "components/spellcheck/common/spellcheck_common.h" #include "components/spellcheck/spellcheck_build_features.h" -#include "content/public/browser/browser_thread.h" #include "content/public/browser/render_process_host.h" #include "net/base/load_flags.h" #include "net/traffic_annotation/network_traffic_annotation.h" @@ -34,13 +35,10 @@ #include "third_party/hunspell/google/bdict.h" #endif -using content::BrowserThread; - namespace { // Close the file. void CloseDictionary(base::File file) { - DCHECK_CURRENTLY_ON(BrowserThread::FILE); file.Close(); } @@ -48,8 +46,6 @@ // returns false. bool SaveDictionaryData(std::unique_ptr<std::string> data, const base::FilePath& path) { - DCHECK_CURRENTLY_ON(BrowserThread::FILE); - size_t bytes_written = base::WriteFile(path, data->data(), data->length()); if (bytes_written != data->length()) { @@ -76,15 +72,12 @@ } // namespace -SpellcheckHunspellDictionary::DictionaryFile::DictionaryFile() { -} +SpellcheckHunspellDictionary::DictionaryFile::DictionaryFile() = default; SpellcheckHunspellDictionary::DictionaryFile::~DictionaryFile() { if (file.IsValid()) { - BrowserThread::PostTask( - BrowserThread::FILE, - FROM_HERE, - base::Bind(&CloseDictionary, Passed(&file))); + base::PostTaskWithTraits(FROM_HERE, {base::MayBlock()}, + base::BindOnce(&CloseDictionary, std::move(file))); } } @@ -109,14 +102,16 @@ request_context_getter_(request_context_getter), spellcheck_service_(spellcheck_service), download_status_(DOWNLOAD_NONE), - weak_ptr_factory_(this) { -} + task_runner_( + base::CreateSequencedTaskRunnerWithTraits({base::MayBlock()})), + weak_ptr_factory_(this) {} SpellcheckHunspellDictionary::~SpellcheckHunspellDictionary() { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); } void SpellcheckHunspellDictionary::Load() { - DCHECK_CURRENTLY_ON(BrowserThread::UI); + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); #if BUILDFLAG(USE_BROWSER_SPELLCHECKER) if (spellcheck_platform::SpellCheckerAvailable() && @@ -135,11 +130,10 @@ // Mac falls back on hunspell if its platform spellchecker isn't available. // However, Android does not support hunspell. #if !defined(OS_ANDROID) - BrowserThread::PostTaskAndReplyWithResult( - BrowserThread::FILE, - FROM_HERE, - base::Bind(&InitializeDictionaryLocation, language_), - base::Bind( + base::PostTaskAndReplyWithResult( + task_runner_.get(), FROM_HERE, + base::BindOnce(&InitializeDictionaryLocation, language_), + base::BindOnce( &SpellcheckHunspellDictionary::InitializeDictionaryLocationComplete, weak_ptr_factory_.GetWeakPtr())); #endif // !OS_ANDROID @@ -147,7 +141,7 @@ void SpellcheckHunspellDictionary::RetryDownloadDictionary( net::URLRequestContextGetter* request_context_getter) { - DCHECK_CURRENTLY_ON(BrowserThread::UI); + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); if (dictionary_file_.file.IsValid()) { NOTREACHED(); return; @@ -173,12 +167,12 @@ } void SpellcheckHunspellDictionary::AddObserver(Observer* observer) { - DCHECK_CURRENTLY_ON(BrowserThread::UI); + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); observers_.AddObserver(observer); } void SpellcheckHunspellDictionary::RemoveObserver(Observer* observer) { - DCHECK_CURRENTLY_ON(BrowserThread::UI); + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); observers_.RemoveObserver(observer); } @@ -193,7 +187,7 @@ void SpellcheckHunspellDictionary::OnURLFetchComplete( const net::URLFetcher* source) { DCHECK(source); - DCHECK_CURRENTLY_ON(BrowserThread::UI); + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); std::unique_ptr<net::URLFetcher> fetcher_destructor(fetcher_.release()); if ((source->GetResponseCode() / 100) != 2) { @@ -223,14 +217,12 @@ } #endif - BrowserThread::PostTaskAndReplyWithResult<bool>( - BrowserThread::FILE, - FROM_HERE, - base::Bind(&SaveDictionaryData, - base::Passed(&data), - dictionary_file_.path), - base::Bind(&SpellcheckHunspellDictionary::SaveDictionaryDataComplete, - weak_ptr_factory_.GetWeakPtr())); + base::PostTaskAndReplyWithResult( + task_runner_.get(), FROM_HERE, + base::BindOnce(&SaveDictionaryData, std::move(data), + dictionary_file_.path), + base::BindOnce(&SpellcheckHunspellDictionary::SaveDictionaryDataComplete, + weak_ptr_factory_.GetWeakPtr())); } GURL SpellcheckHunspellDictionary::GetDictionaryURL() { @@ -245,7 +237,7 @@ } void SpellcheckHunspellDictionary::DownloadDictionary(GURL url) { - DCHECK_CURRENTLY_ON(BrowserThread::UI); + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); DCHECK(request_context_getter_); download_status_ = DOWNLOAD_IN_PROGRESS; @@ -294,9 +286,10 @@ // For systemwide installations on Windows, the default directory may not // have permissions for download. In that case, the alternate directory for // download is chrome::DIR_USER_DATA. +// +// static SpellcheckHunspellDictionary::DictionaryFile SpellcheckHunspellDictionary::OpenDictionaryFile(const base::FilePath& path) { - DCHECK_CURRENTLY_ON(BrowserThread::FILE); DictionaryFile dictionary; #if defined(OS_WIN) @@ -340,11 +333,11 @@ // The default place where the spellcheck dictionary resides is // chrome::DIR_APP_DICTIONARIES. +// +// static SpellcheckHunspellDictionary::DictionaryFile SpellcheckHunspellDictionary::InitializeDictionaryLocation( const std::string& language) { - DCHECK_CURRENTLY_ON(BrowserThread::FILE); - // Initialize the BDICT path. Initialization should be in the FILE thread // because it checks if there is a "Dictionaries" directory and create it. base::FilePath dict_dir; @@ -357,7 +350,6 @@ void SpellcheckHunspellDictionary::InitializeDictionaryLocationComplete( DictionaryFile file) { - DCHECK_CURRENTLY_ON(BrowserThread::UI); dictionary_file_ = std::move(file); if (!dictionary_file_.file.IsValid()) { @@ -382,7 +374,7 @@ void SpellcheckHunspellDictionary::SaveDictionaryDataComplete( bool dictionary_saved) { - DCHECK_CURRENTLY_ON(BrowserThread::UI); + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); if (dictionary_saved) { download_status_ = DOWNLOAD_NONE;
diff --git a/chrome/browser/spellchecker/spellcheck_hunspell_dictionary.h b/chrome/browser/spellchecker/spellcheck_hunspell_dictionary.h index 77b22c9..8b0de815 100644 --- a/chrome/browser/spellchecker/spellcheck_hunspell_dictionary.h +++ b/chrome/browser/spellchecker/spellcheck_hunspell_dictionary.h
@@ -11,8 +11,11 @@ #include "base/files/file.h" #include "base/files/file_path.h" #include "base/macros.h" +#include "base/memory/ref_counted.h" #include "base/memory/weak_ptr.h" #include "base/observer_list.h" +#include "base/sequence_checker.h" +#include "base/sequenced_task_runner.h" #include "components/spellcheck/browser/spellcheck_dictionary.h" #include "net/url_request/url_fetcher_delegate.h" @@ -165,6 +168,10 @@ // Dictionary file path and descriptor. DictionaryFile dictionary_file_; + scoped_refptr<base::SequencedTaskRunner> task_runner_; + + SEQUENCE_CHECKER(sequence_checker_); + base::WeakPtrFactory<SpellcheckHunspellDictionary> weak_ptr_factory_; DISALLOW_COPY_AND_ASSIGN(SpellcheckHunspellDictionary);
diff --git a/chrome/browser/spellchecker/spellcheck_service_browsertest.cc b/chrome/browser/spellchecker/spellcheck_service_browsertest.cc index 2afbf90..bbd0b4bf 100644 --- a/chrome/browser/spellchecker/spellcheck_service_browsertest.cc +++ b/chrome/browser/spellchecker/spellcheck_service_browsertest.cc
@@ -463,8 +463,7 @@ // Check the received event. Also we check if Chrome has successfully deleted // the corrupted dictionary. We delete the corrupted dictionary to avoid // leaking it when this test fails. - content::RunAllPendingInMessageLoop(content::BrowserThread::FILE); - content::RunAllPendingInMessageLoop(content::BrowserThread::UI); + base::RunLoop().RunUntilIdle(); EXPECT_EQ(SpellcheckService::BDICT_CORRUPTED, SpellcheckService::GetStatusEvent()); base::ThreadRestrictions::ScopedAllowIO allow_io;
diff --git a/chrome/browser/sync/test/integration/single_client_themes_sync_test.cc b/chrome/browser/sync/test/integration/single_client_themes_sync_test.cc index ce5099f..fa5b140d 100644 --- a/chrome/browser/sync/test/integration/single_client_themes_sync_test.cc +++ b/chrome/browser/sync/test/integration/single_client_themes_sync_test.cc
@@ -4,20 +4,25 @@ #include "base/macros.h" #include "build/build_config.h" +#include "chrome/browser/chrome_notification_types.h" +#include "chrome/browser/sync/test/integration/sync_integration_test_util.h" #include "chrome/browser/sync/test/integration/sync_test.h" #include "chrome/browser/sync/test/integration/themes_helper.h" #include "chrome/browser/sync/test/integration/updated_progress_marker_checker.h" +#include "chrome/browser/themes/theme_service_factory.h" #include "components/browser_sync/profile_sync_service.h" +#include "content/public/test/test_utils.h" using themes_helper::GetCustomTheme; using themes_helper::GetThemeID; -using themes_helper::UseCustomTheme; using themes_helper::UseDefaultTheme; using themes_helper::UseSystemTheme; using themes_helper::UsingCustomTheme; using themes_helper::UsingDefaultTheme; using themes_helper::UsingSystemTheme; +namespace { + class SingleClientThemesSyncTest : public SyncTest { public: SingleClientThemesSyncTest() : SyncTest(SINGLE_CLIENT) {} @@ -34,18 +39,18 @@ IN_PROC_BROWSER_TEST_F(SingleClientThemesSyncTest, CustomTheme) { ASSERT_TRUE(SetupSync()) << "SetupSync() failed."; - ASSERT_FALSE(UsingCustomTheme(GetProfile(0))); - ASSERT_FALSE(UsingCustomTheme(verifier())); + EXPECT_FALSE(UsingCustomTheme(GetProfile(0))); + EXPECT_FALSE(UsingCustomTheme(verifier())); - UseCustomTheme(GetProfile(0), 0); - UseCustomTheme(verifier(), 0); - ASSERT_EQ(GetCustomTheme(0), GetThemeID(GetProfile(0))); - ASSERT_EQ(GetCustomTheme(0), GetThemeID(verifier())); + SetCustomTheme(GetProfile(0)); + SetCustomTheme(verifier()); + EXPECT_EQ(GetCustomTheme(0), GetThemeID(GetProfile(0))); + EXPECT_EQ(GetCustomTheme(0), GetThemeID(verifier())); - ASSERT_TRUE(UpdatedProgressMarkerChecker(GetSyncService(0)).Wait()); + EXPECT_TRUE(UpdatedProgressMarkerChecker(GetSyncService(0)).Wait()); - ASSERT_EQ(GetCustomTheme(0), GetThemeID(GetProfile(0))); - ASSERT_EQ(GetCustomTheme(0), GetThemeID(verifier())); + EXPECT_EQ(GetCustomTheme(0), GetThemeID(GetProfile(0))); + EXPECT_EQ(GetCustomTheme(0), GetThemeID(verifier())); } // TODO(sync): Fails on Chrome OS. See http://crbug.com/84575. @@ -56,41 +61,43 @@ #endif // OS_CHROMEOS ASSERT_TRUE(SetupSync()) << "SetupSync() failed."; - UseCustomTheme(GetProfile(0), 0); - UseCustomTheme(verifier(), 0); - ASSERT_FALSE(UsingSystemTheme(GetProfile(0))); - ASSERT_FALSE(UsingSystemTheme(verifier())); + SetCustomTheme(GetProfile(0)); + SetCustomTheme(verifier()); + EXPECT_FALSE(UsingSystemTheme(GetProfile(0))); + EXPECT_FALSE(UsingSystemTheme(verifier())); - ASSERT_TRUE(UpdatedProgressMarkerChecker(GetSyncService(0)).Wait()); + EXPECT_TRUE(UpdatedProgressMarkerChecker(GetSyncService(0)).Wait()); UseSystemTheme(GetProfile(0)); UseSystemTheme(verifier()); - ASSERT_TRUE(UsingSystemTheme(GetProfile(0))); - ASSERT_TRUE(UsingSystemTheme(verifier())); + EXPECT_TRUE(UsingSystemTheme(GetProfile(0))); + EXPECT_TRUE(UsingSystemTheme(verifier())); - ASSERT_TRUE(UpdatedProgressMarkerChecker(GetSyncService(0)).Wait()); + EXPECT_TRUE(UpdatedProgressMarkerChecker(GetSyncService(0)).Wait()); - ASSERT_TRUE(UsingSystemTheme(GetProfile(0))); - ASSERT_TRUE(UsingSystemTheme(verifier())); + EXPECT_TRUE(UsingSystemTheme(GetProfile(0))); + EXPECT_TRUE(UsingSystemTheme(verifier())); } IN_PROC_BROWSER_TEST_F(SingleClientThemesSyncTest, DefaultTheme) { ASSERT_TRUE(SetupSync()) << "SetupSync() failed."; - UseCustomTheme(GetProfile(0), 0); - UseCustomTheme(verifier(), 0); - ASSERT_FALSE(UsingDefaultTheme(GetProfile(0))); - ASSERT_FALSE(UsingDefaultTheme(verifier())); + SetCustomTheme(GetProfile(0)); + EXPECT_FALSE(UsingDefaultTheme(GetProfile(0))); - ASSERT_TRUE(UpdatedProgressMarkerChecker(GetSyncService(0)).Wait()); + SetCustomTheme(verifier()); + EXPECT_FALSE(UsingDefaultTheme(verifier())); + EXPECT_TRUE(UpdatedProgressMarkerChecker(GetSyncService(0)).Wait()); UseDefaultTheme(GetProfile(0)); + EXPECT_TRUE(UsingDefaultTheme(GetProfile(0))); UseDefaultTheme(verifier()); - ASSERT_TRUE(UsingDefaultTheme(GetProfile(0))); - ASSERT_TRUE(UsingDefaultTheme(verifier())); + EXPECT_TRUE(UsingDefaultTheme(verifier())); - ASSERT_TRUE(UpdatedProgressMarkerChecker(GetSyncService(0)).Wait()); + EXPECT_TRUE(UpdatedProgressMarkerChecker(GetSyncService(0)).Wait()); - ASSERT_TRUE(UsingDefaultTheme(GetProfile(0))); - ASSERT_TRUE(UsingDefaultTheme(verifier())); + EXPECT_TRUE(UsingDefaultTheme(GetProfile(0))); + EXPECT_TRUE(UsingDefaultTheme(verifier())); } + +} // namespace
diff --git a/chrome/browser/sync/test/integration/sync_integration_test_util.cc b/chrome/browser/sync/test/integration/sync_integration_test_util.cc index 42ef3e24..d9afa063 100644 --- a/chrome/browser/sync/test/integration/sync_integration_test_util.cc +++ b/chrome/browser/sync/test/integration/sync_integration_test_util.cc
@@ -5,7 +5,20 @@ #include "chrome/browser/sync/test/integration/sync_integration_test_util.h" #include "base/strings/stringprintf.h" +#include "chrome/browser/chrome_notification_types.h" +#include "chrome/browser/sync/test/integration/themes_helper.h" +#include "chrome/browser/themes/theme_service_factory.h" #include "components/browser_sync/profile_sync_service.h" +#include "content/public/test/test_utils.h" + +void SetCustomTheme(Profile* profile, int theme_index) { + themes_helper::UseCustomTheme(profile, theme_index); + content::WindowedNotificationObserver theme_change_observer( + chrome::NOTIFICATION_BROWSER_THEME_CHANGED, + content::Source<ThemeService>( + ThemeServiceFactory::GetForProfile(profile))); + theme_change_observer.Wait(); +} ServerCountMatchStatusChecker::ServerCountMatchStatusChecker( syncer::ModelType type,
diff --git a/chrome/browser/sync/test/integration/sync_integration_test_util.h b/chrome/browser/sync/test/integration/sync_integration_test_util.h index c3af2d7..63df4c9 100644 --- a/chrome/browser/sync/test/integration/sync_integration_test_util.h +++ b/chrome/browser/sync/test/integration/sync_integration_test_util.h
@@ -11,10 +11,15 @@ #include "chrome/browser/sync/test/integration/single_client_status_change_checker.h" #include "components/sync/base/model_type.h" +class Profile; + namespace browser_sync { class ProfileSyncService; } // namespace browser_sync +// Sets a custom theme and wait until the asynchronous process is done. +void SetCustomTheme(Profile* profile, int theme_index = 0); + // Checker to block until the server has a given number of entities. class ServerCountMatchStatusChecker : public fake_server::FakeServerMatchStatusChecker {
diff --git a/chrome/browser/sync/test/integration/two_client_themes_sync_test.cc b/chrome/browser/sync/test/integration/two_client_themes_sync_test.cc index 530f209..68beb142 100644 --- a/chrome/browser/sync/test/integration/two_client_themes_sync_test.cc +++ b/chrome/browser/sync/test/integration/two_client_themes_sync_test.cc
@@ -38,7 +38,7 @@ ASSERT_FALSE(UsingCustomTheme(GetProfile(0))); ASSERT_FALSE(UsingCustomTheme(GetProfile(1))); - UseCustomTheme(GetProfile(0), 0); + SetCustomTheme(GetProfile(0)); ASSERT_EQ(GetCustomTheme(0), GetThemeID(GetProfile(0))); // TODO(sync): Add functions to simulate when a pending extension @@ -57,8 +57,8 @@ E2E_ENABLED(CustomThenSyncNative)) { ASSERT_TRUE(SetupClients()); - UseCustomTheme(GetProfile(0), 0); - UseCustomTheme(GetProfile(1), 0); + SetCustomTheme(GetProfile(0)); + SetCustomTheme(GetProfile(1)); ASSERT_TRUE(SetupSync()); @@ -77,8 +77,8 @@ E2E_ENABLED(CustomThenSyncDefault)) { ASSERT_TRUE(SetupClients()); - UseCustomTheme(GetProfile(0), 0); - UseCustomTheme(GetProfile(1), 0); + SetCustomTheme(GetProfile(0)); + SetCustomTheme(GetProfile(1)); ASSERT_TRUE(SetupSync()); @@ -97,7 +97,7 @@ IN_PROC_BROWSER_TEST_F(TwoClientThemesSyncTest, E2E_ENABLED(CycleOptions)) { ASSERT_TRUE(SetupSync()) << "SetupSync() failed."; - UseCustomTheme(GetProfile(0), 0); + SetCustomTheme(GetProfile(0)); ASSERT_TRUE( ThemePendingInstallChecker(GetProfile(1), GetCustomTheme(0)).Wait()); @@ -115,7 +115,7 @@ EXPECT_TRUE(UsingDefaultTheme(GetProfile(0))); EXPECT_TRUE(UsingDefaultTheme(GetProfile(1))); - UseCustomTheme(GetProfile(0), 1); + SetCustomTheme(GetProfile(0), 1); ASSERT_TRUE( ThemePendingInstallChecker(GetProfile(1), GetCustomTheme(1)).Wait()); EXPECT_EQ(GetCustomTheme(1), GetThemeID(GetProfile(0)));
diff --git a/chrome/browser/themes/browser_theme_pack.cc b/chrome/browser/themes/browser_theme_pack.cc index a352c67..4f3da008 100644 --- a/chrome/browser/themes/browser_theme_pack.cc +++ b/chrome/browser/themes/browser_theme_pack.cc
@@ -546,13 +546,13 @@ } // static -scoped_refptr<BrowserThemePack> BrowserThemePack::BuildFromExtension( - const Extension* extension) { - DCHECK_CURRENTLY_ON(BrowserThread::UI); +void BrowserThemePack::BuildFromExtension( + const extensions::Extension* extension, + scoped_refptr<BrowserThemePack> pack) { DCHECK(extension); DCHECK(extension->is_theme()); + DCHECK(!pack->is_valid()); - scoped_refptr<BrowserThemePack> pack(new BrowserThemePack); pack->BuildHeader(extension); pack->BuildTintsFromJSON(extensions::ThemeInfo::GetTints(extension)); pack->BuildColorsFromJSON(extensions::ThemeInfo::GetColors(extension)); @@ -567,14 +567,14 @@ &file_paths); pack->BuildSourceImagesArray(file_paths); - if (!pack->LoadRawBitmapsTo(file_paths, &pack->images_on_ui_thread_)) - return NULL; + if (!pack->LoadRawBitmapsTo(file_paths, &pack->images_)) + return; - pack->CreateImages(&pack->images_on_ui_thread_); + pack->CreateImages(&pack->images_); // Make sure the |images_on_file_thread_| has bitmaps for supported // scale factors before passing to FILE thread. - pack->images_on_file_thread_ = pack->images_on_ui_thread_; + pack->images_on_file_thread_ = pack->images_; for (ImageCache::iterator it = pack->images_on_file_thread_.begin(); it != pack->images_on_file_thread_.end(); ++it) { gfx::ImageSkia* image_skia = @@ -582,13 +582,13 @@ image_skia->MakeThreadSafe(); } - // Set ThemeImageSource on |images_on_ui_thread_| to resample the source + // Set ThemeImageSource on |images_| to resample the source // image if a caller of BrowserThemePack::GetImageNamed() requests an // ImageSkiaRep for a scale factor not specified by the theme author. // Callers of BrowserThemePack::GetImageNamed() to be able to retrieve // ImageSkiaReps for all supported scale factors. - for (ImageCache::iterator it = pack->images_on_ui_thread_.begin(); - it != pack->images_on_ui_thread_.end(); ++it) { + for (ImageCache::iterator it = pack->images_.begin(); + it != pack->images_.end(); ++it) { const gfx::ImageSkia source_image_skia = it->second.AsImageSkia(); ThemeImageSource* source = new ThemeImageSource(source_image_skia); // image_skia takes ownership of source. @@ -603,7 +603,7 @@ } // The BrowserThemePack is now in a consistent state. - return pack; + pack->is_valid_ = true; } // static @@ -671,6 +671,7 @@ << "from those supported by platform."; return NULL; } + pack->is_valid_ = true; return pack; } @@ -683,6 +684,13 @@ return false; } +BrowserThemePack::BrowserThemePack() : CustomThemeSupplier(EXTENSION) { + scale_factors_ = ui::GetSupportedScaleFactors(); + // On Windows HiDPI SCALE_FACTOR_100P may not be supported by default. + if (!base::ContainsValue(scale_factors_, ui::SCALE_FACTOR_100P)) + scale_factors_.push_back(ui::SCALE_FACTOR_100P); +} + bool BrowserThemePack::WriteToDisk(const base::FilePath& path) const { // Add resources for each of the property arrays. RawDataForWriting resources; @@ -771,8 +779,8 @@ return gfx::Image(); // Check if the image is cached. - ImageCache::const_iterator image_iter = images_on_ui_thread_.find(prs_id); - if (image_iter != images_on_ui_thread_.end()) + ImageCache::const_iterator image_iter = images_.find(prs_id); + if (image_iter != images_.end()) return image_iter->second; ThemeImagePngSource::PngMap png_map; @@ -786,7 +794,7 @@ gfx::ImageSkia image_skia(new ThemeImagePngSource(png_map), 1.0f); // |image_skia| takes ownership of ThemeImagePngSource. gfx::Image ret = gfx::Image(image_skia); - images_on_ui_thread_[prs_id] = ret; + images_[prs_id] = ret; return ret; } @@ -830,19 +838,6 @@ // private: -BrowserThemePack::BrowserThemePack() - : CustomThemeSupplier(EXTENSION), - header_(NULL), - tints_(NULL), - colors_(NULL), - display_properties_(NULL), - source_images_(NULL) { - scale_factors_ = ui::GetSupportedScaleFactors(); - // On Windows HiDPI SCALE_FACTOR_100P may not be supported by default. - if (!base::ContainsValue(scale_factors_, ui::SCALE_FACTOR_100P)) - scale_factors_.push_back(ui::SCALE_FACTOR_100P); -} - void BrowserThemePack::BuildHeader(const Extension* extension) { header_ = new BrowserThemePackHeader; header_->version = kThemePackVersion;
diff --git a/chrome/browser/themes/browser_theme_pack.h b/chrome/browser/themes/browser_theme_pack.h index cc975cc..d527e973 100644 --- a/chrome/browser/themes/browser_theme_pack.h +++ b/chrome/browser/themes/browser_theme_pack.h
@@ -53,11 +53,11 @@ // will trip our IO on the UI thread detector. class BrowserThemePack : public CustomThemeSupplier { public: - // Builds the theme pack from all data from |extension|. This is often done - // on a separate thread as it takes so long. This can fail and return NULL in - // the case where the theme has invalid data. - static scoped_refptr<BrowserThemePack> BuildFromExtension( - const extensions::Extension* extension); + // Builds the theme from |extension| into |pack|. This may be done on a + // separate thread as it takes so long. This can fail in the case where the + // theme has invalid data, in which case |pack->is_valid()| will be false. + static void BuildFromExtension(const extensions::Extension* extension, + scoped_refptr<BrowserThemePack> pack); // Builds the theme pack from a previously performed WriteToDisk(). This // operation should be relatively fast, as it should be an mmap() and some @@ -69,6 +69,11 @@ // in the data pack. static bool IsPersistentImageID(int id); + // Default. Everything is empty. + BrowserThemePack(); + + bool is_valid() const { return is_valid_; } + // Builds a data pack on disk at |path| for future quick loading by // BuildFromDataPack(). Often (but not always) called from the file thread; // implementation should be threadsafe because neither thread will write to @@ -103,9 +108,6 @@ // Maps image ids to maps of scale factors to file paths. typedef std::map<int, ScaleFactorToFileMap> FilePathMap; - // Default. Everything is empty. - BrowserThemePack(); - ~BrowserThemePack() override; // Builds a header ready to write to disk. @@ -217,7 +219,7 @@ // theme_id without NULL terminator. uint8_t theme_id[16]; - } *header_; + }* header_ = nullptr; // The remaining structs represent individual entries in an array. For the // following three structs, BrowserThemePack will either allocate an array or @@ -227,21 +229,21 @@ double h; double s; double l; - } *tints_; + }* tints_ = nullptr; struct ColorPair { int32_t id; SkColor color; - } *colors_; + }* colors_ = nullptr; struct DisplayPropertyPair { int32_t id; int32_t property; - } *display_properties_; + }* display_properties_ = nullptr; // A list of included source images. A pointer to a -1 terminated array of // our persistent IDs. - int* source_images_; + int* source_images_ = nullptr; #pragma pack(pop) // The scale factors represented by the images in the theme pack. @@ -254,9 +256,8 @@ RawImages image_memory_; // Loaded images. These are loaded from |image_memory_|, from |data_pack_|, - // and by BuildFromExtension(). These images should only be accessed on the UI - // thread. - ImageCache images_on_ui_thread_; + // and by BuildFromExtension(). + ImageCache images_; // Cache of images created in BuildFromExtension(). Once the theme pack is // created, this cache should only be accessed on the file thread. There @@ -264,6 +265,10 @@ // or vice versa. ImageCache images_on_file_thread_; + // Whether the theme pack has been succesfully initialized and is ready to + // use. + bool is_valid_ = false; + DISALLOW_COPY_AND_ASSIGN(BrowserThemePack); };
diff --git a/chrome/browser/themes/browser_theme_pack_unittest.cc b/chrome/browser/themes/browser_theme_pack_unittest.cc index 1180081..22e9d2f 100644 --- a/chrome/browser/themes/browser_theme_pack_unittest.cc +++ b/chrome/browser/themes/browser_theme_pack_unittest.cc
@@ -10,6 +10,7 @@ #include "base/json/json_file_value_serializer.h" #include "base/json/json_reader.h" #include "base/path_service.h" +#include "base/synchronization/waitable_event.h" #include "base/values.h" #include "build/build_config.h" #include "chrome/browser/themes/theme_properties.h" @@ -34,14 +35,16 @@ class BrowserThemePackTest : public ::testing::Test { public: - BrowserThemePackTest() { + BrowserThemePackTest() + : thread_bundle_(content::TestBrowserThreadBundle::REAL_IO_THREAD), + theme_pack_(new BrowserThemePack()) { std::vector<ui::ScaleFactor> scale_factors; scale_factors.push_back(ui::SCALE_FACTOR_100P); scale_factors.push_back(ui::SCALE_FACTOR_200P); scoped_set_supported_scale_factors_.reset( - new ui::test::ScopedSetSupportedScaleFactors(scale_factors)); - theme_pack_ = new BrowserThemePack(); + new ui::test::ScopedSetSupportedScaleFactors(scale_factors)); } + ~BrowserThemePackTest() override {} // Transformation for link underline colors. SkColor BuildThirdOpacity(SkColor color_link) { @@ -142,33 +145,22 @@ } bool LoadRawBitmapsTo(const TestFilePathMap& out_file_paths) { - return theme_pack_->LoadRawBitmapsTo(out_file_paths, - &theme_pack_->images_on_ui_thread_); + return theme_pack_->LoadRawBitmapsTo(out_file_paths, &theme_pack_->images_); } // This function returns void in order to be able use ASSERT_... // The BrowserThemePack is returned in |pack|. void BuildFromUnpackedExtension(const base::FilePath& extension_path, - scoped_refptr<BrowserThemePack>& pack) { - base::FilePath manifest_path = - extension_path.AppendASCII("manifest.json"); - std::string error; - JSONFileValueDeserializer deserializer(manifest_path); - std::unique_ptr<base::DictionaryValue> valid_value = - base::DictionaryValue::From(deserializer.Deserialize(NULL, &error)); - EXPECT_EQ("", error); - ASSERT_TRUE(valid_value.get()); - scoped_refptr<Extension> extension( - Extension::Create( - extension_path, - extensions::Manifest::INVALID_LOCATION, - *valid_value, - Extension::REQUIRE_KEY, - &error)); - ASSERT_TRUE(extension.get()); - ASSERT_EQ("", error); - pack = BrowserThemePack::BuildFromExtension(extension.get()); - ASSERT_TRUE(pack.get()); + scoped_refptr<BrowserThemePack>* pack) { + io_waiter_.reset(new base::WaitableEvent( + base::WaitableEvent::ResetPolicy::AUTOMATIC, + base::WaitableEvent::InitialState::NOT_SIGNALED)); + content::BrowserThread::PostTask( + content::BrowserThread::IO, FROM_HERE, + base::Bind(&BrowserThemePackTest::DoBuildFromUnpackedExtension, + base::Unretained(this), extension_path, pack)); + io_waiter_->Wait(); + ASSERT_TRUE((*pack)->is_valid()); } base::FilePath GetStarGazingPath() { @@ -347,12 +339,33 @@ } } - content::TestBrowserThreadBundle test_browser_thread_bundle_; - + protected: typedef std::unique_ptr<ui::test::ScopedSetSupportedScaleFactors> ScopedSetSupportedScaleFactors; ScopedSetSupportedScaleFactors scoped_set_supported_scale_factors_; + + void DoBuildFromUnpackedExtension(const base::FilePath& extension_path, + scoped_refptr<BrowserThemePack>* pack) { + base::FilePath manifest_path = extension_path.AppendASCII("manifest.json"); + std::string error; + JSONFileValueDeserializer deserializer(manifest_path); + std::unique_ptr<base::DictionaryValue> valid_value = + base::DictionaryValue::From(deserializer.Deserialize(NULL, &error)); + EXPECT_EQ("", error); + ASSERT_TRUE(valid_value.get()); + scoped_refptr<Extension> extension(Extension::Create( + extension_path, extensions::Manifest::INVALID_LOCATION, *valid_value, + Extension::REQUIRE_KEY, &error)); + ASSERT_TRUE(extension.get()); + ASSERT_EQ("", error); + *pack = new BrowserThemePack; + BrowserThemePack::BuildFromExtension(extension.get(), *pack); + io_waiter_->Signal(); + } + + content::TestBrowserThreadBundle thread_bundle_; scoped_refptr<BrowserThemePack> theme_pack_; + std::unique_ptr<base::WaitableEvent> io_waiter_; }; // 'ntp_section' used to correspond to ThemeProperties::COLOR_NTP_SECTION, @@ -569,7 +582,7 @@ { base::FilePath star_gazing_path = GetStarGazingPath(); scoped_refptr<BrowserThemePack> pack; - BuildFromUnpackedExtension(star_gazing_path, pack); + BuildFromUnpackedExtension(star_gazing_path, &pack); ASSERT_TRUE(pack->WriteToDisk(file)); VerifyStarGazing(pack.get()); } @@ -593,7 +606,7 @@ { base::FilePath hidpi_path = GetHiDpiThemePath(); scoped_refptr<BrowserThemePack> pack; - BuildFromUnpackedExtension(hidpi_path, pack); + BuildFromUnpackedExtension(hidpi_path, &pack); ASSERT_TRUE(pack->WriteToDisk(file)); VerifyHiDpiTheme(pack.get()); }
diff --git a/chrome/browser/themes/theme_service.cc b/chrome/browser/themes/theme_service.cc index 6a9d0e1..34cd105 100644 --- a/chrome/browser/themes/theme_service.cc +++ b/chrome/browser/themes/theme_service.cc
@@ -17,10 +17,12 @@ #include "base/single_thread_task_runner.h" #include "base/strings/string_util.h" #include "base/strings/utf_string_conversions.h" +#include "base/task_scheduler/post_task.h" #include "base/threading/thread_task_runner_handle.h" #include "build/build_config.h" #include "chrome/browser/chrome_notification_types.h" #include "chrome/browser/extensions/extension_service.h" +#include "chrome/browser/extensions/theme_installed_infobar_delegate.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/themes/browser_theme_pack.h" #include "chrome/browser/themes/custom_theme_supplier.h" @@ -262,7 +264,7 @@ case extensions::NOTIFICATION_EXTENSION_ENABLED: { const Extension* extension = Details<const Extension>(details).ptr(); if (extension->is_theme()) - SetTheme(extension); + DoSetTheme(extension, true); break; } default: @@ -271,40 +273,18 @@ } void ThemeService::SetTheme(const Extension* extension) { + DoSetTheme(extension, false); +} + +void ThemeService::RevertToTheme(const Extension* extension) { DCHECK(extension->is_theme()); ExtensionService* service = extensions::ExtensionSystem::Get(profile_)->extension_service(); - if (!service->IsExtensionEnabled(extension->id())) { - // |extension| is disabled when reverting to the previous theme via an - // infobar. - service->EnableExtension(extension->id()); - // Enabling the extension will call back to SetTheme(). - return; - } - - std::string previous_theme_id = GetThemeID(); - - // Clear our image cache. - FreePlatformCaches(); - - BuildFromExtension(extension); - SaveThemeID(extension->id()); - - NotifyThemeChanged(); - base::RecordAction(UserMetricsAction("Themes_Installed")); - - if (previous_theme_id != kDefaultThemeID && - previous_theme_id != extension->id() && - service->GetInstalledExtension(previous_theme_id)) { - // Do not disable the previous theme if it is already uninstalled. Sending - // NOTIFICATION_BROWSER_THEME_CHANGED causes the previous theme to be - // uninstalled when the notification causes the remaining infobar to close - // and does not open any new infobars. See crbug.com/468280. - - // Disable the old theme. - service->DisableExtension(previous_theme_id, - extensions::Extension::DISABLE_USER_ACTION); - } + DCHECK(!service->IsExtensionEnabled(extension->id())); + // |extension| is disabled when reverting to the previous theme via an + // infobar. + service->EnableExtension(extension->id()); + // Enabling the extension will call back to SetTheme(). } void ThemeService::UseDefaultTheme() { @@ -349,8 +329,10 @@ void ThemeService::OnInfobarDestroyed() { number_of_infobars_--; - if (number_of_infobars_ == 0) + if (number_of_infobars_ == 0 && + !build_extension_task_tracker_.HasTrackedTasks()) { RemoveUnusedThemes(false); + } } void ThemeService::RemoveUnusedThemes(bool ignore_infobars) { @@ -375,8 +357,8 @@ for (extensions::ExtensionSet::const_iterator it = extensions->begin(); it != extensions->end(); ++it) { const extensions::Extension* extension = it->get(); - if (extension->is_theme() && - extension->id() != current_theme) { + if (extension->is_theme() && extension->id() != current_theme && + extension->id() != building_extension_id_) { // Only uninstall themes which are not disabled or are disabled with // reason DISABLE_USER_ACTION. We cannot blanket uninstall all disabled // themes because externally installed themes are initially disabled. @@ -578,7 +560,7 @@ // If we don't have a file pack, we're updating from an old version. base::FilePath path = prefs->GetFilePath(prefs::kCurrentThemePackFilename); - if (path != base::FilePath()) { + if (!path.empty()) { path = path.Append(chrome::kThemePackFilename); SwapThemeSupplier(BrowserThemePack::BuildFromDataPack(path, current_id)); if (theme_supplier_) @@ -685,6 +667,15 @@ return SkColorSetA(separator_color, alpha); } +void ThemeService::DoSetTheme(const Extension* extension, + bool suppress_infobar) { + DCHECK(extension->is_theme()); + DCHECK(extensions::ExtensionSystem::Get(profile_) + ->extension_service() + ->IsExtensionEnabled(extension->id())); + BuildFromExtension(extension, suppress_infobar); +} + gfx::ImageSkia* ThemeService::GetImageSkiaNamed(int id, bool incognito) const { gfx::Image image = GetImageNamed(id, incognito); if (image.IsEmpty()) @@ -785,10 +776,6 @@ // be recreated from the extension. MigrateTheme(); set_ready(); - - // Send notification in case anyone requested data and cached it when the - // theme service was not ready yet. - NotifyThemeChanged(); } #if BUILDFLAG(ENABLE_EXTENSIONS) @@ -806,15 +793,18 @@ } void ThemeService::MigrateTheme() { - // TODO(erg): We need to pop up a dialog informing the user that their - // theme is being migrated. ExtensionService* service = extensions::ExtensionSystem::Get(profile_)->extension_service(); const Extension* extension = service ? service->GetExtensionById(GetThemeID(), false) : nullptr; if (extension) { DLOG(ERROR) << "Migrating theme"; - BuildFromExtension(extension); + // Theme migration is done on the UI thread. Blocking the UI from appearing + // until it's ready is deemed better than showing a blip of the default + // theme. + scoped_refptr<BrowserThemePack> pack(new BrowserThemePack); + BrowserThemePack::BuildFromExtension(extension, pack); + OnThemeBuiltFromExtension(extension->id(), pack, true); base::RecordAction(UserMetricsAction("Themes.Migrated")); } else { DLOG(ERROR) << "Theme is mysteriously gone."; @@ -841,10 +831,26 @@ profile_->GetPrefs()->SetString(prefs::kCurrentThemeID, id); } -void ThemeService::BuildFromExtension(const Extension* extension) { - scoped_refptr<BrowserThemePack> pack( - BrowserThemePack::BuildFromExtension(extension)); - if (!pack.get()) { +void ThemeService::BuildFromExtension(const Extension* extension, + bool suppress_infobar) { + build_extension_task_tracker_.TryCancelAll(); + building_extension_id_ = extension->id(); + scoped_refptr<BrowserThemePack> pack(new BrowserThemePack); + auto task_runner = base::CreateTaskRunnerWithTraits( + {base::MayBlock(), base::TaskPriority::USER_BLOCKING}); + build_extension_task_tracker_.PostTaskAndReply( + task_runner.get(), FROM_HERE, + base::Bind(&BrowserThemePack::BuildFromExtension, extension, pack), + base::Bind(&ThemeService::OnThemeBuiltFromExtension, + weak_ptr_factory_.GetWeakPtr(), extension->id(), pack, + suppress_infobar)); +} + +void ThemeService::OnThemeBuiltFromExtension( + const extensions::ExtensionId& extension_id, + scoped_refptr<BrowserThemePack> pack, + bool suppress_infobar) { + if (!pack->is_valid()) { // TODO(erg): We've failed to install the theme; perhaps we should tell the // user? http://crbug.com/34780 LOG(ERROR) << "Could not load theme."; @@ -855,16 +861,57 @@ extensions::ExtensionSystem::Get(profile_)->extension_service(); if (!service) return; + const Extension* extension = extensions::ExtensionRegistry::Get(profile_) + ->enabled_extensions() + .GetByID(extension_id); + if (!extension) + return; // Write the packed file to disk. service->GetFileTaskRunner()->PostTask( FROM_HERE, base::Bind(&WritePackToDiskCallback, base::RetainedRef(pack), extension->path())); + const std::string previous_theme_id = GetThemeID(); + const bool previous_using_system_theme = UsingSystemTheme(); + // Save only the extension path. The packed file will be loaded via // LoadThemePrefs(). SavePackName(extension->path()); SwapThemeSupplier(pack); + + // Clear our image cache. + FreePlatformCaches(); + SaveThemeID(extension->id()); + NotifyThemeChanged(); + + // Same old theme, but the theme has changed (migrated) or auto-updated. + if (previous_theme_id == extension->id()) + return; + + base::RecordAction(UserMetricsAction("Themes_Installed")); + + bool can_revert_theme = previous_theme_id == kDefaultThemeID; + if (previous_theme_id != kDefaultThemeID && + service->GetInstalledExtension(previous_theme_id)) { + // Do not disable the previous theme if it is already uninstalled. Sending + // NOTIFICATION_BROWSER_THEME_CHANGED causes the previous theme to be + // uninstalled when the notification causes the remaining infobar to close + // and does not open any new infobars. See crbug.com/468280. + + // Disable the old theme. + service->DisableExtension(previous_theme_id, + extensions::Extension::DISABLE_USER_ACTION); + + can_revert_theme = true; + } + + // Offer to revert to the old theme. + if (can_revert_theme && !suppress_infobar) { + ThemeInstalledInfoBarDelegate::Create( + extension, profile_, previous_theme_id, previous_using_system_theme); + } + building_extension_id_.clear(); } #if BUILDFLAG(ENABLE_SUPERVISED_USERS)
diff --git a/chrome/browser/themes/theme_service.h b/chrome/browser/themes/theme_service.h index 51c676c..c941a63 100644 --- a/chrome/browser/themes/theme_service.h +++ b/chrome/browser/themes/theme_service.h
@@ -16,14 +16,17 @@ #include "base/memory/ref_counted.h" #include "base/memory/weak_ptr.h" #include "base/sequence_checker.h" +#include "base/task/cancelable_task_tracker.h" #include "build/build_config.h" #include "chrome/common/features.h" #include "components/keyed_service/core/keyed_service.h" #include "content/public/browser/notification_observer.h" #include "content/public/browser/notification_registrar.h" +#include "extensions/common/extension_id.h" #include "extensions/features/features.h" #include "ui/base/theme_provider.h" +class BrowserThemePack; class CustomThemeSupplier; class ThemeSyncableService; class Profile; @@ -82,6 +85,9 @@ // ExtensionService. virtual void SetTheme(const extensions::Extension* extension); + // Similar to SetTheme, but doesn't show an undo infobar. + void RevertToTheme(const extensions::Extension* extension); + // Reset the theme to default. virtual void UseDefaultTheme(); @@ -230,6 +236,9 @@ // and contrasting with the foreground tab is the most important). static SkColor GetSeparatorColor(SkColor tab_color, SkColor frame_color); + void DoSetTheme(const extensions::Extension* extension, + bool suppress_infobar); + // These methods provide the implementation for ui::ThemeProvider (exposed // via BrowserThemeProvider). gfx::ImageSkia* GetImageSkiaNamed(int id, bool incognito) const; @@ -270,8 +279,15 @@ void SaveThemeID(const std::string& id); // Implementation of SetTheme() (and the fallback from LoadThemePrefs() in - // case we don't have a theme pack). - void BuildFromExtension(const extensions::Extension* extension); + // case we don't have a theme pack). |new_theme| indicates whether this is a + // newly installed theme or a migration. + void BuildFromExtension(const extensions::Extension* extension, + bool new_theme); + + // Callback when |pack| has finished or failed building. + void OnThemeBuiltFromExtension(const extensions::ExtensionId& extension_id, + scoped_refptr<BrowserThemePack> pack, + bool new_theme); #if BUILDFLAG(ENABLE_SUPERVISED_USERS) // Returns true if the profile belongs to a supervised user. @@ -328,6 +344,14 @@ SEQUENCE_CHECKER(sequence_checker_); + // Allows us to cancel building a theme pack from an extension. + base::CancelableTaskTracker build_extension_task_tracker_; + + // The ID of the theme that's currently being built on a different thread. + // We hold onto this just to be sure not to uninstall the extension view + // RemoveUnusedThemes while it's still being built. + std::string building_extension_id_; + base::WeakPtrFactory<ThemeService> weak_ptr_factory_; DISALLOW_COPY_AND_ASSIGN(ThemeService);
diff --git a/chrome/browser/themes/theme_service_browsertest.cc b/chrome/browser/themes/theme_service_browsertest.cc index 7ed17415..88de8b3 100644 --- a/chrome/browser/themes/theme_service_browsertest.cc +++ b/chrome/browser/themes/theme_service_browsertest.cc
@@ -7,6 +7,7 @@ #include "base/macros.h" #include "base/threading/sequenced_worker_pool.h" #include "base/threading/thread_restrictions.h" +#include "chrome/browser/chrome_notification_types.h" #include "chrome/browser/extensions/component_loader.h" #include "chrome/browser/extensions/extension_browsertest.h" #include "chrome/browser/profiles/profile.h" @@ -15,6 +16,7 @@ #include "chrome/browser/ui/browser.h" #include "chrome/common/pref_names.h" #include "components/prefs/pref_service.h" +#include "content/public/test/test_utils.h" namespace { @@ -58,7 +60,11 @@ EXPECT_EQ(base::FilePath(), profile->GetPrefs()->GetFilePath(prefs::kCurrentThemePackFilename)); + content::WindowedNotificationObserver theme_change_observer( + chrome::NOTIFICATION_BROWSER_THEME_CHANGED, + content::Source<ThemeService>(theme_service)); InstallExtension(test_data_dir_.AppendASCII("theme"), 1); + theme_change_observer.Wait(); // Check that the theme was installed. EXPECT_TRUE(UsingCustomTheme(*theme_service));
diff --git a/chrome/browser/themes/theme_service_unittest.cc b/chrome/browser/themes/theme_service_unittest.cc index 7f6807ee..83114e6 100644 --- a/chrome/browser/themes/theme_service_unittest.cc +++ b/chrome/browser/themes/theme_service_unittest.cc
@@ -10,6 +10,7 @@ #include "base/path_service.h" #include "base/run_loop.h" #include "base/strings/stringprintf.h" +#include "base/test/scoped_task_environment.h" #include "build/build_config.h" #include "chrome/browser/chrome_notification_types.h" #include "chrome/browser/extensions/extension_service.h" @@ -77,8 +78,7 @@ installer->Load(temp_dir); std::string extension_id = observer.WaitForExtensionLoaded()->id(); - // Let the ThemeService finish creating the theme pack. - base::RunLoop().RunUntilIdle(); + WaitForThemeInstall(); return extension_id; } @@ -111,6 +111,14 @@ return theme_service->get_theme_supplier(); } + void WaitForThemeInstall() { + content::WindowedNotificationObserver theme_change_observer( + chrome::NOTIFICATION_BROWSER_THEME_CHANGED, + content::Source<ThemeService>( + ThemeServiceFactory::GetForProfile(profile()))); + theme_change_observer.Wait(); + } + // Alpha blends a non-opaque foreground color against an opaque background. // This is not the same as color_utils::AlphaBlend() since it gets the opacity // from the foreground color and then does not blend the two colors' alpha @@ -163,8 +171,6 @@ ThemeService* theme_service = ThemeServiceFactory::GetForProfile(profile_.get()); theme_service->UseDefaultTheme(); - // Let the ThemeService uninstall unused themes. - base::RunLoop().RunUntilIdle(); base::ScopedTempDir temp_dir1; ASSERT_TRUE(temp_dir1.CreateUniqueTempDir()); @@ -188,19 +194,19 @@ // 2) Enabling a disabled theme extension should swap the current theme. service_->EnableExtension(extension1_id); - base::RunLoop().RunUntilIdle(); + WaitForThemeInstall(); EXPECT_EQ(extension1_id, theme_service->GetThemeID()); EXPECT_TRUE(service_->IsExtensionEnabled(extension1_id)); EXPECT_TRUE(registry_->GetExtensionById(extension2_id, ExtensionRegistry::DISABLED)); - // 3) Using SetTheme() with a disabled theme should enable and set the + // 3) Using RevertToTheme() with a disabled theme should enable and set the // theme. This is the case when the user reverts to the previous theme // via an infobar. const extensions::Extension* extension2 = service_->GetInstalledExtension(extension2_id); - theme_service->SetTheme(extension2); - base::RunLoop().RunUntilIdle(); + theme_service->RevertToTheme(extension2); + WaitForThemeInstall(); EXPECT_EQ(extension2_id, theme_service->GetThemeID()); EXPECT_TRUE(service_->IsExtensionEnabled(extension2_id)); EXPECT_TRUE(registry_->GetExtensionById(extension1_id, @@ -340,18 +346,21 @@ // Show an infobar. theme_service->OnInfobarDisplayed(); - // Install another theme. Emulate the infobar destroying itself (and - // causing unused themes to be uninstalled) as a result of the - // NOTIFICATION_BROWSER_THEME_CHANGED notification. + // Install another theme. The first extension shouldn't be uninstalled yet as + // it should be possible to revert to it. Emulate the infobar destroying + // itself as a result of the NOTIFICATION_BROWSER_THEME_CHANGED notification. { InfobarDestroyerOnThemeChange destroyer(profile_.get()); const std::string& extension2_id = LoadUnpackedThemeAt(temp_dir2.GetPath()); - ASSERT_EQ(extension2_id, theme_service->GetThemeID()); - ASSERT_FALSE(service_->GetInstalledExtension(extension1_id)); + EXPECT_EQ(extension2_id, theme_service->GetThemeID()); } + auto* extension1 = service_->GetInstalledExtension(extension1_id); + ASSERT_TRUE(extension1); + // Check that it is possible to reinstall extension1. - ASSERT_EQ(extension1_id, LoadUnpackedThemeAt(temp_dir1.GetPath())); + ThemeServiceFactory::GetForProfile(profile_.get())->RevertToTheme(extension1); + WaitForThemeInstall(); EXPECT_EQ(extension1_id, theme_service->GetThemeID()); }
diff --git a/chrome/browser/ui/BUILD.gn b/chrome/browser/ui/BUILD.gn index 630148f..374719ef 100644 --- a/chrome/browser/ui/BUILD.gn +++ b/chrome/browser/ui/BUILD.gn
@@ -1438,6 +1438,10 @@ "autofill/save_card_bubble_controller_impl.h", "autofill/save_card_bubble_view.h", "desktop_ios_promotion/desktop_ios_promotion_footnote_delegate.h", + + # This test header is included because it contains forward declarations + # needed for "friend" statements for use in tests. + "translate/translate_bubble_test_utils.h", "views/apps/app_info_dialog/app_info_dialog_container.cc", "views/apps/app_info_dialog/app_info_dialog_container.h", "views/apps/app_info_dialog/app_info_dialog_views.cc", @@ -1596,6 +1600,8 @@ "views/task_manager_view.h", "views/toolbar/toolbar_actions_bar_bubble_views.cc", "views/toolbar/toolbar_actions_bar_bubble_views.h", + "views/translate/translate_bubble_view.cc", + "views/translate/translate_bubble_view.h", "views/update_recommended_message_box.cc", "views/update_recommended_message_box.h", ] @@ -1687,10 +1693,6 @@ if (!is_mac || mac_views_browser) { sources += [ "javascript_dialogs/javascript_dialog.cc", - - # This test header is included because it contains forward declarations - # needed for "friend" statements for use in tests. - "translate/translate_bubble_test_utils.h", "views/accessibility/invert_bubble_view.cc", "views/accessibility/invert_bubble_view.h", "views/autofill/autofill_popup_base_view.cc", @@ -1917,8 +1919,6 @@ "views/toolbar/toolbar_view.cc", "views/toolbar/toolbar_view.h", "views/touch_uma/touch_uma.h", - "views/translate/translate_bubble_view.cc", - "views/translate/translate_bubble_view.h", "views/translate/translate_icon_view.cc", "views/translate/translate_icon_view.h", "views/validation_message_bubble_view.cc", @@ -3031,6 +3031,8 @@ "cocoa/toolbar/toolbar_controller.mm", "cocoa/toolbar/toolbar_view_cocoa.h", "cocoa/toolbar/toolbar_view_cocoa.mm", + "cocoa/translate/translate_bubble_bridge_views.h", + "cocoa/translate/translate_bubble_bridge_views.mm", "cocoa/translate/translate_bubble_controller.h", "cocoa/translate/translate_bubble_controller.mm", "cocoa/url_drop_target.h", @@ -3113,6 +3115,8 @@ "webui/cleanup_tool/cleanup_action_handler.h", "webui/cleanup_tool/cleanup_tool_ui.cc", "webui/cleanup_tool/cleanup_tool_ui.h", + "webui/conflicts_handler.cc", + "webui/conflicts_handler.h", "webui/conflicts_ui.cc", "webui/conflicts_ui.h", "webui/welcome_win10_handler.cc",
diff --git a/chrome/browser/ui/app_list/app_list_view_delegate.cc b/chrome/browser/ui/app_list/app_list_view_delegate.cc index 27db6fd..aae349ce 100644 --- a/chrome/browser/ui/app_list/app_list_view_delegate.cc +++ b/chrome/browser/ui/app_list/app_list_view_delegate.cc
@@ -24,7 +24,6 @@ #include "chrome/browser/ui/app_list/launcher_page_event_dispatcher.h" #include "chrome/browser/ui/app_list/search/search_controller_factory.h" #include "chrome/browser/ui/app_list/search/search_resource_manager.h" -#include "chrome/browser/ui/app_list/search_answer_web_contents_delegate.h" #include "chrome/browser/ui/app_list/start_page_service.h" #include "chrome/browser/ui/apps/chrome_app_delegate.h" #include "chrome/browser/ui/ash/app_list/app_sync_ui_state_watcher.h" @@ -154,7 +153,6 @@ start_page_service->RemoveObserver(this); app_sync_ui_state_watcher_.reset(); model_ = NULL; - search_answer_delegate_.reset(); } template_url_service_observer_.RemoveAll(); @@ -188,10 +186,6 @@ app_sync_ui_state_watcher_.reset( new AppSyncUIStateWatcher(profile_, model_)); - search_answer_delegate_ = - base::MakeUnique<app_list::SearchAnswerWebContentsDelegate>(profile_, - model_); - SetUpSearchUI(); SetUpCustomLauncherPages(); OnTemplateURLServiceChanged(); @@ -279,8 +273,6 @@ search_controller_->Start(); controller_->OnSearchStarted(); } - if (search_answer_delegate_) - search_answer_delegate_->Update(); } void AppListViewDelegate::StopSearch() { @@ -495,10 +487,6 @@ return web_views; } -views::View* AppListViewDelegate::GetSearchAnswerWebView() { - return search_answer_delegate_->web_view(); -} - void AppListViewDelegate::CustomLauncherPageAnimationChanged(double progress) { if (launcher_page_event_dispatcher_) launcher_page_event_dispatcher_->ProgressChanged(progress);
diff --git a/chrome/browser/ui/app_list/app_list_view_delegate.h b/chrome/browser/ui/app_list/app_list_view_delegate.h index 923bf6b..0a5d7540 100644 --- a/chrome/browser/ui/app_list/app_list_view_delegate.h +++ b/chrome/browser/ui/app_list/app_list_view_delegate.h
@@ -26,7 +26,6 @@ namespace app_list { class CustomLauncherPageContents; class LauncherPageEventDispatcher; -class SearchAnswerWebContentsDelegate; class SearchController; class SearchResourceManager; class SpeechUIModel; @@ -80,7 +79,6 @@ views::View* CreateStartPageWebView(const gfx::Size& size) override; std::vector<views::View*> CreateCustomPageWebViews( const gfx::Size& size) override; - views::View* GetSearchAnswerWebView() override; void CustomLauncherPageAnimationChanged(double progress) override; void CustomLauncherPagePopSubpage() override; bool IsSpeechRecognitionEnabled() override; @@ -144,9 +142,6 @@ // Registers for NOTIFICATION_APP_TERMINATING to unload custom launcher pages. content::NotificationRegistrar registrar_; - std::unique_ptr<app_list::SearchAnswerWebContentsDelegate> - search_answer_delegate_; - DISALLOW_COPY_AND_ASSIGN(AppListViewDelegate); };
diff --git a/chrome/browser/ui/app_list/search/search_controller_factory.cc b/chrome/browser/ui/app_list/search/search_controller_factory.cc index 513a989..911b8dba 100644 --- a/chrome/browser/ui/app_list/search/search_controller_factory.cc +++ b/chrome/browser/ui/app_list/search/search_controller_factory.cc
@@ -15,15 +15,17 @@ #include "chrome/browser/profiles/profile.h" #include "chrome/browser/ui/app_list/search/app_search_provider.h" #include "chrome/browser/ui/app_list/search/history_factory.h" +#include "chrome/browser/ui/app_list/search/launcher_search/launcher_search_provider.h" #include "chrome/browser/ui/app_list/search/omnibox_provider.h" #include "chrome/browser/ui/app_list/search/suggestions/suggestions_search_provider.h" #include "chrome/browser/ui/app_list/search/webstore/webstore_provider.h" +#include "chrome/browser/ui/app_list/search_answer_web_contents_delegate.h" #include "chrome/common/chrome_switches.h" +#include "ui/app_list/app_list_features.h" #include "ui/app_list/app_list_model.h" #include "ui/app_list/app_list_switches.h" #include "ui/app_list/search/mixer.h" #include "ui/app_list/search_controller.h" -#include "chrome/browser/ui/app_list/search/launcher_search/launcher_search_provider.h" namespace app_list { @@ -68,6 +70,9 @@ size_t apps_group_id = controller->AddGroup(kMaxAppsGroupResults, 1.0); size_t omnibox_group_id = controller->AddGroup(kMaxOmniboxResults, 1.0); size_t webstore_group_id = controller->AddGroup(kMaxWebstoreResults, 0.4); + // Multiplier 100 is used because the answer card is designed to be the most + // relevant result and must be on the top of the result list. + size_t answer_card_group_id = controller->AddGroup(1, 100.0); // Add search providers. controller->AddProvider( @@ -81,6 +86,11 @@ controller->AddProvider( webstore_group_id, base::MakeUnique<WebstoreProvider>(profile, list_controller)); + if (features::IsAnswerCardEnabled()) { + controller->AddProvider( + answer_card_group_id, + base::MakeUnique<SearchAnswerWebContentsDelegate>(profile, model)); + } if (IsSuggestionsSearchProviderEnabled()) { size_t suggestions_group_id = controller->AddGroup(kMaxSuggestionsResults, 1.0);
diff --git a/chrome/browser/ui/app_list/search_answer_web_contents_delegate.cc b/chrome/browser/ui/app_list/search_answer_web_contents_delegate.cc index 2246036a..47a56da 100644 --- a/chrome/browser/ui/app_list/search_answer_web_contents_delegate.cc +++ b/chrome/browser/ui/app_list/search_answer_web_contents_delegate.cc
@@ -21,6 +21,7 @@ #include "ui/app_list/app_list_features.h" #include "ui/app_list/app_list_model.h" #include "ui/app_list/search_box_model.h" +#include "ui/app_list/search_result.h" #include "ui/views/controls/webview/web_contents_set_background_color.h" #include "ui/views/controls/webview/webview.h" #include "ui/views/widget/widget.h" @@ -52,7 +53,7 @@ void VisibilityChanged(View* starting_from, bool is_visible) override { WebView::VisibilityChanged(starting_from, is_visible); - if (GetWidget()->IsVisible() && IsDrawn()) { + if (GetWidget() && GetWidget()->IsVisible() && IsDrawn()) { if (shown_time_.is_null()) shown_time_ = base::TimeTicks::Now(); } else { @@ -73,6 +74,34 @@ DISALLOW_COPY_AND_ASSIGN(SearchAnswerWebView); }; +class SearchAnswerResult : public SearchResult { + public: + SearchAnswerResult(Profile* profile, + const std::string& result_url, + views::View* web_view) + : profile_(profile) { + set_display_type(DISPLAY_CARD); + set_id(result_url); + set_relevance(1); + set_view(web_view); + } + + // SearchResult overrides: + std::unique_ptr<SearchResult> Duplicate() const override { + return base::MakeUnique<SearchAnswerResult>(profile_, id(), view()); + } + + void Open(int event_flags) override { + chrome::NavigateParams params(profile_, GURL(id()), + ui::PAGE_TRANSITION_GENERATED); + params.disposition = ui::DispositionFromEventFlags(event_flags); + chrome::Navigate(¶ms); + } + + private: + Profile* const profile_; +}; + } // namespace SearchAnswerWebContentsDelegate::SearchAnswerWebContentsDelegate( @@ -97,10 +126,6 @@ web_contents_->SetDelegate(this); web_view_->set_owned_by_client(); web_view_->SetWebContents(web_contents_.get()); - if (features::IsAnswerCardDarkRunEnabled()) - web_view_->SetFocusBehavior(views::View::FocusBehavior::NEVER); - - model->AddObserver(this); // Make the webview transparent since it's going to be shown on top of a // highlightable button. @@ -110,25 +135,22 @@ SearchAnswerWebContentsDelegate::~SearchAnswerWebContentsDelegate() { RecordReceivedAnswerFinalResult(); - model_->RemoveObserver(this); } views::View* SearchAnswerWebContentsDelegate::web_view() { return web_view_.get(); } -void SearchAnswerWebContentsDelegate::Update() { - if (!answer_server_url_.is_valid()) - return; - +void SearchAnswerWebContentsDelegate::Start(bool is_voice_query, + const base::string16& query) { RecordReceivedAnswerFinalResult(); // Reset the state. received_answer_ = false; - model_->SetSearchAnswerAvailable(false); + OnResultAvailable(false); current_request_url_ = GURL(); server_request_start_time_ = answer_loaded_time_ = base::TimeTicks(); - if (model_->search_box()->is_voice_query()) { + if (is_voice_query) { // No need to send a server request and show a card because launcher // automatically closes upon voice queries. return; @@ -137,12 +159,11 @@ if (!model_->search_engine_is_google()) return; - // Start a request to the answer server. - base::string16 query; - base::TrimWhitespace(model_->search_box()->text(), base::TRIM_ALL, &query); if (query.empty()) return; + // Start a request to the answer server. + // Lifetime of |prefixed_query| should be longer than the one of // |replacements|. base::string16 prefixed_query(base::UTF8ToUTF16("q=") + query); @@ -164,8 +185,8 @@ void SearchAnswerWebContentsDelegate::UpdatePreferredSize( content::WebContents* web_contents, const gfx::Size& pref_size) { - model_->SetSearchAnswerAvailable(received_answer_ && IsCardSizeOk() && - !web_contents_->IsLoading()); + OnResultAvailable(received_answer_ && IsCardSizeOk() && + !web_contents_->IsLoading()); web_view_->SetPreferredSize(pref_size); if (!answer_loaded_time_.is_null()) { UMA_HISTOGRAM_TIMES("SearchAnswer.ResizeAfterLoadTime", @@ -223,10 +244,7 @@ } if (!features::IsAnswerCardDarkRunEnabled()) { - const net::HttpResponseHeaders* headers = - navigation_handle->GetResponseHeaders(); - if (!headers || headers->response_code() != net::HTTP_OK || - !headers->HasHeaderValue("has_answer", "true")) { + if (!ParseResponseHeaders(navigation_handle->GetResponseHeaders())) { RecordRequestResult(SearchAnswerRequestResult::REQUEST_RESULT_NO_ANSWER); return; } @@ -235,6 +253,8 @@ dark_run_received_answer_ = !dark_run_received_answer_; if (!dark_run_received_answer_) return; + // SearchResult requires a non-empty id. This "url" will never be opened. + result_url_ = "some string"; } received_answer_ = true; @@ -247,7 +267,7 @@ return; if (IsCardSizeOk()) - model_->SetSearchAnswerAvailable(true); + OnResultAvailable(true); answer_loaded_time_ = base::TimeTicks::Now(); UMA_HISTOGRAM_TIMES("SearchAnswer.LoadingTime", answer_loaded_time_ - server_request_start_time_); @@ -259,11 +279,6 @@ base::RecordAction(base::UserMetricsAction("SearchAnswer_UserInteraction")); } -void SearchAnswerWebContentsDelegate::OnSearchEngineIsGoogleChanged( - bool is_google) { - Update(); -} - bool SearchAnswerWebContentsDelegate::IsCardSizeOk() const { if (features::IsAnswerCardDarkRunEnabled()) return true; @@ -287,4 +302,25 @@ REQUEST_RESULT_RECEIVED_ANSWER_TOO_LARGE); } +void SearchAnswerWebContentsDelegate::OnResultAvailable(bool is_available) { + SearchProvider::Results results; + if (is_available) { + results.reserve(1); + results.emplace_back(base::MakeUnique<SearchAnswerResult>( + profile_, result_url_, web_view_.get())); + } + SwapResults(&results); +} + +bool SearchAnswerWebContentsDelegate::ParseResponseHeaders( + const net::HttpResponseHeaders* headers) { + if (!headers || headers->response_code() != net::HTTP_OK) + return false; + if (!headers->HasHeaderValue("SearchAnswer-HasResult", "true")) + return false; + if (!headers->GetNormalizedHeader("SearchAnswer-OpenResultUrl", &result_url_)) + return false; + return true; +} + } // namespace app_list
diff --git a/chrome/browser/ui/app_list/search_answer_web_contents_delegate.h b/chrome/browser/ui/app_list/search_answer_web_contents_delegate.h index b56c8531..ebbe661 100644 --- a/chrome/browser/ui/app_list/search_answer_web_contents_delegate.h +++ b/chrome/browser/ui/app_list/search_answer_web_contents_delegate.h
@@ -11,7 +11,7 @@ #include "base/time/time.h" #include "content/public/browser/web_contents_delegate.h" #include "content/public/browser/web_contents_observer.h" -#include "ui/app_list/app_list_model_observer.h" +#include "ui/app_list/search_provider.h" #include "url/gurl.h" class Profile; @@ -20,6 +20,10 @@ class AppListModel; } +namespace net { +class HttpResponseHeaders; +} + namespace views { class View; class WebView; @@ -27,25 +31,25 @@ namespace app_list { -// Manages the web contents for the search answer web view. -class SearchAnswerWebContentsDelegate : public content::WebContentsDelegate, - public content::WebContentsObserver, - public AppListModelObserver { +// Search provider for the answer card. +class SearchAnswerWebContentsDelegate : public SearchProvider, + public content::WebContentsDelegate, + public content::WebContentsObserver { public: SearchAnswerWebContentsDelegate(Profile* profile, app_list::AppListModel* model); ~SearchAnswerWebContentsDelegate() override; - // Updates the state after the query string or any other relevant condition - // changes. - void Update(); - // Returns a pointer to the web view for the web contents managed by this // class. The object is owned by this class and has property // 'set_owned_by_client()' set. views::View* web_view(); + // SearchProvider overrides: + void Start(bool is_voice_query, const base::string16& query) override; + void Stop() override {} + // content::WebContentsDelegate overrides: void UpdatePreferredSize(content::WebContents* web_contents, const gfx::Size& pref_size) override; @@ -62,12 +66,11 @@ void DidStopLoading() override; void DidGetUserInteraction(const blink::WebInputEvent::Type type) override; - // AppListModelObserver overrides: - void OnSearchEngineIsGoogleChanged(bool is_google) override; - private: bool IsCardSizeOk() const; void RecordReceivedAnswerFinalResult(); + void OnResultAvailable(bool is_available); + bool ParseResponseHeaders(const net::HttpResponseHeaders* headers); // Unowned pointer to the associated profile. Profile* const profile_; @@ -101,6 +104,9 @@ // response contains an answer. bool dark_run_received_answer_ = false; + // Url to open when the user clicks at the result. + std::string result_url_; + DISALLOW_COPY_AND_ASSIGN(SearchAnswerWebContentsDelegate); };
diff --git a/chrome/browser/ui/apps/chrome_app_delegate.cc b/chrome/browser/ui/apps/chrome_app_delegate.cc index 2111f5e..619d53c 100644 --- a/chrome/browser/ui/apps/chrome_app_delegate.cc +++ b/chrome/browser/ui/apps/chrome_app_delegate.cc
@@ -294,7 +294,7 @@ web_contents, security_origin, type, extension); } -int ChromeAppDelegate::PreferredIconSize() { +int ChromeAppDelegate::PreferredIconSize() const { #if defined(USE_ASH) return ash::kShelfSize; #else
diff --git a/chrome/browser/ui/apps/chrome_app_delegate.h b/chrome/browser/ui/apps/chrome_app_delegate.h index 3d687f4..31ec3de 100644 --- a/chrome/browser/ui/apps/chrome_app_delegate.h +++ b/chrome/browser/ui/apps/chrome_app_delegate.h
@@ -63,7 +63,7 @@ const GURL& security_origin, content::MediaStreamType type, const extensions::Extension* extension) override; - int PreferredIconSize() override; + int PreferredIconSize() const override; void SetWebContentsBlocked(content::WebContents* web_contents, bool blocked) override; bool IsWebContentsVisible(content::WebContents* web_contents) override;
diff --git a/chrome/browser/ui/ash/launcher/app_window_launcher_item_controller.cc b/chrome/browser/ui/ash/launcher/app_window_launcher_item_controller.cc index 41d5953..e5a924c6 100644 --- a/chrome/browser/ui/ash/launcher/app_window_launcher_item_controller.cc +++ b/chrome/browser/ui/ash/launcher/app_window_launcher_item_controller.cc
@@ -27,7 +27,7 @@ aura::Window* window = app_window->GetNativeWindow(); if (window) observed_windows_.Add(window); - UpdateLauncherItem(); + UpdateShelfItemIcon(); } AppWindowLauncherItemController::WindowList::iterator @@ -51,7 +51,7 @@ return; } windows_.erase(iter); - UpdateLauncherItem(); + UpdateShelfItemIcon(); } ui::BaseWindow* AppWindowLauncherItemController::GetAppWindow( @@ -66,7 +66,7 @@ ui::BaseWindow* app_window = GetAppWindow(window); if (app_window) last_active_window_ = app_window; - UpdateLauncherItem(); + UpdateShelfItemIcon(); } AppWindowLauncherItemController* @@ -143,6 +143,8 @@ status = ash::STATUS_RUNNING; } ChromeLauncherController::instance()->SetItemStatus(shelf_id(), status); + } else if (key == aura::client::kAppIconKey) { + UpdateShelfItemIcon(); } } @@ -174,3 +176,25 @@ } return ash::SHELF_ACTION_NONE; } + +void AppWindowLauncherItemController::UpdateShelfItemIcon() { + // Set the shelf item icon from the kAppIconKey property of the current + // (or most recently) active window. If there is no valid icon, ask + // ChromeLauncherController to update the icon. + const gfx::ImageSkia* app_icon = nullptr; + ui::BaseWindow* last_active_window = GetLastActiveWindow(); + if (last_active_window && last_active_window->GetNativeWindow()) { + app_icon = last_active_window->GetNativeWindow()->GetProperty( + aura::client::kAppIconKey); + } + // TODO(khmel): Remove using image_set_by_controller + if (app_icon && !app_icon->isNull()) { + set_image_set_by_controller(true); + ChromeLauncherController::instance()->SetLauncherItemImage(shelf_id(), + *app_icon); + } else if (image_set_by_controller()) { + set_image_set_by_controller(false); + ChromeLauncherController::instance()->UpdateLauncherItemImage( + shelf_id().app_id); + } +}
diff --git a/chrome/browser/ui/ash/launcher/app_window_launcher_item_controller.h b/chrome/browser/ui/ash/launcher/app_window_launcher_item_controller.h index e1fd876..791a18a 100644 --- a/chrome/browser/ui/ash/launcher/app_window_launcher_item_controller.h +++ b/chrome/browser/ui/ash/launcher/app_window_launcher_item_controller.h
@@ -60,11 +60,6 @@ // Activates the window at position |index|. void ActivateIndexedApp(size_t index); - // Called when launcher item may need to be updated, eg. label or icon. - // TODO(khmel): Use aura::Window property and observe property change - // http://crbug.com/724292 - virtual void UpdateLauncherItem() {} - const WindowList& windows() const { return windows_; } protected: @@ -87,6 +82,10 @@ private: WindowList::iterator GetFromNativeWindow(aura::Window* window); + // Handles the case when the app window in this controller has been changed, + // and sets the new controller icon based on the currently active window. + void UpdateShelfItemIcon(); + // List of associated app windows WindowList windows_;
diff --git a/chrome/browser/ui/ash/launcher/arc_app_deferred_launcher_controller.cc b/chrome/browser/ui/ash/launcher/arc_app_deferred_launcher_controller.cc index 97c20fc..3cd9cbd3 100644 --- a/chrome/browser/ui/ash/launcher/arc_app_deferred_launcher_controller.cc +++ b/chrome/browser/ui/ash/launcher/arc_app_deferred_launcher_controller.cc
@@ -4,7 +4,7 @@ #include "chrome/browser/ui/ash/launcher/arc_app_deferred_launcher_controller.h" -#include "ash/shelf/shelf_model.h" +#include "ash/public/cpp/shelf_model.h" #include "base/memory/ptr_util.h" #include "base/threading/thread_task_runner_handle.h" #include "chrome/browser/chromeos/arc/arc_util.h" @@ -116,7 +116,7 @@ app_controller_map_.erase(it); if (need_close_item) owner_->CloseLauncherItem(shelf_id); - UpdateApp(safe_app_id); + UpdateShelfItemIcon(safe_app_id); } void ArcAppDeferredLauncherController::OnAppReadyChanged( @@ -163,10 +163,9 @@ return it->second->GetActiveTime(); } -void ArcAppDeferredLauncherController::UpdateApp(const std::string& app_id) { - AppIconLoader* icon_loader = owner_->GetAppIconLoaderForApp(app_id); - if (icon_loader) - icon_loader->UpdateImage(app_id); +void ArcAppDeferredLauncherController::UpdateShelfItemIcon( + const std::string& app_id) { + owner_->UpdateLauncherItemImage(app_id); } void ArcAppDeferredLauncherController::UpdateApps() { @@ -175,7 +174,7 @@ RegisterNextUpdate(); for (const auto pair : app_controller_map_) - UpdateApp(pair.first); + UpdateShelfItemIcon(pair.first); } void ArcAppDeferredLauncherController::RegisterNextUpdate() {
diff --git a/chrome/browser/ui/ash/launcher/arc_app_deferred_launcher_controller.h b/chrome/browser/ui/ash/launcher/arc_app_deferred_launcher_controller.h index 02e6145..3f8fe10 100644 --- a/chrome/browser/ui/ash/launcher/arc_app_deferred_launcher_controller.h +++ b/chrome/browser/ui/ash/launcher/arc_app_deferred_launcher_controller.h
@@ -62,7 +62,7 @@ std::map<std::string, ArcAppDeferredLauncherItemController*>; void UpdateApps(); - void UpdateApp(const std::string& app_id); + void UpdateShelfItemIcon(const std::string& app_id); void RegisterNextUpdate(); // Unowned pointers.
diff --git a/chrome/browser/ui/ash/launcher/arc_app_launcher_browsertest.cc b/chrome/browser/ui/ash/launcher/arc_app_launcher_browsertest.cc index e4cd3745..22bf4c8 100644 --- a/chrome/browser/ui/ash/launcher/arc_app_launcher_browsertest.cc +++ b/chrome/browser/ui/ash/launcher/arc_app_launcher_browsertest.cc
@@ -3,7 +3,7 @@ // found in the LICENSE file. #include "ash/public/cpp/shelf_item_delegate.h" -#include "ash/shelf/shelf_model.h" +#include "ash/public/cpp/shelf_model.h" #include "ash/shell.h" #include "ash/wm/window_util.h" #include "base/macros.h"
diff --git a/chrome/browser/ui/ash/launcher/arc_app_window.cc b/chrome/browser/ui/ash/launcher/arc_app_window.cc index d47bf54..cc201ce 100644 --- a/chrome/browser/ui/ash/launcher/arc_app_window.cc +++ b/chrome/browser/ui/ash/launcher/arc_app_window.cc
@@ -14,6 +14,7 @@ #include "ui/aura/window.h" #include "ui/gfx/codec/png_codec.h" #include "ui/gfx/image/image_skia_operations.h" +#include "ui/views/widget/native_widget_aura.h" #include "ui/views/widget/widget.h" ArcAppWindow::ArcAppWindow(int task_id, @@ -33,8 +34,6 @@ ArcAppWindowLauncherItemController* controller) { DCHECK(!controller_ || !controller); controller_ = controller; - if (controller_) - controller_->UpdateLauncherItem(); } void ArcAppWindow::SetFullscreenMode(FullScreenMode mode) { @@ -49,7 +48,7 @@ GetNativeWindow()->SetTitle(base::UTF8ToUTF16(title)); ImageDecoder::Cancel(this); if (unsafe_icon_data_png.empty()) { - ResetIcon(); + SetIcon(gfx::ImageSkia()); return; } @@ -157,21 +156,25 @@ NOTREACHED(); } -void ArcAppWindow::ResetIcon() { - if (icon_.isNull()) +void ArcAppWindow::SetIcon(const gfx::ImageSkia& icon) { + if (!exo::ShellSurface::GetMainSurface(GetNativeWindow())) { + // Support unit tests where we don't have exo system initialized. + views::NativeWidgetAura::AssignIconToAuraWindow( + GetNativeWindow(), gfx::ImageSkia() /* window_icon */, + icon /* app_icon */); return; - icon_ = gfx::ImageSkia(); - if (controller_) - controller_->UpdateLauncherItem(); + } + exo::ShellSurface* shell_surface = static_cast<exo::ShellSurface*>( + widget_->widget_delegate()->GetContentsView()); + if (!shell_surface) + return; + shell_surface->SetIcon(icon); } void ArcAppWindow::OnImageDecoded(const SkBitmap& decoded_image) { - // TODO(khmel): Use aura::Window property http://crbug.com/724292 - icon_ = gfx::ImageSkiaOperations::CreateResizedImage( + SetIcon(gfx::ImageSkiaOperations::CreateResizedImage( gfx::ImageSkia(gfx::ImageSkiaRep(decoded_image, 1.0f)), skia::ImageOperations::RESIZE_BEST, gfx::Size(extension_misc::EXTENSION_ICON_SMALL, - extension_misc::EXTENSION_ICON_SMALL)); - if (controller_) - controller_->UpdateLauncherItem(); + extension_misc::EXTENSION_ICON_SMALL))); }
diff --git a/chrome/browser/ui/ash/launcher/arc_app_window.h b/chrome/browser/ui/ash/launcher/arc_app_window.h index ffef2ba0..4886855 100644 --- a/chrome/browser/ui/ash/launcher/arc_app_window.h +++ b/chrome/browser/ui/ash/launcher/arc_app_window.h
@@ -13,10 +13,12 @@ #include "chrome/browser/image_decoder.h" #include "chrome/browser/ui/ash/launcher/arc_app_shelf_id.h" #include "ui/base/base_window.h" -#include "ui/gfx/image/image_skia.h" class ArcAppWindowLauncherController; class ArcAppWindowLauncherItemController; +namespace gfx { +class ImageSkia; +} namespace views { class Widget; @@ -63,8 +65,6 @@ ArcAppWindowLauncherItemController* controller() { return controller_; } - const gfx::ImageSkia& icon() const { return icon_; } - // ui::BaseWindow: bool IsActive() const override; bool IsMaximized() const override; @@ -89,8 +89,8 @@ void SetAlwaysOnTop(bool always_on_top) override; private: - // Resets the icon and updates |controller_|'s active icon as needed. - void ResetIcon(); + // Sets the icon for the window. + void SetIcon(const gfx::ImageSkia& icon); // ImageDecoder::ImageRequest: void OnImageDecoded(const SkBitmap& decoded_image) override; @@ -103,8 +103,6 @@ ash::ShelfID shelf_id_; // Keeps current full-screen mode. FullScreenMode fullscreen_mode_ = FullScreenMode::NOT_DEFINED; - // Contains custom icon if it was set. - gfx::ImageSkia icon_; // Unowned pointers views::Widget* const widget_; ArcAppWindowLauncherController* const owner_;
diff --git a/chrome/browser/ui/ash/launcher/arc_app_window_launcher_controller.cc b/chrome/browser/ui/ash/launcher/arc_app_window_launcher_controller.cc index 88779bd..0b9a37e 100644 --- a/chrome/browser/ui/ash/launcher/arc_app_window_launcher_controller.cc +++ b/chrome/browser/ui/ash/launcher/arc_app_window_launcher_controller.cc
@@ -6,9 +6,9 @@ #include <string> #include "ash/display/screen_orientation_controller_chromeos.h" +#include "ash/public/cpp/shelf_model.h" #include "ash/public/cpp/window_properties.h" #include "ash/shared/app_types.h" -#include "ash/shelf/shelf_model.h" #include "ash/shell.h" #include "ash/wm/maximize_mode/maximize_mode_controller.h" #include "ash/wm/window_state.h" @@ -547,7 +547,7 @@ std::unique_ptr<ArcAppWindowLauncherItemController> controller = base::MakeUnique<ArcAppWindowLauncherItemController>( - app_shelf_id.ToString(), owner()); + app_shelf_id.ToString()); ArcAppWindowLauncherItemController* item_controller = controller.get(); const ash::ShelfID shelf_id(app_shelf_id.ToString()); if (!owner()->GetItem(shelf_id)) {
diff --git a/chrome/browser/ui/ash/launcher/arc_app_window_launcher_item_controller.cc b/chrome/browser/ui/ash/launcher/arc_app_window_launcher_item_controller.cc index a2d0041..d307b11 100644 --- a/chrome/browser/ui/ash/launcher/arc_app_window_launcher_item_controller.cc +++ b/chrome/browser/ui/ash/launcher/arc_app_window_launcher_item_controller.cc
@@ -20,10 +20,8 @@ #include "ui/base/base_window.h" ArcAppWindowLauncherItemController::ArcAppWindowLauncherItemController( - const std::string& arc_app_id, - ChromeLauncherController* owner) - : AppWindowLauncherItemController(ash::ShelfID(arc_app_id)), - owner_(owner) {} + const std::string& arc_app_id) + : AppWindowLauncherItemController(ash::ShelfID(arc_app_id)) {} ArcAppWindowLauncherItemController::~ArcAppWindowLauncherItemController() {} @@ -67,8 +65,8 @@ ash::MenuItemList ArcAppWindowLauncherItemController::GetAppMenuItems( int event_flags) { ash::MenuItemList items; - base::string16 app_title = - LauncherControllerHelper::GetAppTitle(owner_->profile(), app_id()); + base::string16 app_title = LauncherControllerHelper::GetAppTitle( + ChromeLauncherController::instance()->profile(), app_id()); for (auto it = windows().begin(); it != windows().end(); ++it) { // TODO(khmel): resolve correct icon here. size_t i = std::distance(windows().begin(), it); @@ -82,21 +80,3 @@ return items; } - -void ArcAppWindowLauncherItemController::UpdateLauncherItem() { - const ArcAppWindow* arc_app_window = - static_cast<const ArcAppWindow*>(GetLastActiveWindow()); - if (!arc_app_window || arc_app_window->icon().isNull()) { - if (!image_set_by_controller()) - return; - set_image_set_by_controller(false); - owner_->SetLauncherItemImage(shelf_id(), gfx::ImageSkia()); - AppIconLoader* icon_loader = owner_->GetAppIconLoaderForApp(app_id()); - if (icon_loader) - icon_loader->UpdateImage(app_id()); - return; - } - - owner_->SetLauncherItemImage(shelf_id(), arc_app_window->icon()); - set_image_set_by_controller(true); -}
diff --git a/chrome/browser/ui/ash/launcher/arc_app_window_launcher_item_controller.h b/chrome/browser/ui/ash/launcher/arc_app_window_launcher_item_controller.h index ec8af9c..3ea97b2 100644 --- a/chrome/browser/ui/ash/launcher/arc_app_window_launcher_item_controller.h +++ b/chrome/browser/ui/ash/launcher/arc_app_window_launcher_item_controller.h
@@ -12,14 +12,12 @@ #include "chrome/browser/ui/ash/launcher/app_window_launcher_item_controller.h" class ArcAppWindow; -class ChromeLauncherController; // Shelf item delegate for ARC app windows. class ArcAppWindowLauncherItemController : public AppWindowLauncherItemController { public: - ArcAppWindowLauncherItemController(const std::string& arc_app_id, - ChromeLauncherController* owner); + explicit ArcAppWindowLauncherItemController(const std::string& arc_app_id); ~ArcAppWindowLauncherItemController() override; @@ -35,18 +33,12 @@ void RemoveTaskId(int task_id); bool HasAnyTasks() const; - // AppWindowLauncherItemController: - void UpdateLauncherItem() override; - private: // Update the shelf item's icon for the active window. void UpdateIcon(ArcAppWindow* arc_app_window); std::unordered_set<int> task_ids_; - // Unowned property. - ChromeLauncherController* const owner_; - DISALLOW_COPY_AND_ASSIGN(ArcAppWindowLauncherItemController); };
diff --git a/chrome/browser/ui/ash/launcher/browser_shortcut_launcher_item_controller.cc b/chrome/browser/ui/ash/launcher/browser_shortcut_launcher_item_controller.cc index f2b20a0..a093bfc 100644 --- a/chrome/browser/ui/ash/launcher/browser_shortcut_launcher_item_controller.cc +++ b/chrome/browser/ui/ash/launcher/browser_shortcut_launcher_item_controller.cc
@@ -8,9 +8,9 @@ #include <utility> #include <vector> +#include "ash/public/cpp/shelf_model.h" #include "ash/public/cpp/window_properties.h" #include "ash/resources/grit/ash_resources.h" -#include "ash/shelf/shelf_model.h" #include "base/memory/ptr_util.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/ui/ash/launcher/chrome_launcher_controller.h"
diff --git a/chrome/browser/ui/ash/launcher/chrome_launcher_controller.cc b/chrome/browser/ui/ash/launcher/chrome_launcher_controller.cc index 8908e85..657d1bf 100644 --- a/chrome/browser/ui/ash/launcher/chrome_launcher_controller.cc +++ b/chrome/browser/ui/ash/launcher/chrome_launcher_controller.cc
@@ -7,10 +7,10 @@ #include "ash/multi_profile_uma.h" #include "ash/public/cpp/remote_shelf_item_delegate.h" #include "ash/public/cpp/shelf_item.h" +#include "ash/public/cpp/shelf_model.h" #include "ash/public/interfaces/constants.mojom.h" #include "ash/resources/grit/ash_resources.h" #include "ash/shelf/shelf.h" -#include "ash/shelf/shelf_model.h" #include "ash/shell.h" #include "ash/shell_port.h" #include "ash/strings/grit/ash_strings.h" @@ -422,6 +422,7 @@ void ChromeLauncherController::SetLauncherItemImage( const ash::ShelfID& shelf_id, const gfx::ImageSkia& image) { + DCHECK(!image.isNull()); const ash::ShelfItem* item = GetItem(shelf_id); if (item) { ash::ShelfItem new_item = *item; @@ -430,6 +431,13 @@ } } +void ChromeLauncherController::UpdateLauncherItemImage( + const std::string& app_id) { + AppIconLoader* icon_loader = GetAppIconLoaderForApp(app_id); + if (icon_loader) + icon_loader->UpdateImage(app_id); +} + void ChromeLauncherController::UpdateAppState(content::WebContents* contents, AppState app_state) { ash::ShelfID shelf_id(launcher_controller_helper_->GetAppID(contents)); @@ -686,16 +694,6 @@ return arc_deferred_launcher_.get(); } -AppIconLoader* ChromeLauncherController::GetAppIconLoaderForApp( - const std::string& app_id) { - for (const auto& app_icon_loader : app_icon_loaders_) { - if (app_icon_loader->CanLoadImageForApp(app_id)) - return app_icon_loader.get(); - } - - return nullptr; -} - void ChromeLauncherController::SetShelfAutoHideBehaviorFromPrefs() { if (!ConnectToShelfController() || updating_shelf_pref_from_observer_) return; @@ -761,6 +759,16 @@ model_->UnpinAppWithID(app_id); } +AppIconLoader* ChromeLauncherController::GetAppIconLoaderForApp( + const std::string& app_id) { + for (const auto& app_icon_loader : app_icon_loaders_) { + if (app_icon_loader->CanLoadImageForApp(app_id)) + return app_icon_loader.get(); + } + + return nullptr; +} + /////////////////////////////////////////////////////////////////////////////// // LauncherAppUpdater::Delegate:
diff --git a/chrome/browser/ui/ash/launcher/chrome_launcher_controller.h b/chrome/browser/ui/ash/launcher/chrome_launcher_controller.h index 00d59c4..0c59a46 100644 --- a/chrome/browser/ui/ash/launcher/chrome_launcher_controller.h +++ b/chrome/browser/ui/ash/launcher/chrome_launcher_controller.h
@@ -11,9 +11,9 @@ #include "ash/display/window_tree_host_manager.h" #include "ash/public/cpp/shelf_item_delegate.h" +#include "ash/public/cpp/shelf_model_observer.h" #include "ash/public/cpp/shelf_types.h" #include "ash/public/interfaces/shelf.mojom.h" -#include "ash/shelf/shelf_model_observer.h" #include "base/auto_reset.h" #include "base/macros.h" #include "base/memory/weak_ptr.h" @@ -44,7 +44,6 @@ namespace ash { class Shelf; -struct ShelfItem; class ShelfModel; } // namespace ash @@ -150,6 +149,9 @@ void SetLauncherItemImage(const ash::ShelfID& shelf_id, const gfx::ImageSkia& image); + // Updates the image for a specific shelf item from the app's icon loader. + void UpdateLauncherItemImage(const std::string& app_id); + // Notify the controller that the state of an non platform app's tabs // have changed, void UpdateAppState(content::WebContents* contents, AppState app_state); @@ -219,8 +221,6 @@ // Controller to launch ARC apps in deferred mode. ArcAppDeferredLauncherController* GetArcDeferredLauncher(); - AppIconLoader* GetAppIconLoaderForApp(const std::string& app_id); - // Sets the shelf auto-hide and/or alignment behavior from prefs. void SetShelfAutoHideBehaviorFromPrefs(); void SetShelfAlignmentFromPrefs(); @@ -389,6 +389,9 @@ // An internal helper to unpin a shelf item; this does not update prefs. void UnpinShelfItemInternal(const ash::ShelfID& id); + // Resolves the app icon image loader for the app. + AppIconLoader* GetAppIconLoaderForApp(const std::string& app_id); + static ChromeLauncherController* instance_; // The currently loaded profile used for prefs and loading extensions. This is
diff --git a/chrome/browser/ui/ash/launcher/chrome_launcher_controller_browsertest.cc b/chrome/browser/ui/ash/launcher/chrome_launcher_controller_browsertest.cc index 68545599..58c1fc0 100644 --- a/chrome/browser/ui/ash/launcher/chrome_launcher_controller_browsertest.cc +++ b/chrome/browser/ui/ash/launcher/chrome_launcher_controller_browsertest.cc
@@ -7,12 +7,12 @@ #include <stddef.h> #include "ash/public/cpp/shelf_item_delegate.h" +#include "ash/public/cpp/shelf_model.h" #include "ash/public/cpp/window_properties.h" #include "ash/shelf/app_list_button.h" #include "ash/shelf/shelf.h" #include "ash/shelf/shelf_button.h" #include "ash/shelf/shelf_constants.h" -#include "ash/shelf/shelf_model.h" #include "ash/shelf/shelf_view.h" #include "ash/shelf/shelf_widget.h" #include "ash/shell.h" @@ -51,6 +51,7 @@ #include "chrome/browser/ui/extensions/application_launch.h" #include "chrome/browser/ui/settings_window_manager.h" #include "chrome/browser/ui/tabs/tab_strip_model.h" +#include "chrome/browser/ui/test/test_app_window_icon_observer.h" #include "chrome/browser/web_applications/web_app.h" #include "chrome/common/chrome_switches.h" #include "chrome/common/extensions/manifest_handlers/app_launch_info.h" @@ -130,32 +131,6 @@ DISALLOW_COPY_AND_ASSIGN(TestEvent); }; -class TestAppWindowRegistryObserver - : public extensions::AppWindowRegistry::Observer { - public: - explicit TestAppWindowRegistryObserver(Profile* profile) - : profile_(profile), icon_updates_(0) { - extensions::AppWindowRegistry::Get(profile_)->AddObserver(this); - } - - ~TestAppWindowRegistryObserver() override { - extensions::AppWindowRegistry::Get(profile_)->RemoveObserver(this); - } - - // Overridden from AppWindowRegistry::Observer: - void OnAppWindowIconChanged(AppWindow* app_window) override { - ++icon_updates_; - } - - int icon_updates() { return icon_updates_; } - - private: - Profile* profile_; - int icon_updates_; - - DISALLOW_COPY_AND_ASSIGN(TestAppWindowRegistryObserver); -}; - // Click the "All Apps" button from the app launcher start page. Assumes that // the app launcher is open to the start page. // |display_origin| is the top-left corner of the active display, in screen @@ -853,28 +828,52 @@ EXPECT_EQ(ash::STATUS_RUNNING, shelf_model()->ItemByID(item_id1)->status); } -// Flaky on Linux ChromiumOS bot -- crbug/720601. // Test that opening an app sets the correct icon -IN_PROC_BROWSER_TEST_F(LauncherPlatformAppBrowserTest, DISABLED_SetIcon) { - TestAppWindowRegistryObserver test_observer(browser()->profile()); +IN_PROC_BROWSER_TEST_F(LauncherPlatformAppBrowserTest, SetIcon) { + TestAppWindowIconObserver test_observer(browser()->profile()); // Enable experimental APIs to allow panel creation. base::CommandLine::ForCurrentProcess()->AppendSwitch( extensions::switches::kEnableExperimentalExtensionApis); int base_shelf_item_count = shelf_model()->item_count(); - ExtensionTestMessageListener completed_listener("Completed", false); + ExtensionTestMessageListener ready_listener("ready", true); LoadAndLaunchPlatformApp("app_icon", "Launched"); - ASSERT_TRUE(completed_listener.WaitUntilSatisfied()); + // Create panel window. + ready_listener.WaitUntilSatisfied(); + ready_listener.Reply("createPanelWindow"); + ready_listener.Reset(); + // Default app icon + extension icon updates. + test_observer.WaitForIconUpdates(2); - // Now wait until the WebContent has decoded the icons and chrome has - // processed it. This needs to be in a loop since the renderer runs in a - // different process. - while (test_observer.icon_updates() < 4) { - base::RunLoop run_loop; - run_loop.RunUntilIdle(); - } + // Set panel window icon. + ready_listener.WaitUntilSatisfied(); + ready_listener.Reply("setPanelWindowIcon"); + ready_listener.Reset(); + // Custom icon update. + test_observer.WaitForIconUpdate(); + + // Create non-shelf window. + ready_listener.WaitUntilSatisfied(); + ready_listener.Reply("createNonShelfWindow"); + ready_listener.Reset(); + // Default app icon + extension icon updates. + test_observer.WaitForIconUpdates(2); + + // Create shelf window. + ready_listener.WaitUntilSatisfied(); + ready_listener.Reply("createShelfWindow"); + ready_listener.Reset(); + // Default app icon + extension icon updates. + test_observer.WaitForIconUpdates(2); + + // Set shelf window icon. + ready_listener.WaitUntilSatisfied(); + ready_listener.Reply("setShelfWindowIcon"); + ready_listener.Reset(); + // Custom icon update. + test_observer.WaitForIconUpdate(); // This test creates one app window, one app window with custom icon and one // panel window. @@ -892,7 +891,7 @@ const ash::ShelfItemDelegate* app_item_delegate = GetShelfItemDelegate(app_item.id); ASSERT_TRUE(app_item_delegate); - EXPECT_FALSE(app_item_delegate->image_set_by_controller()); + EXPECT_TRUE(app_item_delegate->image_set_by_controller()); const ash::ShelfItemDelegate* app_custom_icon_item_delegate = GetShelfItemDelegate(app_custom_icon_item.id); @@ -900,10 +899,23 @@ EXPECT_TRUE(app_custom_icon_item_delegate->image_set_by_controller()); // Ensure icon heights are correct (see test.js in app_icon/ test directory) +#if defined(USE_ASH) + EXPECT_EQ(ash::kShelfSize, app_item.image.height()); +#else EXPECT_EQ(extension_misc::EXTENSION_ICON_SMALL, app_item.image.height()); +#endif EXPECT_EQ(extension_misc::EXTENSION_ICON_LARGE, app_custom_icon_item.image.height()); EXPECT_EQ(64, panel_item.image.height()); + + // No more icon updates. + base::RunLoop().RunUntilIdle(); + EXPECT_EQ(8, test_observer.icon_updates()); + + // Exit. + ready_listener.WaitUntilSatisfied(); + ready_listener.Reply("exit"); + ready_listener.Reset(); } // Test that we can launch an app with a shortcut.
diff --git a/chrome/browser/ui/ash/launcher/chrome_launcher_controller_unittest.cc b/chrome/browser/ui/ash/launcher/chrome_launcher_controller_unittest.cc index bff40444..e24620c 100644 --- a/chrome/browser/ui/ash/launcher/chrome_launcher_controller_unittest.cc +++ b/chrome/browser/ui/ash/launcher/chrome_launcher_controller_unittest.cc
@@ -18,11 +18,11 @@ #include "ash/display/screen_orientation_controller_chromeos.h" #include "ash/public/cpp/shelf_item.h" #include "ash/public/cpp/shelf_item_delegate.h" +#include "ash/public/cpp/shelf_model.h" +#include "ash/public/cpp/shelf_model_observer.h" #include "ash/shelf/shelf_application_menu_model.h" #include "ash/shelf/shelf_constants.h" #include "ash/shelf/shelf_controller.h" -#include "ash/shelf/shelf_model.h" -#include "ash/shelf/shelf_model_observer.h" #include "ash/shell.h" #include "ash/test/ash_test_helper.h" #include "ash/test/shell_test_api.h" @@ -2329,6 +2329,7 @@ // Set custom icon on active item. Icon should change to custom. arc_test_.app_instance()->SendTaskDescription(2, std::string(), png_data); + base::RunLoop().RunUntilIdle(); EXPECT_TRUE(item_delegate->image_set_by_controller()); // Switch back to the item without custom icon. Icon should be changed to
diff --git a/chrome/browser/ui/ash/launcher/extension_app_window_launcher_controller.cc b/chrome/browser/ui/ash/launcher/extension_app_window_launcher_controller.cc index b8da64f..3baa7106 100644 --- a/chrome/browser/ui/ash/launcher/extension_app_window_launcher_controller.cc +++ b/chrome/browser/ui/ash/launcher/extension_app_window_launcher_controller.cc
@@ -4,9 +4,9 @@ #include "chrome/browser/ui/ash/launcher/extension_app_window_launcher_controller.h" +#include "ash/public/cpp/shelf_model.h" #include "ash/public/cpp/shelf_types.h" #include "ash/public/cpp/window_properties.h" -#include "ash/shelf/shelf_model.h" #include "ash/wm/window_util.h" #include "base/stl_util.h" #include "base/strings/stringprintf.h" @@ -75,24 +75,6 @@ registry_.insert(registry); } -void ExtensionAppWindowLauncherController::OnAppWindowIconChanged( - AppWindow* app_window) { - const ash::ShelfID shelf_id = GetShelfId(app_window); - AppControllerMap::iterator iter = app_controller_map_.find(shelf_id); - if (iter == app_controller_map_.end()) - return; - - // Check if the window actually overrides its default icon. Otherwise use app - // icon loader provided by owner. - if (!app_window->HasCustomIcon() || app_window->app_icon().IsEmpty()) - return; - - ExtensionAppWindowLauncherItemController* controller = iter->second; - controller->set_image_set_by_controller(true); - owner()->SetLauncherItemImage(controller->shelf_id(), - app_window->app_icon().AsImageSkia()); -} - void ExtensionAppWindowLauncherController::OnAppWindowShown( AppWindow* app_window, bool was_hidden) { @@ -149,21 +131,18 @@ std::unique_ptr<ExtensionAppWindowLauncherItemController> controller = base::MakeUnique<ExtensionAppWindowLauncherItemController>(shelf_id); app_controller_map_[shelf_id] = controller.get(); - controller->AddAppWindow(app_window); // Check for any existing pinned shelf item with a matching |shelf_id|. if (!owner()->GetItem(shelf_id)) { owner()->CreateAppLauncherItem(std::move(controller), status); - // Restore any existing app icon and flag as set. - if (app_window->HasCustomIcon() && !app_window->app_icon().IsEmpty()) { - owner()->SetLauncherItemImage(shelf_id, - app_window->app_icon().AsImageSkia()); - app_controller_map_[shelf_id]->set_image_set_by_controller(true); - } } else { owner()->shelf_model()->SetShelfItemDelegate(shelf_id, std::move(controller)); } + + // Register the window after a shelf item is created to let the controller + // set the shelf icon property. + app_controller_map_[shelf_id]->AddAppWindow(app_window); } owner()->SetItemStatus(shelf_id, status);
diff --git a/chrome/browser/ui/ash/launcher/extension_app_window_launcher_controller.h b/chrome/browser/ui/ash/launcher/extension_app_window_launcher_controller.h index 9a4c4df7..fc0a5a4 100644 --- a/chrome/browser/ui/ash/launcher/extension_app_window_launcher_controller.h +++ b/chrome/browser/ui/ash/launcher/extension_app_window_launcher_controller.h
@@ -45,7 +45,6 @@ aura::Window* window) override; // Overridden from AppWindowRegistry::Observer: - void OnAppWindowIconChanged(extensions::AppWindow* app_window) override; void OnAppWindowShown(extensions::AppWindow* app_window, bool was_hidden) override; void OnAppWindowHidden(extensions::AppWindow* app_window) override;
diff --git a/chrome/browser/ui/ash/launcher/extension_app_window_launcher_item_controller.cc b/chrome/browser/ui/ash/launcher/extension_app_window_launcher_item_controller.cc index 04bc180a..78c557b0 100644 --- a/chrome/browser/ui/ash/launcher/extension_app_window_launcher_item_controller.cc +++ b/chrome/browser/ui/ash/launcher/extension_app_window_launcher_item_controller.cc
@@ -58,8 +58,15 @@ favicon::ContentFaviconDriver::FromWebContents( app_window->web_contents()); gfx::Image icon = favicon_driver->GetFavicon(); - if (icon.IsEmpty()) - icon = app_window->app_icon(); + if (icon.IsEmpty()) { + const gfx::ImageSkia* app_icon = nullptr; + if (app_window->GetNativeWindow()) { + app_icon = app_window->GetNativeWindow()->GetProperty( + aura::client::kAppIconKey); + } + if (app_icon && !app_icon->isNull()) + icon = gfx::Image(*app_icon); + } if (!icon.IsEmpty()) item->image = *icon.ToSkBitmap(); items.push_back(std::move(item));
diff --git a/chrome/browser/ui/ash/launcher/launcher_context_menu.cc b/chrome/browser/ui/ash/launcher/launcher_context_menu.cc index 3639dfd..82b7fdf 100644 --- a/chrome/browser/ui/ash/launcher/launcher_context_menu.cc +++ b/chrome/browser/ui/ash/launcher/launcher_context_menu.cc
@@ -6,8 +6,8 @@ #include <string> +#include "ash/public/cpp/shelf_model.h" #include "ash/shelf/shelf.h" -#include "ash/shelf/shelf_model.h" #include "ash/shelf/shelf_widget.h" #include "ash/shell.h" #include "ash/shell_port.h"
diff --git a/chrome/browser/ui/cocoa/browser_window_controller.mm b/chrome/browser/ui/cocoa/browser_window_controller.mm index 835fd975..0970603 100644 --- a/chrome/browser/ui/cocoa/browser_window_controller.mm +++ b/chrome/browser/ui/cocoa/browser_window_controller.mm
@@ -79,6 +79,7 @@ #import "chrome/browser/ui/cocoa/tabs/tab_strip_view.h" #import "chrome/browser/ui/cocoa/tabs/tab_view.h" #import "chrome/browser/ui/cocoa/toolbar/toolbar_controller.h" +#include "chrome/browser/ui/cocoa/translate/translate_bubble_bridge_views.h" #import "chrome/browser/ui/cocoa/translate/translate_bubble_controller.h" #include "chrome/browser/ui/exclusive_access/fullscreen_controller.h" #include "chrome/browser/ui/location_bar/location_bar.h" @@ -1627,6 +1628,11 @@ step:(translate::TranslateStep)step errorType:(translate::TranslateErrors::Type) errorType { + if (ui::MaterialDesignController::IsSecondaryUiMaterial()) { + ShowTranslateBubbleViews([self window], [self locationBarBridge], contents, + step, errorType, true); + return; + } // TODO(hajimehoshi): The similar logic exists at TranslateBubbleView:: // ShowBubble. This should be unified. if (translateBubbleController_) {
diff --git a/chrome/browser/ui/cocoa/translate/translate_bubble_bridge_views.h b/chrome/browser/ui/cocoa/translate/translate_bubble_bridge_views.h new file mode 100644 index 0000000..669223c --- /dev/null +++ b/chrome/browser/ui/cocoa/translate/translate_bubble_bridge_views.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 CHROME_BROWSER_UI_COCOA_TRANSLATE_BUBBLE_BRIDGE_VIEWS_H_ +#define CHROME_BROWSER_UI_COCOA_TRANSLATE_BUBBLE_BRIDGE_VIEWS_H_ + +#include <Cocoa/Cocoa.h> + +#include "components/translate/core/browser/translate_step.h" +#include "components/translate/core/common/translate_errors.h" + +namespace content { +class WebContents; +} + +class LocationBarViewMac; + +void ShowTranslateBubbleViews(NSWindow* parent_window, + LocationBarViewMac* location_bar, + content::WebContents* web_contents, + translate::TranslateStep step, + translate::TranslateErrors::Type error_type, + bool is_user_gesture); + +#endif // CHROME_BROWSER_UI_COCOA_TRANSLATE_BUBBLE_BRIDGE_VIEWS_H_
diff --git a/chrome/browser/ui/cocoa/translate/translate_bubble_bridge_views.mm b/chrome/browser/ui/cocoa/translate/translate_bubble_bridge_views.mm new file mode 100644 index 0000000..6bd5681 --- /dev/null +++ b/chrome/browser/ui/cocoa/translate/translate_bubble_bridge_views.mm
@@ -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 "chrome/browser/ui/cocoa/translate/translate_bubble_bridge_views.h" + +#include "chrome/browser/ui/cocoa/bubble_anchor_helper_views.h" +#include "chrome/browser/ui/cocoa/location_bar/location_bar_view_mac.h" +#include "chrome/browser/ui/cocoa/location_bar/translate_decoration.h" +#include "chrome/browser/ui/views/translate/translate_bubble_view.h" +#include "ui/base/cocoa/cocoa_base_utils.h" +#include "ui/gfx/mac/coordinate_conversion.h" + +void ShowTranslateBubbleViews(NSWindow* parent_window, + LocationBarViewMac* location_bar, + content::WebContents* web_contents, + translate::TranslateStep step, + translate::TranslateErrors::Type error_type, + bool is_user_gesture) { + gfx::Point anchor_point = + gfx::ScreenPointFromNSPoint(ui::ConvertPointFromWindowToScreen( + parent_window, location_bar->GetBubblePointForDecoration( + location_bar->translate_decoration()))); + TranslateBubbleView::DisplayReason reason = + is_user_gesture ? TranslateBubbleView::USER_GESTURE + : TranslateBubbleView::AUTOMATIC; + TranslateBubbleView::ShowBubble(nullptr, anchor_point, web_contents, step, + error_type, reason); + if (TranslateBubbleView::GetCurrentBubble()) { + KeepBubbleAnchored(TranslateBubbleView::GetCurrentBubble(), + location_bar->translate_decoration()); + } +}
diff --git a/chrome/browser/ui/extensions/extension_install_ui_default.cc b/chrome/browser/ui/extensions/extension_install_ui_default.cc index 53fda5b..6114b11 100644 --- a/chrome/browser/ui/extensions/extension_install_ui_default.cc +++ b/chrome/browser/ui/extensions/extension_install_ui_default.cc
@@ -9,7 +9,6 @@ #include "base/strings/utf_string_conversions.h" #include "build/build_config.h" #include "chrome/browser/chrome_notification_types.h" -#include "chrome/browser/extensions/theme_installed_infobar_delegate.h" #include "chrome/browser/infobars/infobar_service.h" #include "chrome/browser/prefs/incognito_mode_prefs.h" #include "chrome/browser/profiles/profile.h" @@ -141,25 +140,13 @@ content::BrowserContext* context) : profile_(Profile::FromBrowserContext(context)), skip_post_install_ui_(false), - previous_using_system_theme_(false), - use_app_installed_bubble_(false) { - // |profile| can be NULL during tests. - if (profile_) { - // Remember the current theme in case the user presses undo. - const Extension* previous_theme = - ThemeServiceFactory::GetThemeForProfile(profile_); - if (previous_theme) - previous_theme_id_ = previous_theme->id(); - previous_using_system_theme_ = - ThemeServiceFactory::GetForProfile(profile_)->UsingSystemTheme(); - } -} + use_app_installed_bubble_(false) {} ExtensionInstallUIDefault::~ExtensionInstallUIDefault() {} void ExtensionInstallUIDefault::OnInstallSuccess(const Extension* extension, const SkBitmap* icon) { - if (skip_post_install_ui_) + if (skip_post_install_ui_ || extension->is_theme()) return; if (!profile_) { @@ -169,12 +156,6 @@ return; } - if (extension->is_theme()) { - ThemeInstalledInfoBarDelegate::Create( - extension, profile_, previous_theme_id_, previous_using_system_theme_); - return; - } - // Extensions aren't enabled by default in incognito so we confirm // the install in a normal window. Profile* current_profile = profile_->GetOriginalProfile();
diff --git a/chrome/browser/ui/extensions/extension_install_ui_default.h b/chrome/browser/ui/extensions/extension_install_ui_default.h index 32d40e1..2586f2e 100644 --- a/chrome/browser/ui/extensions/extension_install_ui_default.h +++ b/chrome/browser/ui/extensions/extension_install_ui_default.h
@@ -35,10 +35,6 @@ // Whether or not to show the default UI after completing the installation. bool skip_post_install_ui_; - // Used to undo theme installation. - std::string previous_theme_id_; - bool previous_using_system_theme_; - // Whether to show an installed bubble on app install, or use the default // action of opening a new tab page. bool use_app_installed_bubble_;
diff --git a/chrome/browser/ui/search/instant_extended_interactive_uitest.cc b/chrome/browser/ui/search/instant_extended_interactive_uitest.cc index 7bc09d7..e61e99b4 100644 --- a/chrome/browser/ui/search/instant_extended_interactive_uitest.cc +++ b/chrome/browser/ui/search/instant_extended_interactive_uitest.cc
@@ -291,8 +291,7 @@ void InstallThemeAndVerify(const std::string& theme_dir, const std::string& theme_name) { const extensions::Extension* theme = - ThemeServiceFactory::GetThemeForProfile( - ExtensionBrowserTest::browser()->profile()); + ThemeServiceFactory::GetThemeForProfile(profile()); // If there is already a theme installed, the current theme should be // disabled and the new one installed + enabled. int expected_change = theme ? 0 : 1; @@ -300,9 +299,13 @@ const base::FilePath theme_path = test_data_dir_.AppendASCII(theme_dir); ASSERT_TRUE(InstallExtensionWithUIAutoConfirm( theme_path, expected_change, ExtensionBrowserTest::browser())); + content::WindowedNotificationObserver theme_change_observer( + chrome::NOTIFICATION_BROWSER_THEME_CHANGED, + content::Source<ThemeService>( + ThemeServiceFactory::GetForProfile(profile()))); + theme_change_observer.Wait(); const extensions::Extension* new_theme = - ThemeServiceFactory::GetThemeForProfile( - ExtensionBrowserTest::browser()->profile()); + ThemeServiceFactory::GetThemeForProfile(profile()); ASSERT_NE(static_cast<extensions::Extension*>(NULL), new_theme); ASSERT_EQ(new_theme->name(), theme_name); }
diff --git a/chrome/browser/ui/test/test_app_window_icon_observer.cc b/chrome/browser/ui/test/test_app_window_icon_observer.cc new file mode 100644 index 0000000..afa26683 --- /dev/null +++ b/chrome/browser/ui/test/test_app_window_icon_observer.cc
@@ -0,0 +1,61 @@ +// 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/test/test_app_window_icon_observer.h" + +#include "base/run_loop.h" +#include "extensions/browser/app_window/app_window.h" +#include "ui/aura/client/aura_constants.h" +#include "ui/aura/window.h" + +TestAppWindowIconObserver::TestAppWindowIconObserver( + content::BrowserContext* context) + : context_(context) { + extensions::AppWindowRegistry::Get(context_)->AddObserver(this); +} + +TestAppWindowIconObserver::~TestAppWindowIconObserver() { + extensions::AppWindowRegistry::Get(context_)->RemoveObserver(this); + for (aura::Window* window : windows_) + window->RemoveObserver(this); +} + +void TestAppWindowIconObserver::WaitForIconUpdate() { + WaitForIconUpdates(1); +} + +void TestAppWindowIconObserver::WaitForIconUpdates(int updates) { + base::RunLoop run_loop; + expected_icon_updates_ = updates + icon_updates_; + icon_updated_callback_ = run_loop.QuitClosure(); + run_loop.Run(); +} + +void TestAppWindowIconObserver::OnAppWindowAdded( + extensions::AppWindow* app_window) { + aura::Window* window = app_window->GetNativeWindow(); + window->AddObserver(this); + windows_.push_back(window); +} + +void TestAppWindowIconObserver::OnAppWindowRemoved( + extensions::AppWindow* app_window) { + aura::Window* window = app_window->GetNativeWindow(); + if (window) { + windows_.erase(std::find(windows_.begin(), windows_.end(), window)); + window->RemoveObserver(this); + } +} + +void TestAppWindowIconObserver::OnWindowPropertyChanged(aura::Window* window, + const void* key, + intptr_t old) { + if (key == aura::client::kAppIconKey) { + ++icon_updates_; + if (icon_updates_ == expected_icon_updates_ && + !icon_updated_callback_.is_null()) { + base::ResetAndReturn(&icon_updated_callback_).Run(); + } + } +}
diff --git a/chrome/browser/ui/test/test_app_window_icon_observer.h b/chrome/browser/ui/test/test_app_window_icon_observer.h new file mode 100644 index 0000000..c83d1e9 --- /dev/null +++ b/chrome/browser/ui/test/test_app_window_icon_observer.h
@@ -0,0 +1,53 @@ +// 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_TEST_TEST_APP_WINDOW_ICON_OBSERVER_H_ +#define CHROME_BROWSER_UI_TEST_TEST_APP_WINDOW_ICON_OBSERVER_H_ + +#include <vector> + +#include "base/callback.h" +#include "base/macros.h" +#include "extensions/browser/app_window/app_window_registry.h" +#include "ui/aura/window_observer.h" + +namespace content { +class BrowserContext; +} + +// A test helper that waits for AppWindow icon property updates. +class TestAppWindowIconObserver + : public extensions::AppWindowRegistry::Observer, + public aura::WindowObserver { + public: + explicit TestAppWindowIconObserver(content::BrowserContext* context); + ~TestAppWindowIconObserver() override; + + // Waits for one icon update. + void WaitForIconUpdate(); + // Waits for |updates| number of icon updates. + void WaitForIconUpdates(int updates); + + int icon_updates() const { return icon_updates_; } + + private: + // AppWindowRegistry::Observer: + void OnAppWindowAdded(extensions::AppWindow* app_window) override; + void OnAppWindowRemoved(extensions::AppWindow* app_window) override; + + // aura::WindowObserver: + void OnWindowPropertyChanged(aura::Window* window, + const void* key, + intptr_t old) override; + + content::BrowserContext* const context_; + int icon_updates_ = 0; + int expected_icon_updates_ = 0; + std::vector<aura::Window*> windows_; + base::OnceClosure icon_updated_callback_; + + DISALLOW_COPY_AND_ASSIGN(TestAppWindowIconObserver); +}; + +#endif // CHROME_BROWSER_UI_TEST_TEST_APP_WINDOW_ICON_OBSERVER_H_
diff --git a/chrome/browser/ui/views/apps/app_info_dialog/app_info_footer_panel.cc b/chrome/browser/ui/views/apps/app_info_dialog/app_info_footer_panel.cc index c834d03..d7584ee 100644 --- a/chrome/browser/ui/views/apps/app_info_dialog/app_info_footer_panel.cc +++ b/chrome/browser/ui/views/apps/app_info_dialog/app_info_footer_panel.cc
@@ -21,8 +21,8 @@ #include "ui/views/widget/widget.h" #if defined(USE_ASH) -#include "ash/shelf/shelf_model.h" // nogncheck -#include "ash/shell.h" // nogncheck +#include "ash/public/cpp/shelf_model.h" // nogncheck +#include "ash/shell.h" // nogncheck #include "chrome/browser/ui/ash/launcher/chrome_launcher_controller_util.h" // nogncheck #endif
diff --git a/chrome/browser/ui/views/apps/app_info_dialog/app_info_permissions_panel_unittest.cc b/chrome/browser/ui/views/apps/app_info_dialog/app_info_permissions_panel_unittest.cc index f778456..fb9b37e 100644 --- a/chrome/browser/ui/views/apps/app_info_dialog/app_info_permissions_panel_unittest.cc +++ b/chrome/browser/ui/views/apps/app_info_dialog/app_info_permissions_panel_unittest.cc
@@ -12,6 +12,7 @@ #include "base/strings/utf_string_conversions.h" #include "chrome/browser/extensions/extension_service.h" #include "chrome/browser/extensions/test_extension_system.h" +#include "chrome/browser/ui/views/harmony/chrome_layout_provider.h" #include "chrome/grit/generated_resources.h" #include "chrome/test/base/testing_profile.h" #include "content/public/test/test_browser_thread_bundle.h" @@ -55,6 +56,12 @@ .Build(); } + void SetUp() override { + // Set the ChromeLayoutProvider as the default layout provider. + views_delegate_.set_layout_provider( + ChromeLayoutProvider::CreateLayoutProvider()); + } + // We need the UI thread in order to construct UI elements in the view. content::TestBrowserThreadBundle thread_bundle_; views::TestViewsDelegate views_delegate_;
diff --git a/chrome/browser/ui/views/apps/chrome_native_app_window_views.cc b/chrome/browser/ui/views/apps/chrome_native_app_window_views.cc index ae6f17b..af8347b 100644 --- a/chrome/browser/ui/views/apps/chrome_native_app_window_views.cc +++ b/chrome/browser/ui/views/apps/chrome_native_app_window_views.cc
@@ -13,11 +13,16 @@ #include "build/build_config.h" #include "chrome/app/chrome_command_ids.h" #include "chrome/browser/app_mode/app_mode_utils.h" +#include "chrome/browser/extensions/chrome_app_icon.h" +#include "chrome/browser/extensions/chrome_app_icon_service.h" +#include "chrome/browser/extensions/extension_util.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/ui/views/extensions/extension_keybinding_registry_views.h" #include "components/favicon/content/content_favicon_driver.h" #include "components/zoom/page_zoom.h" #include "components/zoom/zoom_controller.h" +#include "extensions/browser/app_window/app_delegate.h" +#include "ui/gfx/image/image_skia_operations.h" #include "ui/views/controls/webview/webview.h" #include "ui/views/widget/widget.h" @@ -250,14 +255,38 @@ // views::WidgetDelegate implementation. gfx::ImageSkia ChromeNativeAppWindowViews::GetWindowAppIcon() { - gfx::Image app_icon = app_window()->app_icon(); - if (app_icon.IsEmpty()) - return GetWindowIcon(); - else - return *app_icon.ToImageSkia(); + // Resulting icon is cached in aura::client::kAppIconKey window property. + const gfx::Image& custom_image = app_window()->custom_app_icon(); + if (app_window()->app_icon_url().is_valid() && + app_window()->show_in_shelf()) { + EnsureAppIconCreated(); + gfx::Image base_image = + !custom_image.IsEmpty() + ? custom_image + : gfx::Image(extensions::util::GetDefaultAppIcon()); + // Scale the icon to EXTENSION_ICON_LARGE. + const int large_icon_size = extension_misc::EXTENSION_ICON_LARGE; + if (base_image.Width() != large_icon_size || + base_image.Height() != large_icon_size) { + gfx::ImageSkia resized_image = + gfx::ImageSkiaOperations::CreateResizedImage( + base_image.AsImageSkia(), skia::ImageOperations::RESIZE_BEST, + gfx::Size(large_icon_size, large_icon_size)); + return gfx::ImageSkiaOperations::CreateIconWithBadge( + resized_image, app_icon_->image_skia()); + } + return gfx::ImageSkiaOperations::CreateIconWithBadge( + base_image.AsImageSkia(), app_icon_->image_skia()); + } + + if (!custom_image.IsEmpty()) + return *custom_image.ToImageSkia(); + EnsureAppIconCreated(); + return app_icon_->image_skia(); } gfx::ImageSkia ChromeNativeAppWindowViews::GetWindowIcon() { + // Resulting icon is cached in aura::client::kWindowIconKey window property. content::WebContents* web_contents = app_window()->web_contents(); if (web_contents) { favicon::FaviconDriver* favicon_driver = @@ -366,3 +395,25 @@ extensions::ExtensionKeybindingRegistry::PLATFORM_APPS_ONLY, NULL)); } + +void ChromeNativeAppWindowViews::EnsureAppIconCreated() { + if (app_icon_ && app_icon_->IsValid()) + return; + + // To avoid recursive call, reset the smart pointer. It will be checked in + // OnIconUpdated to determine if this is a real update or the initial callback + // on icon creation. + app_icon_.reset(); + app_icon_ = + extensions::ChromeAppIconService::Get(app_window()->browser_context()) + ->CreateIcon(this, app_window()->extension_id(), + app_window()->app_delegate()->PreferredIconSize()); +} + +void ChromeNativeAppWindowViews::OnIconUpdated( + extensions::ChromeAppIcon* icon) { + if (!app_icon_) + return; + DCHECK_EQ(app_icon_.get(), icon); + UpdateWindowIcon(); +}
diff --git a/chrome/browser/ui/views/apps/chrome_native_app_window_views.h b/chrome/browser/ui/views/apps/chrome_native_app_window_views.h index 7809977..3234213 100644 --- a/chrome/browser/ui/views/apps/chrome_native_app_window_views.h +++ b/chrome/browser/ui/views/apps/chrome_native_app_window_views.h
@@ -8,12 +8,14 @@ #include <memory> #include "base/macros.h" +#include "chrome/browser/extensions/chrome_app_icon_delegate.h" #include "extensions/components/native_app_window/native_app_window_views.h" class ExtensionKeybindingRegistryViews; class ChromeNativeAppWindowViews - : public native_app_window::NativeAppWindowViews { + : public native_app_window::NativeAppWindowViews, + public extensions::ChromeAppIconDelegate { public: ChromeNativeAppWindowViews(); ~ChromeNativeAppWindowViews() override; @@ -69,6 +71,12 @@ const extensions::AppWindow::CreateParams& create_params) override; private: + // Ensures that the Chrome app icon is created. + void EnsureAppIconCreated(); + + // extensions::ChromeAppIconDelegate: + void OnIconUpdated(extensions::ChromeAppIcon* icon) override; + // Custom shape of the window. If this is not set then the window has a // default shape, usually rectangular. std::unique_ptr<SkRegion> shape_; @@ -81,6 +89,10 @@ std::unique_ptr<ExtensionKeybindingRegistryViews> extension_keybinding_registry_; + // Contains the default Chrome app icon. It is used in case the custom icon + // for the extension app window is not set, or as a part of composite image. + std::unique_ptr<extensions::ChromeAppIcon> app_icon_; + DISALLOW_COPY_AND_ASSIGN(ChromeNativeAppWindowViews); };
diff --git a/chrome/browser/ui/views/ash/chrome_browser_main_extra_parts_ash.cc b/chrome/browser/ui/views/ash/chrome_browser_main_extra_parts_ash.cc index aab4bb8..ff60812fb 100644 --- a/chrome/browser/ui/views/ash/chrome_browser_main_extra_parts_ash.cc +++ b/chrome/browser/ui/views/ash/chrome_browser_main_extra_parts_ash.cc
@@ -5,11 +5,11 @@ #include "chrome/browser/ui/views/ash/chrome_browser_main_extra_parts_ash.h" #include "ash/public/cpp/mus_property_mirror_ash.h" +#include "ash/public/cpp/shelf_model.h" #include "ash/public/cpp/window_pin_type.h" #include "ash/public/cpp/window_properties.h" #include "ash/public/interfaces/window_pin_type.mojom.h" #include "ash/root_window_controller.h" -#include "ash/shelf/shelf_model.h" #include "ash/shell.h" #include "base/memory/ptr_util.h" #include "chrome/browser/chrome_browser_main.h"
diff --git a/chrome/browser/ui/views/desktop_capture/desktop_media_picker_views.cc b/chrome/browser/ui/views/desktop_capture/desktop_media_picker_views.cc index 875173c..13758ba 100644 --- a/chrome/browser/ui/views/desktop_capture/desktop_media_picker_views.cc +++ b/chrome/browser/ui/views/desktop_capture/desktop_media_picker_views.cc
@@ -24,7 +24,6 @@ #include "ui/base/l10n/l10n_util.h" #include "ui/events/keycodes/keyboard_codes.h" #include "ui/gfx/canvas.h" -#include "ui/views/background.h" #include "ui/views/controls/button/checkbox.h" #include "ui/views/controls/scroll_view.h" #include "ui/views/controls/tabbed_pane/tabbed_pane.h" @@ -78,9 +77,6 @@ description_label_->SetHorizontalAlignment(gfx::ALIGN_LEFT); AddChildView(description_label_); - const SkColor bg_color = GetNativeTheme()->GetSystemColor( - ui::NativeTheme::kColorId_DialogBackground); - if (screen_list) { source_types_.push_back(DesktopMediaID::TYPE_SCREEN); @@ -117,7 +113,6 @@ kGenericScreenStyle.item_size.height(), kGenericScreenStyle.item_size.height() * 2); screen_scroll_view->set_hide_horizontal_scrollbar(true); - screen_scroll_view->SetBackground(views::CreateSolidBackground(bg_color)); pane_->AddTab(screen_title_text, screen_scroll_view); pane_->set_listener(this); @@ -147,7 +142,6 @@ window_scroll_view->ClipHeightTo(kWindowStyle.item_size.height(), kWindowStyle.item_size.height() * 2); window_scroll_view->set_hide_horizontal_scrollbar(true); - window_scroll_view->SetBackground(views::CreateSolidBackground(bg_color)); pane_->AddTab(window_title_text, window_scroll_view); pane_->set_listener(this); @@ -177,7 +171,6 @@ tab_scroll_view->ClipHeightTo(kTabStyle.item_size.height(), kTabStyle.item_size.height() * 10); tab_scroll_view->set_hide_horizontal_scrollbar(true); - tab_scroll_view->SetBackground(views::CreateSolidBackground(bg_color)); pane_->AddTab(tab_title_text, tab_scroll_view); pane_->set_listener(this);
diff --git a/chrome/browser/ui/views/extensions/extension_install_dialog_view.cc b/chrome/browser/ui/views/extensions/extension_install_dialog_view.cc index c15d2b7..7b76bb7 100644 --- a/chrome/browser/ui/views/extensions/extension_install_dialog_view.cc +++ b/chrome/browser/ui/views/extensions/extension_install_dialog_view.cc
@@ -503,12 +503,6 @@ return layout; } -void ExtensionInstallDialogView::OnNativeThemeChanged( - const ui::NativeTheme* theme) { - scroll_view_->SetBackgroundColor( - theme->GetSystemColor(ui::NativeTheme::kColorId_DialogBackground)); -} - int ExtensionInstallDialogView::GetDialogButtons() const { int buttons = prompt_->GetDialogButtons(); // Simply having just an OK button is *not* supported. See comment on function
diff --git a/chrome/browser/ui/views/extensions/extension_install_dialog_view.h b/chrome/browser/ui/views/extensions/extension_install_dialog_view.h index de6da73..14e29abc 100644 --- a/chrome/browser/ui/views/extensions/extension_install_dialog_view.h +++ b/chrome/browser/ui/views/extensions/extension_install_dialog_view.h
@@ -54,7 +54,6 @@ private: // views::View: - void OnNativeThemeChanged(const ui::NativeTheme* theme) override; void VisibilityChanged(views::View* starting_from, bool is_visible) override; // views::DialogDelegateView:
diff --git a/chrome/browser/ui/views/intent_picker_bubble_view.cc b/chrome/browser/ui/views/intent_picker_bubble_view.cc index e12e075..4c6a5a8 100644 --- a/chrome/browser/ui/views/intent_picker_bubble_view.cc +++ b/chrome/browser/ui/views/intent_picker_bubble_view.cc
@@ -180,7 +180,7 @@ } scroll_view_ = new views::ScrollView(); - scroll_view_->EnableViewPortLayer(); + scroll_view_->SetBackgroundColor(SK_ColorWHITE); scroll_view_->SetContents(scrollable_view); // Setting a customized ScrollBar which is shown only when the mouse pointer // is inside the ScrollView.
diff --git a/chrome/browser/ui/views/payments/payment_request_sheet_controller.cc b/chrome/browser/ui/views/payments/payment_request_sheet_controller.cc index f02bb75b0..c3461f9 100644 --- a/chrome/browser/ui/views/payments/payment_request_sheet_controller.cc +++ b/chrome/browser/ui/views/payments/payment_request_sheet_controller.cc
@@ -145,6 +145,7 @@ }; BorderedScrollView() : views::ScrollView() { + SetBackgroundColor(SK_ColorWHITE); SetBorder(views::CreateBorderPainter( base::MakeUnique<BorderedScrollViewBorderPainter>( GetNativeTheme()->GetSystemColor( @@ -239,7 +240,6 @@ scroll_ = base::MakeUnique<BorderedScrollView>(); scroll_->set_owned_by_client(); - scroll_->EnableViewPortLayer(); scroll_->set_hide_horizontal_scrollbar(true); scroll_->SetContents(pane_); layout->AddView(scroll_.get());
diff --git a/chrome/browser/ui/views/toolbar/extension_toolbar_menu_view.cc b/chrome/browser/ui/views/toolbar/extension_toolbar_menu_view.cc index 274f13e0..867139e 100644 --- a/chrome/browser/ui/views/toolbar/extension_toolbar_menu_view.cc +++ b/chrome/browser/ui/views/toolbar/extension_toolbar_menu_view.cc
@@ -35,6 +35,9 @@ max_height_(0), toolbar_actions_bar_observer_(this), weak_factory_(this) { + // Use a transparent background so that the menu's background shows through. + // None of the children use layers, so this should be ok. + SetBackgroundColor(SK_ColorTRANSPARENT); BrowserActionsContainer* main = BrowserView::GetBrowserViewForBrowser(browser_) ->toolbar()->browser_actions();
diff --git a/chrome/browser/ui/views/toolbar/toolbar_view.cc b/chrome/browser/ui/views/toolbar/toolbar_view.cc index ef9ffcd2..72eaaa1 100644 --- a/chrome/browser/ui/views/toolbar/toolbar_view.cc +++ b/chrome/browser/ui/views/toolbar/toolbar_view.cc
@@ -345,9 +345,9 @@ } views::Widget* bubble_widget = TranslateBubbleView::ShowBubble( - anchor_view, web_contents, step, - error_type, is_user_gesture ? TranslateBubbleView::USER_GESTURE - : TranslateBubbleView::AUTOMATIC); + anchor_view, gfx::Point(), web_contents, step, error_type, + is_user_gesture ? TranslateBubbleView::USER_GESTURE + : TranslateBubbleView::AUTOMATIC); if (bubble_widget && translate_icon_view) bubble_widget->AddObserver(translate_icon_view); }
diff --git a/chrome/browser/ui/views/translate/translate_bubble_view.cc b/chrome/browser/ui/views/translate/translate_bubble_view.cc index 4a2aa3e7..4f5f3af2 100644 --- a/chrome/browser/ui/views/translate/translate_bubble_view.cc +++ b/chrome/browser/ui/views/translate/translate_bubble_view.cc
@@ -91,6 +91,7 @@ // static views::Widget* TranslateBubbleView::ShowBubble( views::View* anchor_view, + const gfx::Point& anchor_point, content::WebContents* web_contents, translate::TranslateStep step, translate::TranslateErrors::Type error_type, @@ -131,7 +132,7 @@ std::unique_ptr<TranslateBubbleModel> model( new TranslateBubbleModelImpl(step, std::move(ui_delegate))); TranslateBubbleView* view = new TranslateBubbleView( - anchor_view, std::move(model), error_type, web_contents); + anchor_view, anchor_point, std::move(model), error_type, web_contents); views::Widget* bubble_widget = views::BubbleDialogDelegateView::CreateBubble(view); view->ShowForReason(reason); @@ -345,10 +346,11 @@ TranslateBubbleView::TranslateBubbleView( views::View* anchor_view, + const gfx::Point& anchor_point, std::unique_ptr<TranslateBubbleModel> model, translate::TranslateErrors::Type error_type, content::WebContents* web_contents) - : LocationBarBubbleDelegateView(anchor_view, web_contents), + : LocationBarBubbleDelegateView(anchor_view, anchor_point, web_contents), WebContentsObserver(web_contents), before_translate_view_(NULL), translating_view_(NULL),
diff --git a/chrome/browser/ui/views/translate/translate_bubble_view.h b/chrome/browser/ui/views/translate/translate_bubble_view.h index 00e58619..d4921bc 100644 --- a/chrome/browser/ui/views/translate/translate_bubble_view.h +++ b/chrome/browser/ui/views/translate/translate_bubble_view.h
@@ -69,6 +69,7 @@ // |is_user_gesture| is true when the bubble is shown on the user's deliberate // action. static views::Widget* ShowBubble(views::View* anchor_view, + const gfx::Point& anchor_point, content::WebContents* web_contents, translate::TranslateStep step, translate::TranslateErrors::Type error_type, @@ -174,6 +175,7 @@ FRIEND_TEST_ALL_PREFIXES(TranslateBubbleViewTest, CancelButtonReturningError); TranslateBubbleView(views::View* anchor_view, + const gfx::Point& anchor_point, std::unique_ptr<TranslateBubbleModel> model, translate::TranslateErrors::Type error_type, content::WebContents* web_contents);
diff --git a/chrome/browser/ui/views/translate/translate_bubble_view_unittest.cc b/chrome/browser/ui/views/translate/translate_bubble_view_unittest.cc index 40984d47..f28fddbc5 100644 --- a/chrome/browser/ui/views/translate/translate_bubble_view_unittest.cc +++ b/chrome/browser/ui/views/translate/translate_bubble_view_unittest.cc
@@ -169,7 +169,7 @@ void CreateAndShowBubble() { std::unique_ptr<TranslateBubbleModel> model(mock_model_); bubble_ = new TranslateBubbleView(anchor_widget_->GetContentsView(), - std::move(model), + gfx::Point(), std::move(model), translate::TranslateErrors::NONE, NULL); views::BubbleDialogDelegateView::CreateBubble(bubble_)->Show(); }
diff --git a/chrome/browser/ui/webui/conflicts_handler.cc b/chrome/browser/ui/webui/conflicts_handler.cc new file mode 100644 index 0000000..75c06bd --- /dev/null +++ b/chrome/browser/ui/webui/conflicts_handler.cc
@@ -0,0 +1,70 @@ +// 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/webui/conflicts_handler.h" + +#include "base/bind.h" +#include "base/bind_helpers.h" +#include "base/strings/string16.h" +#include "base/strings/string_number_conversions.h" +#include "base/values.h" +#include "chrome/grit/generated_resources.h" +#include "content/public/browser/web_ui.h" +#include "ui/base/l10n/l10n_util.h" + +ConflictsHandler::ConflictsHandler() : observer_(this) {} +ConflictsHandler::~ConflictsHandler() = default; + +void ConflictsHandler::RegisterMessages() { + web_ui()->RegisterMessageCallback( + "requestModuleList", + base::Bind(&ConflictsHandler::HandleRequestModuleList, + base::Unretained(this))); +} + +void ConflictsHandler::HandleRequestModuleList(const base::ListValue* args) { + // The request is handled asynchronously, and will callback via + // OnScanCompleted on completion. + auto* model = EnumerateModulesModel::GetInstance(); + + // The JS shouldn't be abusive and call 'requestModuleList' twice, but it's + // easy enough to defend against this. + if (!observer_.IsObserving(model)) { + observer_.Add(model); + + // Ask the scan to be performed immediately, and not in background mode. + // This ensures the results are available ASAP for the UI. + model->ScanNow(false); + } +} + +void ConflictsHandler::SendModuleList() { + auto* loaded_modules = EnumerateModulesModel::GetInstance(); + base::ListValue* list = loaded_modules->GetModuleList(); + base::DictionaryValue results; + results.Set("moduleList", list); + + // Add the section title and the total count for bad modules found. + int confirmed_bad = loaded_modules->confirmed_bad_modules_detected(); + int suspected_bad = loaded_modules->suspected_bad_modules_detected(); + base::string16 table_title; + if (!confirmed_bad && !suspected_bad) { + table_title += l10n_util::GetStringFUTF16( + IDS_CONFLICTS_CHECK_PAGE_TABLE_TITLE_SUFFIX_ONE, + base::IntToString16(list->GetSize())); + } else { + table_title += l10n_util::GetStringFUTF16( + IDS_CONFLICTS_CHECK_PAGE_TABLE_TITLE_SUFFIX_TWO, + base::IntToString16(list->GetSize()), + base::IntToString16(confirmed_bad), base::IntToString16(suspected_bad)); + } + results.SetString("modulesTableTitle", table_title); + + web_ui()->CallJavascriptFunctionUnsafe("returnModuleList", results); +} + +void ConflictsHandler::OnScanCompleted() { + SendModuleList(); + observer_.Remove(EnumerateModulesModel::GetInstance()); +}
diff --git a/chrome/browser/ui/webui/conflicts_handler.h b/chrome/browser/ui/webui/conflicts_handler.h new file mode 100644 index 0000000..1b7cfae --- /dev/null +++ b/chrome/browser/ui/webui/conflicts_handler.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_WEBUI_CONFLICTS_HANDLER_H_ +#define CHROME_BROWSER_UI_WEBUI_CONFLICTS_HANDLER_H_ + +#include "base/macros.h" +#include "base/scoped_observer.h" +#include "chrome/browser/win/enumerate_modules_model.h" +#include "content/public/browser/web_ui_message_handler.h" + +class ConflictsHandler : public content::WebUIMessageHandler, + public EnumerateModulesModel::Observer { + public: + ConflictsHandler(); + ~ConflictsHandler() override; + + // WebUIMessageHandler implementation. + void RegisterMessages() override; + + // Callback for the "requestModuleList" message. + void HandleRequestModuleList(const base::ListValue* args); + + private: + void SendModuleList(); + + // EnumerateModulesModel::Observer implementation. + void OnScanCompleted() override; + + ScopedObserver<EnumerateModulesModel, EnumerateModulesModel::Observer> + observer_; + + DISALLOW_COPY_AND_ASSIGN(ConflictsHandler); +}; + +#endif // CHROME_BROWSER_UI_WEBUI_CONFLICTS_HANDLER_H_
diff --git a/chrome/browser/ui/webui/conflicts_ui.cc b/chrome/browser/ui/webui/conflicts_ui.cc index 7ed3878..440f7fe3 100644 --- a/chrome/browser/ui/webui/conflicts_ui.cc +++ b/chrome/browser/ui/webui/conflicts_ui.cc
@@ -4,45 +4,20 @@ #include "chrome/browser/ui/webui/conflicts_ui.h" -#if defined(OS_WIN) - -#include <string> - -#include "base/bind.h" -#include "base/bind_helpers.h" -#include "base/macros.h" #include "base/memory/ptr_util.h" #include "base/memory/ref_counted_memory.h" #include "base/metrics/user_metrics.h" -#include "base/scoped_observer.h" -#include "base/strings/string_number_conversions.h" -#include "base/strings/utf_string_conversions.h" -#include "base/values.h" -#include "build/build_config.h" -#include "chrome/browser/chrome_notification_types.h" #include "chrome/browser/profiles/profile.h" -#include "chrome/browser/win/enumerate_modules_model.h" +#include "chrome/browser/ui/webui/conflicts_handler.h" #include "chrome/common/url_constants.h" #include "chrome/grit/browser_resources.h" #include "chrome/grit/chromium_strings.h" #include "chrome/grit/generated_resources.h" #include "chrome/grit/theme_resources.h" #include "components/strings/grit/components_strings.h" -#include "content/public/browser/notification_observer.h" -#include "content/public/browser/notification_registrar.h" -#include "content/public/browser/notification_service.h" -#include "content/public/browser/web_contents.h" -#include "content/public/browser/web_ui.h" #include "content/public/browser/web_ui_data_source.h" -#include "content/public/browser/web_ui_message_handler.h" -#include "ui/base/l10n/l10n_util.h" -#include "ui/base/layout.h" #include "ui/base/resource/resource_bundle.h" -using base::UserMetricsAction; -using content::WebContents; -using content::WebUIMessageHandler; - namespace { content::WebUIDataSource* CreateConflictsUIHTMLSource() { @@ -73,94 +48,6 @@ return source; } -//////////////////////////////////////////////////////////////////////////////// -// -// ConflictsDOMHandler -// -//////////////////////////////////////////////////////////////////////////////// - -// The handler for JavaScript messages for the about:conflicts page. -class ConflictsDOMHandler : public WebUIMessageHandler, - public EnumerateModulesModel::Observer { - public: - ConflictsDOMHandler(); - ~ConflictsDOMHandler() override {} - - // WebUIMessageHandler implementation. - void RegisterMessages() override; - - // Callback for the "requestModuleList" message. - void HandleRequestModuleList(const base::ListValue* args); - - private: - void SendModuleList(); - - // EnumerateModulesModel::Observer implementation. - void OnScanCompleted() override; - - ScopedObserver<EnumerateModulesModel, - EnumerateModulesModel::Observer> observer_; - - DISALLOW_COPY_AND_ASSIGN(ConflictsDOMHandler); -}; - -ConflictsDOMHandler::ConflictsDOMHandler() - : observer_(this) { -} - -void ConflictsDOMHandler::RegisterMessages() { - web_ui()->RegisterMessageCallback("requestModuleList", - base::Bind(&ConflictsDOMHandler::HandleRequestModuleList, - base::Unretained(this))); -} - -void ConflictsDOMHandler::HandleRequestModuleList(const base::ListValue* args) { - // The request is handled asynchronously, and will callback via - // OnScanCompleted on completion. - auto* model = EnumerateModulesModel::GetInstance(); - - // The JS shouldn't be abusive and call 'requestModuleList' twice, but it's - // easy enough to defend against this. - if (!observer_.IsObserving(model)) { - observer_.Add(model); - - // Ask the scan to be performed immediately, and not in background mode. - // This ensures the results are available ASAP for the UI. - model->ScanNow(false); - } -} - -void ConflictsDOMHandler::SendModuleList() { - auto* loaded_modules = EnumerateModulesModel::GetInstance(); - base::ListValue* list = loaded_modules->GetModuleList(); - base::DictionaryValue results; - results.Set("moduleList", list); - - // Add the section title and the total count for bad modules found. - int confirmed_bad = loaded_modules->confirmed_bad_modules_detected(); - int suspected_bad = loaded_modules->suspected_bad_modules_detected(); - base::string16 table_title; - if (!confirmed_bad && !suspected_bad) { - table_title += l10n_util::GetStringFUTF16( - IDS_CONFLICTS_CHECK_PAGE_TABLE_TITLE_SUFFIX_ONE, - base::IntToString16(list->GetSize())); - } else { - table_title += l10n_util::GetStringFUTF16( - IDS_CONFLICTS_CHECK_PAGE_TABLE_TITLE_SUFFIX_TWO, - base::IntToString16(list->GetSize()), - base::IntToString16(confirmed_bad), - base::IntToString16(suspected_bad)); - } - results.SetString("modulesTableTitle", table_title); - - web_ui()->CallJavascriptFunctionUnsafe("returnModuleList", results); -} - -void ConflictsDOMHandler::OnScanCompleted() { - SendModuleList(); - observer_.Remove(EnumerateModulesModel::GetInstance()); -} - } // namespace /////////////////////////////////////////////////////////////////////////////// @@ -169,9 +56,10 @@ // /////////////////////////////////////////////////////////////////////////////// -ConflictsUI::ConflictsUI(content::WebUI* web_ui) : WebUIController(web_ui) { - base::RecordAction(UserMetricsAction("ViewAboutConflicts")); - web_ui->AddMessageHandler(base::MakeUnique<ConflictsDOMHandler>()); +ConflictsUI::ConflictsUI(content::WebUI* web_ui) + : content::WebUIController(web_ui) { + base::RecordAction(base::UserMetricsAction("ViewAboutConflicts")); + web_ui->AddMessageHandler(base::MakeUnique<ConflictsHandler>()); // Set up the about:conflicts source. Profile* profile = Profile::FromWebUI(web_ui); @@ -185,5 +73,3 @@ ResourceBundle::GetSharedInstance().LoadDataResourceBytesForScale( IDR_CONFLICT_FAVICON, scale_factor)); } - -#endif
diff --git a/chrome/browser/ui/webui/conflicts_ui.h b/chrome/browser/ui/webui/conflicts_ui.h index 46735f14..0618ae5 100644 --- a/chrome/browser/ui/webui/conflicts_ui.h +++ b/chrome/browser/ui/webui/conflicts_ui.h
@@ -10,8 +10,6 @@ #include "content/public/browser/web_ui_controller.h" #include "ui/base/layout.h" -#if defined(OS_WIN) - namespace base { class RefCountedMemory; } @@ -28,6 +26,4 @@ DISALLOW_COPY_AND_ASSIGN(ConflictsUI); }; -#endif - #endif // CHROME_BROWSER_UI_WEBUI_CONFLICTS_UI_H_
diff --git a/chrome/common/extensions/api/accessibility_private.json b/chrome/common/extensions/api/accessibility_private.json index 0b9f629..cc34f2b 100644 --- a/chrome/common/extensions/api/accessibility_private.json +++ b/chrome/common/extensions/api/accessibility_private.json
@@ -100,6 +100,24 @@ "description": "True to darken screen; false to undarken screen." } ] + }, + { + "name": "setSwitchAccessKeys", + "type": "function", + "description": "Change the keyboard keys captured by Switch Access.", + "parameters": [ + { + "name": "key_codes", + "type": "array", + "items": { + "type": "integer", + "minimum": 48, // '0' key + "maximum": 90 // 'z' key + }, + "description": "The key codes for the keys that will be captured." + } + ], + "platforms": ["chromeos"] } ], "events": [
diff --git a/chrome/service/cloud_print/cloud_print_token_store.cc b/chrome/service/cloud_print/cloud_print_token_store.cc index 84006ee..bebf595 100644 --- a/chrome/service/cloud_print/cloud_print_token_store.cc +++ b/chrome/service/cloud_print/cloud_print_token_store.cc
@@ -15,6 +15,7 @@ base::ThreadLocalPointer<CloudPrintTokenStore>>::DestructorAtExit lazy_tls = LAZY_INSTANCE_INITIALIZER; +// static CloudPrintTokenStore* CloudPrintTokenStore::current() { return lazy_tls.Pointer()->Get(); } @@ -24,12 +25,12 @@ } CloudPrintTokenStore::~CloudPrintTokenStore() { - DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); lazy_tls.Pointer()->Set(NULL); } void CloudPrintTokenStore::SetToken(const std::string& token) { - DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); token_ = token; }
diff --git a/chrome/service/cloud_print/cloud_print_token_store.h b/chrome/service/cloud_print/cloud_print_token_store.h index b61ed9ee..c8c46823 100644 --- a/chrome/service/cloud_print/cloud_print_token_store.h +++ b/chrome/service/cloud_print/cloud_print_token_store.h
@@ -8,7 +8,7 @@ #include <string> #include "base/logging.h" #include "base/macros.h" -#include "base/sequence_checker.h" +#include "base/threading/thread_checker.h" // This class serves as the single repository for cloud print auth tokens. This // is only used within the CloudPrintProxyCoreThread. @@ -26,14 +26,15 @@ void SetToken(const std::string& token); std::string token() const { - DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); return token_; } private: std::string token_; - SEQUENCE_CHECKER(sequence_checker_); + // Thread-affine per use of TLS in impl. + THREAD_CHECKER(thread_checker_); DISALLOW_COPY_AND_ASSIGN(CloudPrintTokenStore); };
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn index cef0c0a..9e73427 100644 --- a/chrome/test/BUILD.gn +++ b/chrome/test/BUILD.gn
@@ -223,6 +223,10 @@ sources += [ "../browser/chromeos/accessibility/speech_monitor.cc", "../browser/chromeos/accessibility/speech_monitor.h", + "../browser/chromeos/ownership/fake_owner_settings_service.cc", + "../browser/chromeos/ownership/fake_owner_settings_service.h", + "../browser/chromeos/settings/scoped_cros_settings_test_helper.cc", + "../browser/chromeos/settings/scoped_cros_settings_test_helper.h", ] public_deps += [ "//components/ownership", @@ -2025,7 +2029,11 @@ } } if (use_aura) { - sources += [ "../browser/ui/aura/accessibility/automation_manager_aura_browsertest.cc" ] + sources += [ + "../browser/ui/aura/accessibility/automation_manager_aura_browsertest.cc", + "../browser/ui/test/test_app_window_icon_observer.cc", + "../browser/ui/test/test_app_window_icon_observer.h", + ] } if (use_aura || toolkit_views) { deps += [ "//ui/events:test_support" ] @@ -2231,8 +2239,6 @@ "../browser/chromeos/login/webview_login_browsertest.cc", "../browser/chromeos/login/wizard_controller_browsertest.cc", "../browser/chromeos/net/network_portal_detector_impl_browsertest.cc", - "../browser/chromeos/ownership/fake_owner_settings_service.cc", - "../browser/chromeos/ownership/fake_owner_settings_service.h", "../browser/chromeos/policy/affiliation_test_helper.cc", "../browser/chromeos/policy/affiliation_test_helper.h", "../browser/chromeos/policy/blocking_login_browsertest.cc", @@ -2262,8 +2268,6 @@ "../browser/chromeos/power/peripheral_battery_observer_browsertest.cc", "../browser/chromeos/preferences_chromeos_browsertest.cc", "../browser/chromeos/profiles/profile_helper_browsertest.cc", - "../browser/chromeos/settings/scoped_cros_settings_test_helper.cc", - "../browser/chromeos/settings/scoped_cros_settings_test_helper.h", "../browser/chromeos/shutdown_policy_browsertest.cc", "../browser/chromeos/system/device_disabling_browsertest.cc", "../browser/chromeos/system/tray_accessibility_browsertest.cc",
diff --git a/chrome/test/base/testing_profile.cc b/chrome/test/base/testing_profile.cc index 58041030..f67cb424 100644 --- a/chrome/test/base/testing_profile.cc +++ b/chrome/test/base/testing_profile.cc
@@ -28,6 +28,7 @@ #include "chrome/browser/browsing_data/chrome_browsing_data_remover_delegate.h" #include "chrome/browser/browsing_data/chrome_browsing_data_remover_delegate_factory.h" #include "chrome/browser/chrome_notification_types.h" +#include "chrome/browser/chromeos/settings/cros_settings.h" #include "chrome/browser/content_settings/host_content_settings_map_factory.h" #include "chrome/browser/favicon/favicon_service_factory.h" #include "chrome/browser/history/chrome_history_client.h" @@ -426,6 +427,13 @@ content::BrowserThread::UI) || content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); +#if defined(OS_CHROMEOS) + if (!chromeos::CrosSettings::IsInitialized()) { + scoped_cros_settings_test_helper_.reset( + new chromeos::ScopedCrosSettingsTestHelper); + } +#endif + set_is_guest_profile(guest_session_); BrowserContext::Initialize(this, profile_path_);
diff --git a/chrome/test/base/testing_profile.h b/chrome/test/base/testing_profile.h index 9fff4af..2384f0c 100644 --- a/chrome/test/base/testing_profile.h +++ b/chrome/test/base/testing_profile.h
@@ -19,6 +19,10 @@ #include "components/keyed_service/content/browser_context_keyed_service_factory.h" #include "extensions/features/features.h" +#if defined(OS_CHROMEOS) +#include "chrome/browser/chromeos/settings/scoped_cros_settings_test_helper.h" +#endif + class BrowserContextDependencyManager; class ExtensionSpecialStoragePolicy; class HostContentSettingsMap; @@ -438,6 +442,11 @@ std::string profile_name_; +#if defined(OS_CHROMEOS) + std::unique_ptr<chromeos::ScopedCrosSettingsTestHelper> + scoped_cros_settings_test_helper_; +#endif // defined(OS_CHROMEOS) + std::unique_ptr<policy::PolicyService> policy_service_; };
diff --git a/chrome/test/data/extensions/platform_apps/app_icon/test.js b/chrome/test/data/extensions/platform_apps/app_icon/test.js index 3b3887a..bebd82e0 100644 --- a/chrome/test/data/extensions/platform_apps/app_icon/test.js +++ b/chrome/test/data/extensions/platform_apps/app_icon/test.js
@@ -2,29 +2,54 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -chrome.app.runtime.onLaunched.addListener(function() { - chrome.test.sendMessage("Launched"); - // Create a panel window first - chrome.app.window.create( - 'main.html', { type: "panel" }, - function (win) { - // Set the panel window icon - win.setIcon("icon64.png") +var panelWindow; +var nonShelfWindow; +var shelfWindow; + +function processNextCommand() { + chrome.test.sendMessage('ready', function(response) { + if (response == 'Exit') { + return; + } + if (response == 'createPanelWindow') { + chrome.app.window.create('main.html', { type: 'panel' }, function (win) { + panelWindow = win; + }); + } + if (response == 'setPanelWindowIcon') { + panelWindow.setIcon('icon64.png') + } + if (response == 'createNonShelfWindow') { // Create the shell window; it should use the app icon, and not affect // the panel icon. chrome.app.window.create( - 'main.html', { type: "shell" }, + 'main.html', { id: 'win', + type: 'shell' }, function (win) { - // Create the shell window which is shown in shelf; it should use - // another custom app icon. - chrome.app.window.create( - 'main.html', { id: "win_with_icon", - type: "shell", - icon: "icon48.png", - showInShelf: true }, - function (win) { - chrome.test.sendMessage("Completed"); - }); + nonShelfWindow = win; }); - }); + } + if (response == 'createShelfWindow') { + // Create the shell window which is shown in shelf; it should use + // another custom app icon. + chrome.app.window.create( + 'main.html', { id: 'win_with_icon', + type: 'shell', + showInShelf: true }, + function (win) { + shelfWindow = win; + }); + } + if (response == 'setShelfWindowIcon') { + shelfWindow.setIcon('icon32.png') + } + processNextCommand(); + }); +}; + + +chrome.app.runtime.onLaunched.addListener(function() { + chrome.test.sendMessage('Launched'); + processNextCommand(); }); +
diff --git a/components/autofill/core/browser/autofill_metrics.cc b/components/autofill/core/browser/autofill_metrics.cc index 670ec072..3039a08 100644 --- a/components/autofill/core/browser/autofill_metrics.cc +++ b/components/autofill/core/browser/autofill_metrics.cc
@@ -12,6 +12,8 @@ #include "base/metrics/histogram_macros.h" #include "base/metrics/sparse_histogram.h" #include "base/metrics/user_metrics.h" +#include "base/strings/string_piece.h" +#include "base/strings/string_util.h" #include "base/time/time.h" #include "components/autofill/core/browser/autofill_experiments.h" #include "components/autofill/core/browser/autofill_field.h" @@ -80,6 +82,10 @@ NUM_FIELD_TYPE_GROUPS_FOR_METRICS }; +const int KMaxFieldTypeGroupMetric = + (NUM_FIELD_TYPE_GROUPS_FOR_METRICS << 8) | + AutofillMetrics::NUM_FIELD_TYPE_QUALITY_METRICS; + std::string PreviousSaveCreditCardPromptUserDecisionToString( int previous_save_credit_card_prompt_user_decision) { DCHECK_LT(previous_save_credit_card_prompt_user_decision, @@ -228,9 +234,12 @@ break; } - // Interpolate the |metric| with the |group|, so that all metrics for a given - // |group| are adjacent. - return (group * AutofillMetrics::NUM_FIELD_TYPE_QUALITY_METRICS) + metric; + // Use bits 8-15 for the group and bits 0-7 for the metric. + static_assert(AutofillMetrics::NUM_FIELD_TYPE_QUALITY_METRICS <= UINT8_MAX, + "maximum field type quality metric must fit into 8 bits"); + static_assert(NUM_FIELD_TYPE_GROUPS_FOR_METRICS <= UINT8_MAX, + "number of field type groups must fit into 8 bits"); + return (group << 8) | metric; } namespace { @@ -268,40 +277,194 @@ histogram->AddTime(duration); } -// Logs a type quality metric. The primary histogram name is constructed based -// on |base_name|. The field-specific histogram name also factors in the -// |field_type|. Logs a sample of |metric|, which should be in the range -// [0, |num_possible_metrics|). May log a suffixed version of the metric -// depending on |metric_type|. -void LogTypeQualityMetric(const std::string& base_name, - AutofillMetrics::FieldTypeQualityMetric metric, - ServerFieldType field_type, - AutofillMetrics::QualityMetricType metric_type) { - DCHECK_LT(metric, AutofillMetrics::NUM_FIELD_TYPE_QUALITY_METRICS); - - std::string suffix; +const char* GetQualityMetricTypeSuffix( + AutofillMetrics::QualityMetricType metric_type) { switch (metric_type) { - case AutofillMetrics::TYPE_SUBMISSION: - break; - case AutofillMetrics::TYPE_NO_SUBMISSION: - suffix = ".NoSubmission"; - break; - case AutofillMetrics::TYPE_AUTOCOMPLETE_BASED: - suffix = ".BasedOnAutocomplete"; - break; default: NOTREACHED(); - } - LogUMAHistogramEnumeration(base_name + suffix, metric, - AutofillMetrics::NUM_FIELD_TYPE_QUALITY_METRICS); + // Fall through... - int field_type_group_metric = GetFieldTypeGroupMetric(field_type, metric); - int num_field_type_group_metrics = - AutofillMetrics::NUM_FIELD_TYPE_QUALITY_METRICS * - NUM_FIELD_TYPE_GROUPS_FOR_METRICS; - LogUMAHistogramEnumeration(base_name + ".ByFieldType" + suffix, - field_type_group_metric, - num_field_type_group_metrics); + case AutofillMetrics::TYPE_SUBMISSION: + return ""; + case AutofillMetrics::TYPE_NO_SUBMISSION: + return ".NoSubmission"; + case AutofillMetrics::TYPE_AUTOCOMPLETE_BASED: + return ".BasedOnAutocomplete"; + } +} + +// Given a set of |possible_types| for a field, select the best type to use as +// the "actual" field type when calculating metrics. If the |predicted_type| is +// among the |possible_types] then use that as the best type (i.e., the +// prediction is deemed to have been correct). +ServerFieldType GetActualFieldType(const ServerFieldTypeSet& possible_types, + ServerFieldType predicted_type) { + DCHECK_NE(possible_types.size(), 0u); + + if (possible_types.count(EMPTY_TYPE)) { + DCHECK_EQ(possible_types.size(), 1u); + return EMPTY_TYPE; + } + + if (possible_types.count(UNKNOWN_TYPE)) { + DCHECK_EQ(possible_types.size(), 1u); + return UNKNOWN_TYPE; + } + + if (possible_types.count(predicted_type)) + return predicted_type; + + // Collapse field types that Chrome treats as identical, e.g. home and + // billing address fields. + ServerFieldTypeSet collapsed_field_types; + for (const auto& type : possible_types) { + DCHECK_NE(type, EMPTY_TYPE); + DCHECK_NE(type, UNKNOWN_TYPE); + + // A phone number that's only missing its country code is (for metrics + // purposes) the same as the whole phone number. + if (type == PHONE_HOME_CITY_AND_NUMBER) + collapsed_field_types.insert(PHONE_HOME_WHOLE_NUMBER); + else + collapsed_field_types.insert(AutofillType(type).GetStorableType()); + } + + // Capture the field's type, if it is unambiguous. + ServerFieldType actual_type = AMBIGUOUS_TYPE; + if (collapsed_field_types.size() == 1) + actual_type = *collapsed_field_types.begin(); + + DVLOG(2) << "Inferred Type: " << AutofillType(actual_type).ToString(); + return actual_type; +} + +// Logs field type prediction quality metrics. The primary histogram name is +// constructed based on |source| The field-specific histogram name also factors +// possible and predicted field types (|possible_types| and |predicted_type|, +// respectively). May log a suffixed version of the metric depending on +// |metric_type|. +void LogPredictionQualityMetrics( + const base::StringPiece& source, + const ServerFieldTypeSet& possible_types, + ServerFieldType predicted_type, + AutofillMetrics::QualityMetricType metric_type) { + // Generate histogram names. + const char* const suffix = GetQualityMetricTypeSuffix(metric_type); + std::string raw_data_histogram = + base::JoinString({"Autofill.FieldPrediction.", source, suffix}, ""); + std::string aggregate_histogram = base::JoinString( + {"Autofill.FieldPredictionQuality.Aggregate.", source, suffix}, ""); + std::string type_specific_histogram = base::JoinString( + {"Autofill.FieldPredictionQuality.ByFieldType.", source, suffix}, ""); + + // Get the best type classification we can for the field. + ServerFieldType actual_type = + GetActualFieldType(possible_types, predicted_type); + + DVLOG(2) << "Predicted: " << AutofillType(predicted_type).ToString() << "; " + << "Actual: " << AutofillType(actual_type).ToString(); + + DCHECK_LE(predicted_type, UINT16_MAX); + DCHECK_LE(actual_type, UINT16_MAX); + UMA_HISTOGRAM_SPARSE_SLOWLY(raw_data_histogram, + (predicted_type << 16) | actual_type); + + // NO_SERVER_DATA is the equivalent of predicting UNKNOWN. + if (predicted_type == NO_SERVER_DATA) + predicted_type = UNKNOWN_TYPE; + + // The actual type being EMPTY_TYPE is the same as UNKNOWN_TYPE for comparison + // purposes, but remember whether or not it was empty for more precise logging + // later. + bool is_empty = (actual_type == EMPTY_TYPE); + bool is_ambiguous = (actual_type == AMBIGUOUS_TYPE); + if (is_empty || is_ambiguous) + actual_type = UNKNOWN_TYPE; + + // If the predicted and actual types match then it's either a true positive + // or a true negative (if they are both unknown). Do not log type specific + // true negatives (instead log a true positive for the "Ambiguous" type). + if (predicted_type == actual_type) { + if (actual_type == UNKNOWN_TYPE) { + // Only log aggregate true negative; do not log type specific metrics + // for UNKNOWN/EMPTY. + DVLOG(2) << "TRUE NEGATIVE"; + LogUMAHistogramEnumeration( + aggregate_histogram, + (is_empty ? AutofillMetrics::TRUE_NEGATIVE_EMPTY + : (is_ambiguous ? AutofillMetrics::TRUE_NEGATIVE_AMBIGUOUS + : AutofillMetrics::TRUE_NEGATIVE_UNKNOWN)), + AutofillMetrics::NUM_FIELD_TYPE_QUALITY_METRICS); + return; + } + + DVLOG(2) << "TRUE POSITIVE"; + // Log both aggregate and type specific true positive if we correctly + // predict that type with which the field was filled. + LogUMAHistogramEnumeration(aggregate_histogram, + AutofillMetrics::TRUE_POSITIVE, + AutofillMetrics::NUM_FIELD_TYPE_QUALITY_METRICS); + LogUMAHistogramEnumeration( + type_specific_histogram, + GetFieldTypeGroupMetric(actual_type, AutofillMetrics::TRUE_POSITIVE), + KMaxFieldTypeGroupMetric); + return; + } + + // Note: At this point predicted_type != actual type + // If actual type is UNKNOWN_TYPE then the prediction is a false positive. + // Further specialize the type of false positive by whether the field was + // empty or contained an unknown value. + if (actual_type == UNKNOWN_TYPE) { + DVLOG(2) << "FALSE POSITIVE"; + auto metric = + (is_empty ? AutofillMetrics::FALSE_POSITIVE_EMPTY + : (is_ambiguous ? AutofillMetrics::FALSE_POSITIVE_AMBIGUOUS + : AutofillMetrics::FALSE_POSITIVE_UNKNOWN)); + LogUMAHistogramEnumeration(aggregate_histogram, metric, + AutofillMetrics::NUM_FIELD_TYPE_QUALITY_METRICS); + LogUMAHistogramEnumeration(type_specific_histogram, + GetFieldTypeGroupMetric(predicted_type, metric), + KMaxFieldTypeGroupMetric); + return; + } + + // Note: At this point predicted_type != actual type, actual_type != UNKNOWN. + // If predicted type is UNKNOWN_TYPE then the prediction is a false negative + // unknown. + if (predicted_type == UNKNOWN_TYPE) { + DVLOG(2) << "FALSE NEGATIVE"; + LogUMAHistogramEnumeration(aggregate_histogram, + AutofillMetrics::FALSE_NEGATIVE_UNKNOWN, + AutofillMetrics::NUM_FIELD_TYPE_QUALITY_METRICS); + LogUMAHistogramEnumeration( + type_specific_histogram, + GetFieldTypeGroupMetric(actual_type, + AutofillMetrics::FALSE_NEGATIVE_UNKNOWN), + KMaxFieldTypeGroupMetric); + return; + } + + DVLOG(2) << "MISMATCH"; + + // Note: At this point predicted_type != actual type, actual_type != UNKNOWN, + // predicted_type != UNKNOWN. + // This is a mismatch. From the reference of the actual type, this is a false + // negative (it was T, but predicted U). From the reference of the prediction, + // this is a false positive (predicted it was T, but it was U). + LogUMAHistogramEnumeration(aggregate_histogram, + AutofillMetrics::FALSE_NEGATIVE_MISMATCH, + AutofillMetrics::NUM_FIELD_TYPE_QUALITY_METRICS); + LogUMAHistogramEnumeration( + type_specific_histogram, + GetFieldTypeGroupMetric(actual_type, + AutofillMetrics::FALSE_NEGATIVE_MISMATCH), + KMaxFieldTypeGroupMetric); + LogUMAHistogramEnumeration( + type_specific_histogram, + GetFieldTypeGroupMetric(predicted_type, + AutofillMetrics::FALSE_POSITIVE_MISMATCH), + KMaxFieldTypeGroupMetric); } } // namespace @@ -500,29 +663,28 @@ NUM_DEVELOPER_ENGAGEMENT_METRICS); } -// static -void AutofillMetrics::LogHeuristicTypePrediction( - FieldTypeQualityMetric metric, - ServerFieldType field_type, - QualityMetricType metric_type) { - LogTypeQualityMetric("Autofill.Quality.HeuristicType", metric, field_type, - metric_type); +void AutofillMetrics::LogHeuristicPredictionQualityMetrics( + const ServerFieldTypeSet& possible_types, + ServerFieldType predicted_type, + AutofillMetrics::QualityMetricType metric_type) { + LogPredictionQualityMetrics("Heuristic", possible_types, predicted_type, + metric_type); } -// static -void AutofillMetrics::LogOverallTypePrediction(FieldTypeQualityMetric metric, - ServerFieldType field_type, - QualityMetricType metric_type) { - LogTypeQualityMetric("Autofill.Quality.PredictedType", metric, field_type, - metric_type); +void AutofillMetrics::LogServerPredictionQualityMetrics( + const ServerFieldTypeSet& possible_types, + ServerFieldType predicted_type, + AutofillMetrics::QualityMetricType metric_type) { + LogPredictionQualityMetrics("Server", possible_types, predicted_type, + metric_type); } -// static -void AutofillMetrics::LogServerTypePrediction(FieldTypeQualityMetric metric, - ServerFieldType field_type, - QualityMetricType metric_type) { - LogTypeQualityMetric("Autofill.Quality.ServerType", metric, field_type, - metric_type); +void AutofillMetrics::LogOverallPredictionQualityMetrics( + const ServerFieldTypeSet& possible_types, + ServerFieldType predicted_type, + AutofillMetrics::QualityMetricType metric_type) { + LogPredictionQualityMetrics("Overall", possible_types, predicted_type, + metric_type); } // static
diff --git a/components/autofill/core/browser/autofill_metrics.h b/components/autofill/core/browser/autofill_metrics.h index 974f0cbf..d849ce1 100644 --- a/components/autofill/core/browser/autofill_metrics.h +++ b/components/autofill/core/browser/autofill_metrics.h
@@ -11,6 +11,7 @@ #include <vector> #include "base/macros.h" +#include "base/strings/string_piece_forward.h" #include "base/time/time.h" #include "components/autofill/core/browser/autofill_client.h" #include "components/autofill/core/browser/autofill_profile.h" @@ -319,33 +320,92 @@ NUM_SAVE_CARD_PROMPT_METRICS, }; - // Metrics measuring how well we predict field types. Exactly three such - // metrics are logged for each fillable field in a submitted form: for - // the heuristic prediction, for the crowd-sourced prediction, and for the - // overall prediction. + // Metrics measuring how well we predict field types. These metric values are + // logged for each field in a submitted form for: + // - the heuristic prediction + // - the crowd-sourced (server) prediction + // - for the overall prediction + // + // For each of these prediction types, these metrics are also logged by + // actual and predicted field type. enum FieldTypeQualityMetric { - // The field was found to be of type T, but autofill made no prediction. - TYPE_UNKNOWN = 0, // The field was found to be of type T, which matches the predicted type. - TYPE_MATCH, - // The field was found to be of type T, autofill predicted some other type. - TYPE_MISMATCH, - // The field was left empty and autofil predicted that the field type would - // be UNKNOWN. - TYPE_MATCH_EMPTY, - // The field was populated with data that did not match any part of the - // user's profile (it's type could not be determined). Autofill predicted - // the field's type would be UNKNOWN. - TYPE_MATCH_UNKNOWN, - // The field was left empty, autofill predicted the user would populate it - // with autofillable data. - TYPE_MISMATCH_EMPTY, - // The field was populated with data that did not match any part of the - // user's profile (it's type could not be determined). Autofill predicted - // the user would populate it with autofillable data. - TYPE_MISMATCH_UNKNOWN, - // This must be the last value. - NUM_FIELD_TYPE_QUALITY_METRICS, + // i.e. actual_type == predicted type == T + // + // This is captured as a type-specific log entry for T. Is is also captured + // as an aggregate (non-type-specific) log entry. + TRUE_POSITIVE = 0, + + // The field type is AMBIGUOUS and autofill made no prediction. + // i.e. actual_type == AMBIGUOUS,predicted type == UNKNOWN|NO_SERVER_DATA. + // + // This is captured as an aggregate (non-type-specific) log entry. It is + // NOT captured by type-specific logging. + TRUE_NEGATIVE_AMBIGUOUS, + + // The field type is UNKNOWN and autofill made no prediction. + // i.e. actual_type == UNKNOWN and predicted type == UNKNOWN|NO_SERVER_DATA. + // + // This is captured as an aggregate (non-type-specific) log entry. It is + // NOT captured by type-specific logging. + TRUE_NEGATIVE_UNKNOWN, + + // The field type is EMPTY and autofill predicted UNKNOWN + // i.e. actual_type == EMPTY and predicted type == UNKNOWN|NO_SERVER_DATA. + // + // This is captured as an aggregate (non-type-specific) log entry. It is + // NOT captured by type-specific logging. + TRUE_NEGATIVE_EMPTY, + + // Autofill predicted type T, but the field actually had a different type. + // i.e., actual_type == T, predicted_type = U, T != U, + // UNKNOWN not in (T,U). + // + // This is captured as a type-specific log entry for U. It is NOT captured + // as an aggregate (non-type-specific) entry as this would double count with + // FALSE_NEGATIVE_MISMATCH logging captured for T. + FALSE_POSITIVE_MISMATCH, + + // Autofill predicted type T, but the field actually matched multiple + // pieces of autofill data, none of which are T. + // i.e., predicted_type == T, actual_type = {U, V, ...), + // T not in {U, V, ...}. + // + // This is captured as a type-specific log entry for T. It is also captured + // as an aggregate (non-type-specific) log entry. + FALSE_POSITIVE_AMBIGUOUS, + + // The field type is UNKNOWN, but autofill predicted it to be of type T. + // i.e., actual_type == UNKNOWN, predicted_type = T, T != UNKNOWN + // + // This is captured as a type-specific log entry for T. Is is also captured + // as an aggregate (non-type-specific) log entry. + FALSE_POSITIVE_UNKNOWN, + + // The field type is EMPTY, but autofill predicted it to be of type T. + // i.e., actual_type == EMPTY, predicted_type = T, T != UNKNOWN + // + // This is captured as a type-specific log entry for T. Is is also captured + // as an aggregate (non-type-specific) log entry. + FALSE_POSITIVE_EMPTY, + + // The field is of type T, but autofill did not make a type prediction. + // i.e., actual_type == T, predicted_type = UNKNOWN, T != UNKNOWN. + // + // This is captured as a type-specific log entry for T. Is is also captured + // as an aggregate (non-type-specific) log entry. + FALSE_NEGATIVE_UNKNOWN, + + // The field is of type T, but autofill predicted it to be of type U. + // i.e., actual_type == T, predicted_type = U, T != U, + // UNKNOWN not in (T,U). + // + // This is captured as a type-specific log entry for T. Is is also captured + // as an aggregate (non-type-specific) log entry. + FALSE_NEGATIVE_MISMATCH, + + // This must be last. + NUM_FIELD_TYPE_QUALITY_METRICS }; enum QualityMetricType { @@ -675,15 +735,18 @@ static void LogDeveloperEngagementMetric(DeveloperEngagementMetric metric); - static void LogHeuristicTypePrediction(FieldTypeQualityMetric metric, - ServerFieldType field_type, - QualityMetricType metric_type); - static void LogOverallTypePrediction(FieldTypeQualityMetric metric, - ServerFieldType field_type, - QualityMetricType metric_type); - static void LogServerTypePrediction(FieldTypeQualityMetric metric, - ServerFieldType field_type, - QualityMetricType metric_type); + static void LogHeuristicPredictionQualityMetrics( + const ServerFieldTypeSet& possible_types, + ServerFieldType predicted_type, + QualityMetricType metric_type); + static void LogServerPredictionQualityMetrics( + const ServerFieldTypeSet& possible_types, + ServerFieldType predicted_type, + QualityMetricType metric_type); + static void LogOverallPredictionQualityMetrics( + const ServerFieldTypeSet& possible_types, + ServerFieldType predicted_type, + QualityMetricType metric_type); static void LogServerQueryMetric(ServerQueryMetric metric);
diff --git a/components/autofill/core/browser/autofill_metrics_unittest.cc b/components/autofill/core/browser/autofill_metrics_unittest.cc index 2e0eee8..65c3b283f 100644 --- a/components/autofill/core/browser/autofill_metrics_unittest.cc +++ b/components/autofill/core/browser/autofill_metrics_unittest.cc
@@ -189,6 +189,19 @@ bool IsAutofillEnabled() const override { return autofill_enabled_; } + void CreateAmbiguousProfiles() { + web_profiles_.clear(); + CreateTestAutofillProfiles(&web_profiles_); + + auto profile = base::MakeUnique<AutofillProfile>(); + test::SetProfileInfo(profile.get(), "John", "Decca", "Public", + "john@gmail.com", "Company", "123 Main St.", "unit 7", + "Springfield", "Texas", "79401", "US", "2345678901"); + profile->set_guid("00000000-0000-0000-0000-000000000003"); + web_profiles_.push_back(std::move(profile)); + Refresh(); + } + private: void CreateTestAutofillProfiles( std::vector<std::unique_ptr<AutofillProfile>>* profiles) { @@ -522,111 +535,259 @@ autofill_manager_->SubmitForm(form, TimeTicks::Now()); // Heuristic predictions. - // Unknown: - histogram_tester.ExpectBucketCount("Autofill.Quality.HeuristicType", - AutofillMetrics::TYPE_UNKNOWN, 1); - histogram_tester.ExpectBucketCount( - "Autofill.Quality.HeuristicType.ByFieldType", - GetFieldTypeGroupMetric(ADDRESS_HOME_COUNTRY, - AutofillMetrics::TYPE_UNKNOWN), - 1); - // Match: - histogram_tester.ExpectBucketCount("Autofill.Quality.HeuristicType", - AutofillMetrics::TYPE_MATCH, 2); - histogram_tester.ExpectBucketCount( - "Autofill.Quality.HeuristicType.ByFieldType", - GetFieldTypeGroupMetric(NAME_FULL, AutofillMetrics::TYPE_MATCH), 1); - histogram_tester.ExpectBucketCount( - "Autofill.Quality.HeuristicType.ByFieldType", - GetFieldTypeGroupMetric(PHONE_HOME_CITY_AND_NUMBER, - AutofillMetrics::TYPE_MATCH), - 1); - // Mismatch: - histogram_tester.ExpectBucketCount("Autofill.Quality.HeuristicType", - AutofillMetrics::TYPE_MISMATCH, 1); - histogram_tester.ExpectBucketCount( - "Autofill.Quality.HeuristicType.ByFieldType", - GetFieldTypeGroupMetric(EMAIL_ADDRESS, AutofillMetrics::TYPE_MISMATCH), - 1); + { + std::string aggregate_histogram = + "Autofill.FieldPredictionQuality.Aggregate.Heuristic"; + std::string by_field_type_histogram = + "Autofill.FieldPredictionQuality.ByFieldType.Heuristic"; - // Server predictions: - // Unknown: - histogram_tester.ExpectBucketCount("Autofill.Quality.ServerType", - AutofillMetrics::TYPE_UNKNOWN, 1); - histogram_tester.ExpectBucketCount( - "Autofill.Quality.ServerType.ByFieldType", - GetFieldTypeGroupMetric(ADDRESS_HOME_COUNTRY, - AutofillMetrics::TYPE_UNKNOWN), - 1); - // Match: - histogram_tester.ExpectBucketCount("Autofill.Quality.ServerType", - AutofillMetrics::TYPE_MATCH, 2); - histogram_tester.ExpectBucketCount( - "Autofill.Quality.ServerType.ByFieldType", - GetFieldTypeGroupMetric(EMAIL_ADDRESS, AutofillMetrics::TYPE_MATCH), 1); - histogram_tester.ExpectBucketCount( - "Autofill.Quality.ServerType.ByFieldType", - GetFieldTypeGroupMetric(PHONE_HOME_WHOLE_NUMBER, - AutofillMetrics::TYPE_MATCH), - 1); - // Mismatch: - histogram_tester.ExpectBucketCount("Autofill.Quality.ServerType", - AutofillMetrics::TYPE_MISMATCH, 1); - histogram_tester.ExpectBucketCount( - "Autofill.Quality.ServerType.ByFieldType", - GetFieldTypeGroupMetric(NAME_FULL, AutofillMetrics::TYPE_MISMATCH), 1); + // Unknown: + histogram_tester.ExpectBucketCount( + aggregate_histogram, AutofillMetrics::FALSE_NEGATIVE_UNKNOWN, 1); + histogram_tester.ExpectBucketCount( + by_field_type_histogram, + GetFieldTypeGroupMetric(ADDRESS_HOME_COUNTRY, + AutofillMetrics::FALSE_NEGATIVE_UNKNOWN), + 1); + // Match: + histogram_tester.ExpectBucketCount(aggregate_histogram, + AutofillMetrics::TRUE_POSITIVE, 2); + histogram_tester.ExpectBucketCount( + by_field_type_histogram, + GetFieldTypeGroupMetric(NAME_FULL, AutofillMetrics::TRUE_POSITIVE), 1); + histogram_tester.ExpectBucketCount( + by_field_type_histogram, + GetFieldTypeGroupMetric(PHONE_HOME_CITY_AND_NUMBER, + AutofillMetrics::TRUE_POSITIVE), + 1); + // Mismatch: + histogram_tester.ExpectBucketCount( + aggregate_histogram, AutofillMetrics::FALSE_NEGATIVE_MISMATCH, 1); + histogram_tester.ExpectBucketCount( + by_field_type_histogram, + GetFieldTypeGroupMetric(EMAIL_ADDRESS, + AutofillMetrics::FALSE_NEGATIVE_MISMATCH), + 1); + histogram_tester.ExpectBucketCount( + by_field_type_histogram, + GetFieldTypeGroupMetric(PHONE_HOME_NUMBER, + AutofillMetrics::FALSE_POSITIVE_MISMATCH), + 1); + // False Positive Unknown: + histogram_tester.ExpectBucketCount( + aggregate_histogram, AutofillMetrics::FALSE_POSITIVE_UNKNOWN, 1); + histogram_tester.ExpectBucketCount( + by_field_type_histogram, + GetFieldTypeGroupMetric(PHONE_HOME_NUMBER, + AutofillMetrics::FALSE_POSITIVE_UNKNOWN), + 1); + // False Positive Empty: + histogram_tester.ExpectBucketCount( + aggregate_histogram, AutofillMetrics::FALSE_POSITIVE_EMPTY, 1); + histogram_tester.ExpectBucketCount( + by_field_type_histogram, + GetFieldTypeGroupMetric(NAME_FULL, + AutofillMetrics::FALSE_POSITIVE_EMPTY), + 1); - // Overall predictions: - // Unknown: - histogram_tester.ExpectBucketCount("Autofill.Quality.PredictedType", - AutofillMetrics::TYPE_UNKNOWN, 1); - histogram_tester.ExpectBucketCount( - "Autofill.Quality.PredictedType.ByFieldType", - GetFieldTypeGroupMetric(ADDRESS_HOME_COUNTRY, - AutofillMetrics::TYPE_UNKNOWN), - 1); - // Match: - histogram_tester.ExpectBucketCount("Autofill.Quality.PredictedType", - AutofillMetrics::TYPE_MATCH, 2); - histogram_tester.ExpectBucketCount( - "Autofill.Quality.PredictedType.ByFieldType", - GetFieldTypeGroupMetric(EMAIL_ADDRESS, AutofillMetrics::TYPE_MATCH), 1); - histogram_tester.ExpectBucketCount( - "Autofill.Quality.PredictedType.ByFieldType", - GetFieldTypeGroupMetric(PHONE_HOME_WHOLE_NUMBER, - AutofillMetrics::TYPE_MATCH), - 1); - // Mismatch: - histogram_tester.ExpectBucketCount("Autofill.Quality.PredictedType", - AutofillMetrics::TYPE_MISMATCH, 1); - histogram_tester.ExpectBucketCount( - "Autofill.Quality.PredictedType.ByFieldType", - GetFieldTypeGroupMetric(NAME_FULL, AutofillMetrics::TYPE_MISMATCH), 1); + // Sanity Check: + histogram_tester.ExpectTotalCount(aggregate_histogram, 6); + histogram_tester.ExpectTotalCount(by_field_type_histogram, 7); + } + + // Server overrides heuristic so Overall and Server are the same predictions + // (as there were no test fields where server == NO_SERVER_DATA and heuristic + // != UNKNOWN_TYPE). + for (const std::string source : {"Server", "Overall"}) { + std::string aggregate_histogram = + "Autofill.FieldPredictionQuality.Aggregate." + source; + std::string by_field_type_histogram = + "Autofill.FieldPredictionQuality.ByFieldType." + source; + + // Unknown: + histogram_tester.ExpectBucketCount( + aggregate_histogram, AutofillMetrics::FALSE_NEGATIVE_UNKNOWN, 1); + histogram_tester.ExpectBucketCount( + by_field_type_histogram, + GetFieldTypeGroupMetric(ADDRESS_HOME_COUNTRY, + AutofillMetrics::FALSE_NEGATIVE_UNKNOWN), + 1); + // Match: + histogram_tester.ExpectBucketCount(aggregate_histogram, + AutofillMetrics::TRUE_POSITIVE, 2); + histogram_tester.ExpectBucketCount( + by_field_type_histogram, + GetFieldTypeGroupMetric(EMAIL_ADDRESS, AutofillMetrics::TRUE_POSITIVE), + 1); + histogram_tester.ExpectBucketCount( + by_field_type_histogram, + GetFieldTypeGroupMetric(PHONE_HOME_WHOLE_NUMBER, + AutofillMetrics::TRUE_POSITIVE), + 1); + // Mismatch: + histogram_tester.ExpectBucketCount( + aggregate_histogram, AutofillMetrics::FALSE_NEGATIVE_MISMATCH, 1); + histogram_tester.ExpectBucketCount( + by_field_type_histogram, + GetFieldTypeGroupMetric(NAME_FULL, + AutofillMetrics::FALSE_NEGATIVE_MISMATCH), + 1); + histogram_tester.ExpectBucketCount( + by_field_type_histogram, + GetFieldTypeGroupMetric(NAME_FIRST, + AutofillMetrics::FALSE_POSITIVE_MISMATCH), + 1); + + // False Positive Unknown: + histogram_tester.ExpectBucketCount( + aggregate_histogram, AutofillMetrics::FALSE_POSITIVE_UNKNOWN, 1); + histogram_tester.ExpectBucketCount( + by_field_type_histogram, + GetFieldTypeGroupMetric(EMAIL_ADDRESS, + AutofillMetrics::FALSE_POSITIVE_UNKNOWN), + 1); + // False Positive Empty: + histogram_tester.ExpectBucketCount( + aggregate_histogram, AutofillMetrics::FALSE_POSITIVE_EMPTY, 1); + histogram_tester.ExpectBucketCount( + by_field_type_histogram, + GetFieldTypeGroupMetric(NAME_FIRST, + AutofillMetrics::FALSE_POSITIVE_EMPTY), + 1); + + // Sanity Check: + histogram_tester.ExpectTotalCount(aggregate_histogram, 6); + histogram_tester.ExpectTotalCount(by_field_type_histogram, 7); + } } // Tests the true negatives (empty + no prediction and unknown + no prediction) // and false positives (empty + bad prediction and unknown + bad prediction) // are counted correctly. -struct UnrecognizedOrEmptyFieldsCase { +struct QualityMetricsTestCase { + const ServerFieldType predicted_field_type; const ServerFieldType actual_field_type; - const bool make_prediction; - const AutofillMetrics::FieldTypeQualityMetric metric_to_test; }; -class UnrecognizedOrEmptyFieldsTest +class QualityMetricsTest : public AutofillMetricsTest, - public testing::WithParamInterface<UnrecognizedOrEmptyFieldsCase> {}; + public testing::WithParamInterface<QualityMetricsTestCase> { + public: + const char* ValueForType(ServerFieldType type) { + switch (type) { + case EMPTY_TYPE: + return ""; + case UNKNOWN_TYPE: + return "unknown"; + case COMPANY_NAME: + return "RCA"; + case NAME_FIRST: + return "Elvis"; + case NAME_MIDDLE: + return "Aaron"; + case NAME_LAST: + return "Presley"; + case NAME_FULL: + return "Elvis Aaron Presley"; + case EMAIL_ADDRESS: + return "buddy@gmail.com"; + case PHONE_HOME_NUMBER: + case PHONE_HOME_WHOLE_NUMBER: + case PHONE_HOME_CITY_AND_NUMBER: + return "2345678901"; + case ADDRESS_HOME_STREET_ADDRESS: + return "123 Apple St.\nunit 6"; + case ADDRESS_HOME_LINE1: + return "123 Apple St."; + case ADDRESS_HOME_LINE2: + return "unit 6"; + case ADDRESS_HOME_CITY: + return "Lubbock"; + case ADDRESS_HOME_STATE: + return "Texas"; + case ADDRESS_HOME_ZIP: + return "79401"; + case ADDRESS_HOME_COUNTRY: + return "US"; + case AMBIGUOUS_TYPE: + // This occurs as both a company name and a middle name once ambiguous + // profiles are created. + personal_data_->CreateAmbiguousProfiles(); + return "Decca"; -TEST_P(UnrecognizedOrEmptyFieldsTest, QualityMetrics) { + default: + NOTREACHED(); // Fall through + return "unexpected!"; + } + } + + bool IsExampleOf(AutofillMetrics::FieldTypeQualityMetric metric, + ServerFieldType predicted_type, + ServerFieldType actual_type) { + switch (metric) { + case AutofillMetrics::TRUE_POSITIVE: + return unknown_equivalent_types_.count(actual_type) == 0 && + predicted_type == actual_type; + + case AutofillMetrics::TRUE_NEGATIVE_AMBIGUOUS: + return actual_type == AMBIGUOUS_TYPE && predicted_type == UNKNOWN_TYPE; + + case AutofillMetrics::TRUE_NEGATIVE_UNKNOWN: + return actual_type == UNKNOWN_TYPE && predicted_type == UNKNOWN_TYPE; + + case AutofillMetrics::TRUE_NEGATIVE_EMPTY: + return actual_type == EMPTY_TYPE && predicted_type == UNKNOWN_TYPE; + + case AutofillMetrics::FALSE_POSITIVE_AMBIGUOUS: + return actual_type == AMBIGUOUS_TYPE && predicted_type != UNKNOWN_TYPE; + + case AutofillMetrics::FALSE_POSITIVE_UNKNOWN: + return actual_type == UNKNOWN_TYPE && predicted_type != UNKNOWN_TYPE; + + case AutofillMetrics::FALSE_POSITIVE_EMPTY: + return actual_type == EMPTY_TYPE && predicted_type != UNKNOWN_TYPE; + + // False negative mismatch and false positive mismatch trigger on the same + // conditions: + // - False positive prediction of predicted type + // - False negative prediction of actual type + case AutofillMetrics::FALSE_POSITIVE_MISMATCH: + case AutofillMetrics::FALSE_NEGATIVE_MISMATCH: + return unknown_equivalent_types_.count(actual_type) == 0 && + actual_type != predicted_type && predicted_type != UNKNOWN_TYPE; + + case AutofillMetrics::FALSE_NEGATIVE_UNKNOWN: + return unknown_equivalent_types_.count(actual_type) == 0 && + actual_type != predicted_type && predicted_type == UNKNOWN_TYPE; + + default: + NOTREACHED(); + } + return false; + } + + static int FieldTypeCross(ServerFieldType predicted_type, + ServerFieldType actual_type) { + EXPECT_LE(predicted_type, UINT16_MAX); + EXPECT_LE(actual_type, UINT16_MAX); + return (predicted_type << 16) | actual_type; + } + + const ServerFieldTypeSet unknown_equivalent_types_{UNKNOWN_TYPE, EMPTY_TYPE, + AMBIGUOUS_TYPE}; +}; + +TEST_P(QualityMetricsTest, Classification) { + const std::vector<std::string> prediction_sources{"Heuristic", "Server", + "Overall"}; // Setup the test parameters. - const ServerFieldType actual_field_type = GetParam().actual_field_type; - const ServerFieldType heuristic_type = - GetParam().make_prediction ? EMAIL_ADDRESS : UNKNOWN_TYPE; - const ServerFieldType server_type = - GetParam().make_prediction ? EMAIL_ADDRESS : NO_SERVER_DATA; - const AutofillMetrics::FieldTypeQualityMetric metric_to_test = - GetParam().metric_to_test; + ServerFieldType actual_field_type = GetParam().actual_field_type; + ServerFieldType predicted_type = GetParam().predicted_field_type; + + VLOG(2) << "Test Case = Predicted: " + << AutofillType(predicted_type).ToString() << "; " + << "Actual: " << AutofillType(actual_field_type).ToString(); // Set up our form data. FormData form; @@ -638,27 +799,26 @@ AutofillField field; // Add a first name field, that is predicted correctly. - test::CreateTestFormField("first", "first", "Elvis", "text", &field); - field.set_possible_types({NAME_FIRST}); + test::CreateTestFormField("first", "first", ValueForType(NAME_FIRST), "text", + &field); form.fields.push_back(field); heuristic_types.push_back(NAME_FIRST); server_types.push_back(NAME_FIRST); // Add a last name field, that is predicted correctly. - test::CreateTestFormField("last", "last", "Presley", "test", &field); - field.set_possible_types({NAME_LAST}); + test::CreateTestFormField("last", "last", ValueForType(NAME_LAST), "test", + &field); form.fields.push_back(field); heuristic_types.push_back(NAME_LAST); server_types.push_back(NAME_LAST); // Add an empty or unknown field, that is predicted as per the test params. test::CreateTestFormField("Unknown", "Unknown", - (actual_field_type == EMPTY_TYPE ? "" : "unknown"), - "text", &field); - field.set_possible_types({actual_field_type}); + ValueForType(actual_field_type), "text", &field); form.fields.push_back(field); - heuristic_types.push_back(heuristic_type); - server_types.push_back(server_type); + heuristic_types.push_back(predicted_type); + server_types.push_back(predicted_type == UNKNOWN_TYPE ? NO_SERVER_DATA + : predicted_type); // Simulate having seen this form on page load. autofill_manager_->AddSeenForm(form, heuristic_types, server_types); @@ -667,65 +827,122 @@ base::HistogramTester histogram_tester; autofill_manager_->SubmitForm(form, TimeTicks::Now()); - // Validate the histogram counter values. + // Resolve any field type ambiguity. + if (actual_field_type == AMBIGUOUS_TYPE) { + if (predicted_type == COMPANY_NAME || predicted_type == NAME_MIDDLE) + actual_field_type = predicted_type; + } + + // Validate the total samples and the crossed (predicted-to-actual) samples. + for (const auto& source : prediction_sources) { + const std::string crossed_histogram = "Autofill.FieldPrediction." + source; + const std::string aggregate_histogram = + "Autofill.FieldPredictionQuality.Aggregate." + source; + const std::string by_field_type_histogram = + "Autofill.FieldPredictionQuality.ByFieldType." + source; + + // Sanity Check: + histogram_tester.ExpectTotalCount(crossed_histogram, 3); + histogram_tester.ExpectTotalCount(aggregate_histogram, 3); + histogram_tester.ExpectTotalCount( + by_field_type_histogram, + 2 + + (predicted_type != UNKNOWN_TYPE && + predicted_type != actual_field_type) + + (unknown_equivalent_types_.count(actual_field_type) == 0)); + + // The Crossed Histogram: + histogram_tester.ExpectBucketCount( + crossed_histogram, FieldTypeCross(NAME_FIRST, NAME_FIRST), 1); + histogram_tester.ExpectBucketCount(crossed_histogram, + FieldTypeCross(NAME_LAST, NAME_LAST), 1); + histogram_tester.ExpectBucketCount( + crossed_histogram, + FieldTypeCross((source == "Server" && predicted_type == UNKNOWN_TYPE + ? NO_SERVER_DATA + : predicted_type), + actual_field_type), + 1); + } + + // Validate the individual histogram counter values. for (int i = 0; i < AutofillMetrics::NUM_FIELD_TYPE_QUALITY_METRICS; ++i) { // The metric enum value we're currently examining. auto metric = static_cast<AutofillMetrics::FieldTypeQualityMetric>(i); - // For the overall metric counts... - // If the current metric is the metric we're testing, then we expect its - // count to be 1. Otherwise, the metric's count should be zero (0) except - // for the TYPE_MATCH metric which should be 2 (because of the matching - // first and last name fields) - int overall_expected_count = - (metric == metric_to_test) - ? 1 - : ((metric == AutofillMetrics::TYPE_MATCH) ? 2 : 0); + // The type specific expected count is 1 if (predicted, actual) is an + // example + int basic_expected_count = + IsExampleOf(metric, predicted_type, actual_field_type) ? 1 : 0; - histogram_tester.ExpectBucketCount("Autofill.Quality.HeuristicType", metric, - overall_expected_count); - histogram_tester.ExpectBucketCount("Autofill.Quality.ServerType", metric, - overall_expected_count); - histogram_tester.ExpectBucketCount("Autofill.Quality.PredictedType", metric, - overall_expected_count); + // For aggregate metrics don't capture aggregate FALSE_POSITIVE_MISMATCH. + // Note there are two true positive values (first and last name) hard- + // coded into the test. + int aggregate_expected_count = + (metric == AutofillMetrics::TRUE_POSITIVE ? 2 : 0) + + (metric == AutofillMetrics::FALSE_POSITIVE_MISMATCH + ? 0 + : basic_expected_count); - // For the ByFieldType metric counts... - // We only examine the counter for the field_type being tested. If the - // current metric is the metric we're testing, then we expect its - // count to be 1 otherwise it should be 0. - int field_type_expected_count = (metric == metric_to_test) ? 1 : 0; + // If this test exercises the ambiguous middle name match, then validation + // of the name-specific metrics must include the true-positives created by + // the first and last name fields. + if (metric == AutofillMetrics::TRUE_POSITIVE && + predicted_type == NAME_MIDDLE && actual_field_type == NAME_MIDDLE) { + basic_expected_count += 2; + } - histogram_tester.ExpectBucketCount( - "Autofill.Quality.HeuristicType.ByFieldType", - GetFieldTypeGroupMetric(actual_field_type, metric), - field_type_expected_count); - histogram_tester.ExpectBucketCount( - "Autofill.Quality.ServerType.ByFieldType", - GetFieldTypeGroupMetric(actual_field_type, metric), - field_type_expected_count); - histogram_tester.ExpectBucketCount( - "Autofill.Quality.PredictedType.ByFieldType", - GetFieldTypeGroupMetric(actual_field_type, metric), - field_type_expected_count); + // For metrics keyed to the actual field type, we don't capture unknown, + // empty or ambiguous and we don't capture false positive mismatches. + int expected_count_for_actual_type = + (unknown_equivalent_types_.count(actual_field_type) == 0 && + metric != AutofillMetrics::FALSE_POSITIVE_MISMATCH) + ? basic_expected_count + : 0; + + // For metrics keyed to the predicted field type, we don't capture unknown + // (empty is not a predictable value) and we don't capture false negative + // mismatches. + int expected_count_for_predicted_type = + (predicted_type != UNKNOWN_TYPE && + metric != AutofillMetrics::FALSE_NEGATIVE_MISMATCH) + ? basic_expected_count + : 0; + + for (const auto& source : prediction_sources) { + std::string aggregate_histogram = + "Autofill.FieldPredictionQuality.Aggregate." + source; + std::string by_field_type_histogram = + "Autofill.FieldPredictionQuality.ByFieldType." + source; + histogram_tester.ExpectBucketCount(aggregate_histogram, metric, + aggregate_expected_count); + histogram_tester.ExpectBucketCount( + by_field_type_histogram, + GetFieldTypeGroupMetric(actual_field_type, metric), + expected_count_for_actual_type); + histogram_tester.ExpectBucketCount( + by_field_type_histogram, + GetFieldTypeGroupMetric(predicted_type, metric), + expected_count_for_predicted_type); + } } } INSTANTIATE_TEST_CASE_P( AutofillMetricsTest, - UnrecognizedOrEmptyFieldsTest, - testing::Values( - UnrecognizedOrEmptyFieldsCase{EMPTY_TYPE, - /* make_prediction = */ false, - AutofillMetrics::TYPE_MATCH_EMPTY}, - UnrecognizedOrEmptyFieldsCase{UNKNOWN_TYPE, - /* make_prediction = */ false, - AutofillMetrics::TYPE_MATCH_UNKNOWN}, - UnrecognizedOrEmptyFieldsCase{EMPTY_TYPE, - /* make_prediction = */ true, - AutofillMetrics::TYPE_MISMATCH_EMPTY}, - UnrecognizedOrEmptyFieldsCase{UNKNOWN_TYPE, - /* make_prediction = */ true, - AutofillMetrics::TYPE_MISMATCH_UNKNOWN})); + QualityMetricsTest, + testing::Values(QualityMetricsTestCase{UNKNOWN_TYPE, EMPTY_TYPE}, + QualityMetricsTestCase{UNKNOWN_TYPE, UNKNOWN_TYPE}, + QualityMetricsTestCase{UNKNOWN_TYPE, AMBIGUOUS_TYPE}, + QualityMetricsTestCase{UNKNOWN_TYPE, EMAIL_ADDRESS}, + QualityMetricsTestCase{EMAIL_ADDRESS, EMPTY_TYPE}, + QualityMetricsTestCase{EMAIL_ADDRESS, UNKNOWN_TYPE}, + QualityMetricsTestCase{EMAIL_ADDRESS, AMBIGUOUS_TYPE}, + QualityMetricsTestCase{EMAIL_ADDRESS, EMAIL_ADDRESS}, + QualityMetricsTestCase{EMAIL_ADDRESS, COMPANY_NAME}, + QualityMetricsTestCase{COMPANY_NAME, EMAIL_ADDRESS}, + QualityMetricsTestCase{NAME_MIDDLE, AMBIGUOUS_TYPE}, + QualityMetricsTestCase{COMPANY_NAME, AMBIGUOUS_TYPE})); // Ensures that metrics that measure timing some important Autofill functions // actually are recorded and retrieved. @@ -831,92 +1048,127 @@ autofill_manager_->RunRunLoop(); // Heuristic predictions. - // Unknown: - histogram_tester.ExpectBucketCount( - "Autofill.Quality.HeuristicType.NoSubmission", - AutofillMetrics::TYPE_UNKNOWN, 1); - histogram_tester.ExpectBucketCount( - "Autofill.Quality.HeuristicType.ByFieldType.NoSubmission", - GetFieldTypeGroupMetric(ADDRESS_HOME_COUNTRY, - AutofillMetrics::TYPE_UNKNOWN), - 1); - // Match: - histogram_tester.ExpectBucketCount( - "Autofill.Quality.HeuristicType.NoSubmission", - AutofillMetrics::TYPE_MATCH, 2); - histogram_tester.ExpectBucketCount( - "Autofill.Quality.HeuristicType.ByFieldType.NoSubmission", - GetFieldTypeGroupMetric(NAME_FULL, AutofillMetrics::TYPE_MATCH), 1); - histogram_tester.ExpectBucketCount( - "Autofill.Quality.HeuristicType.ByFieldType.NoSubmission", - GetFieldTypeGroupMetric(PHONE_HOME_WHOLE_NUMBER, - AutofillMetrics::TYPE_MATCH), - 1); - // Mismatch: - histogram_tester.ExpectBucketCount( - "Autofill.Quality.HeuristicType.NoSubmission", - AutofillMetrics::TYPE_MISMATCH, 1); - histogram_tester.ExpectBucketCount( - "Autofill.Quality.HeuristicType.ByFieldType.NoSubmission", - GetFieldTypeGroupMetric(EMAIL_ADDRESS, AutofillMetrics::TYPE_MISMATCH), - 1); + { + std::string aggregate_histogram = + "Autofill.FieldPredictionQuality.Aggregate.Heuristic.NoSubmission"; + std::string by_field_type_histogram = + "Autofill.FieldPredictionQuality.ByFieldType.Heuristic.NoSubmission"; + // False Negative: + histogram_tester.ExpectBucketCount( + aggregate_histogram, AutofillMetrics::FALSE_NEGATIVE_UNKNOWN, 1); + histogram_tester.ExpectBucketCount( + by_field_type_histogram, + GetFieldTypeGroupMetric(ADDRESS_HOME_COUNTRY, + AutofillMetrics::FALSE_NEGATIVE_UNKNOWN), + 1); + // Match: + histogram_tester.ExpectBucketCount(aggregate_histogram, + AutofillMetrics::TRUE_POSITIVE, 2); + histogram_tester.ExpectBucketCount( + by_field_type_histogram, + GetFieldTypeGroupMetric(NAME_FULL, AutofillMetrics::TRUE_POSITIVE), 1); + histogram_tester.ExpectBucketCount( + by_field_type_histogram, + GetFieldTypeGroupMetric(PHONE_HOME_WHOLE_NUMBER, + AutofillMetrics::TRUE_POSITIVE), + 1); + // Mismatch: + histogram_tester.ExpectBucketCount( + aggregate_histogram, AutofillMetrics::FALSE_NEGATIVE_MISMATCH, 1); + histogram_tester.ExpectBucketCount( + by_field_type_histogram, + GetFieldTypeGroupMetric(EMAIL_ADDRESS, + AutofillMetrics::FALSE_NEGATIVE_MISMATCH), + 1); + histogram_tester.ExpectBucketCount( + by_field_type_histogram, + GetFieldTypeGroupMetric(PHONE_HOME_NUMBER, + AutofillMetrics::FALSE_POSITIVE_MISMATCH), + 1); + // False Positives: + histogram_tester.ExpectBucketCount( + aggregate_histogram, AutofillMetrics::FALSE_POSITIVE_EMPTY, 1); + histogram_tester.ExpectBucketCount( + by_field_type_histogram, + GetFieldTypeGroupMetric(NAME_FULL, + AutofillMetrics::FALSE_POSITIVE_EMPTY), + 1); + histogram_tester.ExpectBucketCount( + aggregate_histogram, AutofillMetrics::FALSE_POSITIVE_UNKNOWN, 1); + histogram_tester.ExpectBucketCount( + by_field_type_histogram, + GetFieldTypeGroupMetric(PHONE_HOME_NUMBER, + AutofillMetrics::FALSE_POSITIVE_UNKNOWN), + 1); - // Server predictions: - // Unknown: - histogram_tester.ExpectBucketCount("Autofill.Quality.ServerType.NoSubmission", - AutofillMetrics::TYPE_UNKNOWN, 1); - histogram_tester.ExpectBucketCount( - "Autofill.Quality.ServerType.ByFieldType.NoSubmission", - GetFieldTypeGroupMetric(ADDRESS_HOME_COUNTRY, - AutofillMetrics::TYPE_UNKNOWN), - 1); - // Match: - histogram_tester.ExpectBucketCount("Autofill.Quality.ServerType.NoSubmission", - AutofillMetrics::TYPE_MATCH, 2); - histogram_tester.ExpectBucketCount( - "Autofill.Quality.ServerType.ByFieldType.NoSubmission", - GetFieldTypeGroupMetric(EMAIL_ADDRESS, AutofillMetrics::TYPE_MATCH), 1); - histogram_tester.ExpectBucketCount( - "Autofill.Quality.ServerType.ByFieldType.NoSubmission", - GetFieldTypeGroupMetric(PHONE_HOME_WHOLE_NUMBER, - AutofillMetrics::TYPE_MATCH), - 1); - // Mismatch: - histogram_tester.ExpectBucketCount("Autofill.Quality.ServerType.NoSubmission", - AutofillMetrics::TYPE_MISMATCH, 1); - histogram_tester.ExpectBucketCount( - "Autofill.Quality.ServerType.ByFieldType.NoSubmission", - GetFieldTypeGroupMetric(NAME_FULL, AutofillMetrics::TYPE_MISMATCH), 1); + // Sanity Check: + histogram_tester.ExpectTotalCount(aggregate_histogram, 6); + histogram_tester.ExpectTotalCount(by_field_type_histogram, 7); + } - // Overall predictions: - // Unknown: - histogram_tester.ExpectBucketCount( - "Autofill.Quality.PredictedType.NoSubmission", - AutofillMetrics::TYPE_UNKNOWN, 1); - histogram_tester.ExpectBucketCount( - "Autofill.Quality.PredictedType.ByFieldType.NoSubmission", - GetFieldTypeGroupMetric(ADDRESS_HOME_COUNTRY, - AutofillMetrics::TYPE_UNKNOWN), - 1); - // Match: - histogram_tester.ExpectBucketCount( - "Autofill.Quality.PredictedType.NoSubmission", - AutofillMetrics::TYPE_MATCH, 2); - histogram_tester.ExpectBucketCount( - "Autofill.Quality.PredictedType.ByFieldType.NoSubmission", - GetFieldTypeGroupMetric(EMAIL_ADDRESS, AutofillMetrics::TYPE_MATCH), 1); - histogram_tester.ExpectBucketCount( - "Autofill.Quality.PredictedType.ByFieldType.NoSubmission", - GetFieldTypeGroupMetric(PHONE_HOME_WHOLE_NUMBER, - AutofillMetrics::TYPE_MATCH), - 1); - // Mismatch: - histogram_tester.ExpectBucketCount( - "Autofill.Quality.PredictedType.NoSubmission", - AutofillMetrics::TYPE_MISMATCH, 1); - histogram_tester.ExpectBucketCount( - "Autofill.Quality.PredictedType.ByFieldType.NoSubmission", - GetFieldTypeGroupMetric(NAME_FULL, AutofillMetrics::TYPE_MISMATCH), 1); + // Server predictions override heuristics, so server and overall will be the + // same. + for (const std::string source : {"Server", "Overall"}) { + std::string aggregate_histogram = + "Autofill.FieldPredictionQuality.Aggregate." + source + ".NoSubmission"; + std::string by_field_type_histogram = + "Autofill.FieldPredictionQuality.ByFieldType." + source + + ".NoSubmission"; + + // Unknown. + histogram_tester.ExpectBucketCount( + aggregate_histogram, AutofillMetrics::FALSE_NEGATIVE_UNKNOWN, 1); + histogram_tester.ExpectBucketCount( + by_field_type_histogram, + GetFieldTypeGroupMetric(ADDRESS_HOME_COUNTRY, + AutofillMetrics::FALSE_NEGATIVE_UNKNOWN), + 1); + // Match: + histogram_tester.ExpectBucketCount(aggregate_histogram, + AutofillMetrics::TRUE_POSITIVE, 2); + histogram_tester.ExpectBucketCount( + by_field_type_histogram, + GetFieldTypeGroupMetric(EMAIL_ADDRESS, AutofillMetrics::TRUE_POSITIVE), + 1); + histogram_tester.ExpectBucketCount( + by_field_type_histogram, + GetFieldTypeGroupMetric(PHONE_HOME_WHOLE_NUMBER, + AutofillMetrics::TRUE_POSITIVE), + 1); + // Mismatch: + histogram_tester.ExpectBucketCount( + aggregate_histogram, AutofillMetrics::FALSE_NEGATIVE_MISMATCH, 1); + histogram_tester.ExpectBucketCount( + by_field_type_histogram, + GetFieldTypeGroupMetric(NAME_FULL, + AutofillMetrics::FALSE_NEGATIVE_MISMATCH), + 1); + histogram_tester.ExpectBucketCount( + by_field_type_histogram, + GetFieldTypeGroupMetric(NAME_FIRST, + AutofillMetrics::FALSE_POSITIVE_MISMATCH), + 1); + + // False Positives: + histogram_tester.ExpectBucketCount( + aggregate_histogram, AutofillMetrics::FALSE_POSITIVE_EMPTY, 1); + histogram_tester.ExpectBucketCount( + by_field_type_histogram, + GetFieldTypeGroupMetric(NAME_FIRST, + AutofillMetrics::FALSE_POSITIVE_EMPTY), + 1); + histogram_tester.ExpectBucketCount( + aggregate_histogram, AutofillMetrics::FALSE_POSITIVE_UNKNOWN, 1); + histogram_tester.ExpectBucketCount( + by_field_type_histogram, + GetFieldTypeGroupMetric(EMAIL_ADDRESS, + AutofillMetrics::FALSE_POSITIVE_UNKNOWN), + 1); + + // Sanity Check: + histogram_tester.ExpectTotalCount(aggregate_histogram, 6); + histogram_tester.ExpectTotalCount(by_field_type_histogram, 7); + } } // Test that we log quality metrics for heuristics and server predictions based @@ -987,53 +1239,46 @@ EXPECT_EQ(ADDRESS_HOME_ZIP, form_structure_ptr->field(2)->Type().GetStorableType()); - // Heuristic predictions. - // Unknown: - histogram_tester.ExpectBucketCount( - "Autofill.Quality.HeuristicType.BasedOnAutocomplete", - AutofillMetrics::TYPE_UNKNOWN, 1); - histogram_tester.ExpectBucketCount( - "Autofill.Quality.HeuristicType.ByFieldType.BasedOnAutocomplete", - GetFieldTypeGroupMetric(ADDRESS_HOME_ZIP, AutofillMetrics::TYPE_UNKNOWN), - 1); - // Match: - histogram_tester.ExpectBucketCount( - "Autofill.Quality.HeuristicType.BasedOnAutocomplete", - AutofillMetrics::TYPE_MATCH, 1); - histogram_tester.ExpectBucketCount( - "Autofill.Quality.HeuristicType.ByFieldType.BasedOnAutocomplete", - GetFieldTypeGroupMetric(NAME_LAST, AutofillMetrics::TYPE_MATCH), 1); - // Mismatch: - histogram_tester.ExpectBucketCount( - "Autofill.Quality.HeuristicType.BasedOnAutocomplete", - AutofillMetrics::TYPE_MISMATCH, 1); - histogram_tester.ExpectBucketCount( - "Autofill.Quality.HeuristicType.ByFieldType.BasedOnAutocomplete", - GetFieldTypeGroupMetric(NAME_MIDDLE, AutofillMetrics::TYPE_MISMATCH), 1); + for (const std::string source : {"Heuristic", "Server"}) { + std::string aggregate_histogram = + "Autofill.FieldPredictionQuality.Aggregate." + source + + ".BasedOnAutocomplete"; + std::string by_field_type_histogram = + "Autofill.FieldPredictionQuality.ByFieldType." + source + + ".BasedOnAutocomplete"; - // Server predictions. - // Unknown: - histogram_tester.ExpectBucketCount( - "Autofill.Quality.ServerType.BasedOnAutocomplete", - AutofillMetrics::TYPE_UNKNOWN, 1); - histogram_tester.ExpectBucketCount( - "Autofill.Quality.ServerType.ByFieldType.BasedOnAutocomplete", - GetFieldTypeGroupMetric(ADDRESS_HOME_ZIP, AutofillMetrics::TYPE_UNKNOWN), - 1); - // Match: - histogram_tester.ExpectBucketCount( - "Autofill.Quality.ServerType.BasedOnAutocomplete", - AutofillMetrics::TYPE_MATCH, 1); - histogram_tester.ExpectBucketCount( - "Autofill.Quality.ServerType.ByFieldType.BasedOnAutocomplete", - GetFieldTypeGroupMetric(NAME_LAST, AutofillMetrics::TYPE_MATCH), 1); - // Mismatch: - histogram_tester.ExpectBucketCount( - "Autofill.Quality.ServerType.BasedOnAutocomplete", - AutofillMetrics::TYPE_MISMATCH, 1); - histogram_tester.ExpectBucketCount( - "Autofill.Quality.ServerType.ByFieldType.BasedOnAutocomplete", - GetFieldTypeGroupMetric(NAME_MIDDLE, AutofillMetrics::TYPE_MISMATCH), 1); + // Unknown: + histogram_tester.ExpectBucketCount( + aggregate_histogram, AutofillMetrics::FALSE_NEGATIVE_UNKNOWN, 1); + histogram_tester.ExpectBucketCount( + by_field_type_histogram, + GetFieldTypeGroupMetric(ADDRESS_HOME_ZIP, + AutofillMetrics::FALSE_NEGATIVE_UNKNOWN), + 1); + // Match: + histogram_tester.ExpectBucketCount(aggregate_histogram, + AutofillMetrics::TRUE_POSITIVE, 1); + histogram_tester.ExpectBucketCount( + by_field_type_histogram, + GetFieldTypeGroupMetric(NAME_LAST, AutofillMetrics::TRUE_POSITIVE), 1); + // Mismatch: + histogram_tester.ExpectBucketCount( + aggregate_histogram, AutofillMetrics::FALSE_NEGATIVE_MISMATCH, 1); + histogram_tester.ExpectBucketCount( + by_field_type_histogram, + GetFieldTypeGroupMetric(NAME_FIRST, + AutofillMetrics::FALSE_POSITIVE_MISMATCH), + 1); + histogram_tester.ExpectBucketCount( + by_field_type_histogram, + GetFieldTypeGroupMetric(NAME_MIDDLE, + AutofillMetrics::FALSE_POSITIVE_MISMATCH), + 1); + + // Sanity check. + histogram_tester.ExpectTotalCount(aggregate_histogram, 3); + histogram_tester.ExpectTotalCount(by_field_type_histogram, 4); + } } // Test that we log UPI Virtual Payment Address. @@ -1077,195 +1322,6 @@ "Autofill.UserHappiness", AutofillMetrics::USER_DID_ENTER_UPI_VPA, 1); } -// Test that we do not log RAPPOR metrics when the number of mismatches is not -// high enough. -TEST_F(AutofillMetricsTest, Rappor_LowMismatchRate_NoMetricsReported) { - // Set up our form data. - FormData form; - form.name = ASCIIToUTF16("TestForm"); - form.origin = GURL("http://example.com/form.html"); - form.action = GURL("http://example.com/submit.html"); - - std::vector<ServerFieldType> heuristic_types, server_types; - FormFieldData field; - - test::CreateTestFormField("Autofilled", "autofilled", "Elvis Aaron Presley", - "text", &field); - field.is_autofilled = true; - form.fields.push_back(field); - heuristic_types.push_back(NAME_FULL); - server_types.push_back(NAME_FULL); - - test::CreateTestFormField("Autofill Failed", "autofillfailed", - "buddy@gmail.com", "text", &field); - field.is_autofilled = false; - form.fields.push_back(field); - heuristic_types.push_back(EMAIL_ADDRESS); - server_types.push_back(NAME_LAST); - - test::CreateTestFormField("Phone", "phone", "2345678901", "tel", &field); - field.is_autofilled = true; - form.fields.push_back(field); - heuristic_types.push_back(PHONE_HOME_CITY_AND_NUMBER); - server_types.push_back(EMAIL_ADDRESS); - - // Simulate having seen this form on page load. - autofill_manager_->AddSeenForm(form, heuristic_types, server_types); - - // Simulate form submission. - autofill_manager_->SubmitForm(form, TimeTicks::Now()); - - // The number of mismatches did not trigger the RAPPOR metric logging. - EXPECT_EQ(0, autofill_client_.test_rappor_service()->GetReportsCount()); -} - -// Test that we don't log RAPPOR metrics in the case heuristics and/or server -// have no data. -TEST_F(AutofillMetricsTest, Rappor_NoDataServerAndHeuristic_NoMetricsReported) { - // Set up our form data. - FormData form; - form.name = ASCIIToUTF16("TestForm"); - form.origin = GURL("http://example.com/form.html"); - form.action = GURL("http://example.com/submit.html"); - - std::vector<ServerFieldType> heuristic_types, server_types; - FormFieldData field; - - test::CreateTestFormField("Autofilled", "autofilled", "Elvis Aaron Presley", - "text", &field); - field.is_autofilled = true; - form.fields.push_back(field); - heuristic_types.push_back(UNKNOWN_TYPE); - server_types.push_back(NO_SERVER_DATA); - - test::CreateTestFormField("Autofill Failed", "autofillfailed", - "buddy@gmail.com", "text", &field); - field.is_autofilled = false; - form.fields.push_back(field); - heuristic_types.push_back(UNKNOWN_TYPE); - server_types.push_back(NO_SERVER_DATA); - - test::CreateTestFormField("Phone", "phone", "2345678901", "tel", &field); - field.is_autofilled = true; - form.fields.push_back(field); - heuristic_types.push_back(UNKNOWN_TYPE); - server_types.push_back(NO_SERVER_DATA); - - // Simulate having seen this form on page load. - autofill_manager_->AddSeenForm(form, heuristic_types, server_types); - - // Simulate form submission. - autofill_manager_->SubmitForm(form, TimeTicks::Now()); - - // No RAPPOR metrics are logged in the case of multiple UNKNOWN_TYPE and - // NO_SERVER_DATA for heuristics and server predictions, respectively. - EXPECT_EQ(0, autofill_client_.test_rappor_service()->GetReportsCount()); -} - -// Test that we log high number of mismatches for the server prediction. -TEST_F(AutofillMetricsTest, Rappor_HighServerMismatchRate_MetricsReported) { - // Set up our form data. - FormData form; - form.name = ASCIIToUTF16("TestForm"); - form.origin = GURL("http://example.com/form.html"); - form.action = GURL("http://example.com/submit.html"); - - std::vector<ServerFieldType> heuristic_types, server_types; - FormFieldData field; - - test::CreateTestFormField("Autofilled", "autofilled", "Elvis Aaron Presley", - "text", &field); - field.is_autofilled = true; - form.fields.push_back(field); - heuristic_types.push_back(NAME_FULL); - server_types.push_back(NAME_FIRST); - - test::CreateTestFormField("Autofill Failed", "autofillfailed", - "buddy@gmail.com", "text", &field); - field.is_autofilled = false; - form.fields.push_back(field); - heuristic_types.push_back(PHONE_HOME_NUMBER); - server_types.push_back(NAME_LAST); - - test::CreateTestFormField("Phone", "phone", "2345678901", "tel", &field); - field.is_autofilled = true; - form.fields.push_back(field); - heuristic_types.push_back(PHONE_HOME_CITY_AND_NUMBER); - server_types.push_back(EMAIL_ADDRESS); - - // Simulate having seen this form on page load. - autofill_manager_->AddSeenForm(form, heuristic_types, server_types); - - // Simulate form submission. - autofill_manager_->SubmitForm(form, TimeTicks::Now()); - - // The number of mismatches did trigger the RAPPOR metric logging for server - // predictions. - EXPECT_EQ(1, autofill_client_.test_rappor_service()->GetReportsCount()); - std::string sample; - rappor::RapporType type; - EXPECT_FALSE( - autofill_client_.test_rappor_service()->GetRecordedSampleForMetric( - "Autofill.HighNumberOfHeuristicMismatches", &sample, &type)); - EXPECT_TRUE( - autofill_client_.test_rappor_service()->GetRecordedSampleForMetric( - "Autofill.HighNumberOfServerMismatches", &sample, &type)); - EXPECT_EQ("example.com", sample); - EXPECT_EQ(rappor::ETLD_PLUS_ONE_RAPPOR_TYPE, type); -} - -// Test that we log high number of mismatches for the heuristic predictions. -TEST_F(AutofillMetricsTest, Rappor_HighHeuristicMismatchRate_MetricsReported) { - // Set up our form data. - FormData form; - form.name = ASCIIToUTF16("TestForm"); - form.origin = GURL("http://example.com/form.html"); - form.action = GURL("http://example.com/submit.html"); - - std::vector<ServerFieldType> heuristic_types, server_types; - FormFieldData field; - - test::CreateTestFormField("Autofilled", "autofilled", "Elvis Aaron Presley", - "text", &field); - field.is_autofilled = true; - form.fields.push_back(field); - heuristic_types.push_back(NAME_FIRST); - server_types.push_back(NAME_FULL); - - test::CreateTestFormField("Autofill Failed", "autofillfailed", - "buddy@gmail.com", "text", &field); - field.is_autofilled = false; - form.fields.push_back(field); - heuristic_types.push_back(PHONE_HOME_NUMBER); - server_types.push_back(NAME_LAST); - - test::CreateTestFormField("Phone", "phone", "2345678901", "tel", &field); - field.is_autofilled = true; - form.fields.push_back(field); - heuristic_types.push_back(EMAIL_ADDRESS); - server_types.push_back(PHONE_HOME_WHOLE_NUMBER); - - // Simulate having seen this form on page load. - autofill_manager_->AddSeenForm(form, heuristic_types, server_types); - - // Simulate form submission. - autofill_manager_->SubmitForm(form, TimeTicks::Now()); - - // The number of mismatches did trigger the RAPPOR metric logging for - // heuristic predictions. - EXPECT_EQ(1, autofill_client_.test_rappor_service()->GetReportsCount()); - std::string sample; - rappor::RapporType type; - EXPECT_FALSE( - autofill_client_.test_rappor_service()->GetRecordedSampleForMetric( - "Autofill.HighNumberOfServerMismatches", &sample, &type)); - EXPECT_TRUE( - autofill_client_.test_rappor_service()->GetRecordedSampleForMetric( - "Autofill.HighNumberOfHeuristicMismatches", &sample, &type)); - EXPECT_EQ("example.com", sample); - EXPECT_EQ(rappor::ETLD_PLUS_ONE_RAPPOR_TYPE, type); -} - // Verify that when a field is annotated with the autocomplete attribute, its // predicted type is remembered when quality metrics are logged. TEST_F(AutofillMetricsTest, PredictedMetricsWithAutocomplete) { @@ -1293,69 +1349,43 @@ std::vector<FormData> forms(1, form); - { - base::HistogramTester histogram_tester; - autofill_manager_->OnFormsSeen(forms, TimeTicks()); - // We change the value of the text fields to change the default/seen values - // (hence the values are not cleared in UpdateFromCache). The new values - // match what is in the test profile. - form.fields[1].value = base::ASCIIToUTF16("79401"); - form.fields[2].value = base::ASCIIToUTF16("2345678901"); - autofill_manager_->SubmitForm(form, TimeTicks::Now()); + base::HistogramTester histogram_tester; + autofill_manager_->OnFormsSeen(forms, TimeTicks()); + // We change the value of the text fields to change the default/seen values + // (hence the values are not cleared in UpdateFromCache). The new values + // match what is in the test profile. + form.fields[1].value = base::ASCIIToUTF16("79401"); + form.fields[2].value = base::ASCIIToUTF16("2345678901"); + autofill_manager_->SubmitForm(form, TimeTicks::Now()); + + for (const std::string source : {"Heuristic", "Server", "Overall"}) { + std::string histogram_name = + "Autofill.FieldPredictionQuality.ByFieldType." + source; // First verify that country was not predicted by client or server. histogram_tester.ExpectBucketCount( - "Autofill.Quality.ServerType.ByFieldType", + histogram_name, GetFieldTypeGroupMetric(ADDRESS_HOME_COUNTRY, - AutofillMetrics::TYPE_UNKNOWN), - 1); - histogram_tester.ExpectBucketCount( - "Autofill.Quality.HeuristicType.ByFieldType", - GetFieldTypeGroupMetric(ADDRESS_HOME_COUNTRY, - AutofillMetrics::TYPE_UNKNOWN), - 1); - // We expect a match for country because it had |autocomplete_attribute|. - histogram_tester.ExpectBucketCount( - "Autofill.Quality.PredictedType.ByFieldType", - GetFieldTypeGroupMetric(ADDRESS_HOME_COUNTRY, - AutofillMetrics::TYPE_MATCH), + source == "Overall" + ? AutofillMetrics::TRUE_POSITIVE + : AutofillMetrics::FALSE_NEGATIVE_UNKNOWN), 1); // We did not predict zip code or phone number, because they did not have // |autocomplete_attribute|, nor client or server predictions. histogram_tester.ExpectBucketCount( - "Autofill.Quality.ServerType.ByFieldType", + histogram_name, GetFieldTypeGroupMetric(ADDRESS_HOME_ZIP, - AutofillMetrics::TYPE_UNKNOWN), + AutofillMetrics::FALSE_NEGATIVE_UNKNOWN), 1); histogram_tester.ExpectBucketCount( - "Autofill.Quality.HeuristicType.ByFieldType", - GetFieldTypeGroupMetric(ADDRESS_HOME_ZIP, - AutofillMetrics::TYPE_UNKNOWN), - 1); - histogram_tester.ExpectBucketCount( - "Autofill.Quality.PredictedType.ByFieldType", - GetFieldTypeGroupMetric(ADDRESS_HOME_ZIP, - AutofillMetrics::TYPE_UNKNOWN), - 1); - histogram_tester.ExpectBucketCount( - "Autofill.Quality.ServerType.ByFieldType", + histogram_name, GetFieldTypeGroupMetric(PHONE_HOME_WHOLE_NUMBER, - AutofillMetrics::TYPE_UNKNOWN), - 1); - histogram_tester.ExpectBucketCount( - "Autofill.Quality.HeuristicType.ByFieldType", - GetFieldTypeGroupMetric(PHONE_HOME_WHOLE_NUMBER, - AutofillMetrics::TYPE_UNKNOWN), - 1); - histogram_tester.ExpectBucketCount( - "Autofill.Quality.PredictedType.ByFieldType", - GetFieldTypeGroupMetric(PHONE_HOME_WHOLE_NUMBER, - AutofillMetrics::TYPE_UNKNOWN), + AutofillMetrics::FALSE_NEGATIVE_UNKNOWN), 1); // Sanity check. - histogram_tester.ExpectTotalCount("Autofill.Quality.PredictedType", 3); + histogram_tester.ExpectTotalCount(histogram_name, 3); } } @@ -1415,88 +1445,45 @@ base::HistogramTester histogram_tester; autofill_manager_->SubmitForm(form, TimeTicks::Now()); - // Heuristic predictions. - // Unknown: - histogram_tester.ExpectBucketCount("Autofill.Quality.HeuristicType", - AutofillMetrics::TYPE_UNKNOWN, 1); - histogram_tester.ExpectBucketCount( - "Autofill.Quality.HeuristicType.ByFieldType", - GetFieldTypeGroupMetric(ADDRESS_HOME_STATE, - AutofillMetrics::TYPE_UNKNOWN), - 1); - // Match: - histogram_tester.ExpectBucketCount("Autofill.Quality.HeuristicType", - AutofillMetrics::TYPE_MATCH, 2); - histogram_tester.ExpectBucketCount( - "Autofill.Quality.HeuristicType.ByFieldType", - GetFieldTypeGroupMetric(ADDRESS_HOME_CITY, AutofillMetrics::TYPE_MATCH), - 1); - histogram_tester.ExpectBucketCount( - "Autofill.Quality.HeuristicType.ByFieldType", - GetFieldTypeGroupMetric(NAME_FULL, AutofillMetrics::TYPE_MATCH), 1); - // Mismatch: - histogram_tester.ExpectBucketCount("Autofill.Quality.HeuristicType", - AutofillMetrics::TYPE_MISMATCH, 1); - histogram_tester.ExpectBucketCount( - "Autofill.Quality.HeuristicType.ByFieldType", - GetFieldTypeGroupMetric(EMAIL_ADDRESS, AutofillMetrics::TYPE_MISMATCH), - 1); + for (const std::string source : {"Heuristic", "Server", "Overall"}) { + std::string aggregate_histogram = + "Autofill.FieldPredictionQuality.Aggregate." + source; + std::string by_field_type_histogram = + "Autofill.FieldPredictionQuality.ByFieldType." + source; - // Server predictions: - // Unknown: - histogram_tester.ExpectBucketCount("Autofill.Quality.ServerType", - AutofillMetrics::TYPE_UNKNOWN, 1); - histogram_tester.ExpectBucketCount( - "Autofill.Quality.ServerType.ByFieldType", - GetFieldTypeGroupMetric(ADDRESS_HOME_STATE, - AutofillMetrics::TYPE_UNKNOWN), - 1); - // Match: - histogram_tester.ExpectBucketCount("Autofill.Quality.ServerType", - AutofillMetrics::TYPE_MATCH, 1); - histogram_tester.ExpectBucketCount( - "Autofill.Quality.ServerType.ByFieldType", - GetFieldTypeGroupMetric(NAME_FULL, AutofillMetrics::TYPE_MATCH), 1); - // Mismatch: - histogram_tester.ExpectBucketCount("Autofill.Quality.ServerType", - AutofillMetrics::TYPE_MISMATCH, 2); - histogram_tester.ExpectBucketCount( - "Autofill.Quality.ServerType.ByFieldType", - GetFieldTypeGroupMetric(ADDRESS_HOME_CITY, - AutofillMetrics::TYPE_MISMATCH), - 1); - histogram_tester.ExpectBucketCount( - "Autofill.Quality.ServerType.ByFieldType", - GetFieldTypeGroupMetric(EMAIL_ADDRESS, AutofillMetrics::TYPE_MISMATCH), - 1); - - // Overall predictions: - // Unknown: - histogram_tester.ExpectBucketCount("Autofill.Quality.PredictedType", - AutofillMetrics::TYPE_UNKNOWN, 1); - histogram_tester.ExpectBucketCount( - "Autofill.Quality.PredictedType.ByFieldType", - GetFieldTypeGroupMetric(ADDRESS_HOME_STATE, - AutofillMetrics::TYPE_UNKNOWN), - 1); - // Match: - histogram_tester.ExpectBucketCount("Autofill.Quality.PredictedType", - AutofillMetrics::TYPE_MATCH, 1); - histogram_tester.ExpectBucketCount( - "Autofill.Quality.PredictedType.ByFieldType", - GetFieldTypeGroupMetric(NAME_FULL, AutofillMetrics::TYPE_MATCH), 1); - // Mismatch: - histogram_tester.ExpectBucketCount("Autofill.Quality.PredictedType", - AutofillMetrics::TYPE_MISMATCH, 2); - histogram_tester.ExpectBucketCount( - "Autofill.Quality.PredictedType.ByFieldType", - GetFieldTypeGroupMetric(ADDRESS_HOME_CITY, - AutofillMetrics::TYPE_MISMATCH), - 1); - histogram_tester.ExpectBucketCount( - "Autofill.Quality.PredictedType.ByFieldType", - GetFieldTypeGroupMetric(EMAIL_ADDRESS, AutofillMetrics::TYPE_MISMATCH), - 1); + // Unknown: + histogram_tester.ExpectBucketCount( + aggregate_histogram, AutofillMetrics::FALSE_NEGATIVE_UNKNOWN, 1); + histogram_tester.ExpectBucketCount( + by_field_type_histogram, + GetFieldTypeGroupMetric(ADDRESS_HOME_STATE, + AutofillMetrics::FALSE_NEGATIVE_UNKNOWN), + 1); + // Match: + histogram_tester.ExpectBucketCount(aggregate_histogram, + AutofillMetrics::TRUE_POSITIVE, + source == "Heuristic" ? 2 : 1); + histogram_tester.ExpectBucketCount( + by_field_type_histogram, + GetFieldTypeGroupMetric(NAME_FULL, AutofillMetrics::TRUE_POSITIVE), 1); + // Mismatch: + histogram_tester.ExpectBucketCount(aggregate_histogram, + AutofillMetrics::FALSE_NEGATIVE_MISMATCH, + source == "Heuristic" ? 1 : 2); + histogram_tester.ExpectBucketCount( + by_field_type_histogram, + GetFieldTypeGroupMetric(EMAIL_ADDRESS, + AutofillMetrics::FALSE_NEGATIVE_MISMATCH), + 1); + // Source dependent: + histogram_tester.ExpectBucketCount( + by_field_type_histogram, + GetFieldTypeGroupMetric(ADDRESS_HOME_CITY, + source == "Heuristic" + ? AutofillMetrics::TRUE_POSITIVE + : AutofillMetrics::FALSE_NEGATIVE_MISMATCH), + 1); + } } // Verify that when submitting an autofillable form, the stored profile metric
diff --git a/components/autofill/core/browser/autofill_type.cc b/components/autofill/core/browser/autofill_type.cc index 2b97a2f..b58d1a13 100644 --- a/components/autofill/core/browser/autofill_type.cc +++ b/components/autofill/core/browser/autofill_type.cc
@@ -131,6 +131,7 @@ case NO_SERVER_DATA: case EMPTY_TYPE: + case AMBIGUOUS_TYPE: case PHONE_FAX_NUMBER: case PHONE_FAX_CITY_CODE: case PHONE_FAX_COUNTRY_CODE: @@ -771,6 +772,9 @@ case CONFIRMATION_PASSWORD: return "CONFIRMATION_PASSWORD"; + case AMBIGUOUS_TYPE: + return "AMBIGUOUS_TYPE"; + case MAX_VALID_FIELD_TYPE: return std::string(); }
diff --git a/components/autofill/core/browser/field_types.h b/components/autofill/core/browser/field_types.h index cee305f..1b1ab99 100644 --- a/components/autofill/core/browser/field_types.h +++ b/components/autofill/core/browser/field_types.h
@@ -163,9 +163,14 @@ // forms. CONFIRMATION_PASSWORD = 95, + // The data entered by the user matches multiple pieces of autofill data, + // none of which were predicted by autofill. This value is used for metrics + // only, it is not a predicted nor uploaded type. + AMBIGUOUS_TYPE = 96, + // No new types can be added without a corresponding change to the Autofill // server. - MAX_VALID_FIELD_TYPE = 96, + MAX_VALID_FIELD_TYPE = 97, }; // The list of all HTML autocomplete field type hints supported by Chrome.
diff --git a/components/autofill/core/browser/form_structure.cc b/components/autofill/core/browser/form_structure.cc index 9a7b87d..10a83809 100644 --- a/components/autofill/core/browser/form_structure.cc +++ b/components/autofill/core/browser/form_structure.cc
@@ -47,10 +47,6 @@ const char kBillingMode[] = "billing"; const char kShippingMode[] = "shipping"; -// A form is considered to have a high prediction mismatch rate if the number of -// mismatches exceeds this threshold. -const int kNumberOfMismatchesThreshold = 3; - // Only removing common name prefixes if we have a minimum number of fields and // a minimum prefix length. These values are chosen to avoid cases such as two // fields with "address1" and "address2" and be effective against web frameworks @@ -701,8 +697,6 @@ bool did_show_suggestions, bool observed_submission) const { size_t num_detected_field_types = 0; - size_t num_server_mismatches = 0; - size_t num_heuristic_mismatches = 0; size_t num_edited_autofilled_fields = 0; bool did_autofill_all_possible_fields = true; bool did_autofill_some_possible_fields = false; @@ -741,93 +735,21 @@ const ServerFieldTypeSet& field_types = field->possible_types(); DCHECK(!field_types.empty()); - // If the field data is empty, or unrecognized, log whether or not autofill - // predicted that it would be populated with an autofillable data type. - bool has_empty_data = field_types.count(EMPTY_TYPE) != 0; - bool has_unrecognized_data = field_types.count(UNKNOWN_TYPE) != 0; - if (has_empty_data || has_unrecognized_data) { - AutofillMetrics::FieldTypeQualityMetric match_empty_or_unknown = - has_empty_data ? AutofillMetrics::TYPE_MATCH_EMPTY - : AutofillMetrics::TYPE_MATCH_UNKNOWN; - AutofillMetrics::FieldTypeQualityMetric mismatch_empty_or_unknown = - has_empty_data ? AutofillMetrics::TYPE_MISMATCH_EMPTY - : AutofillMetrics::TYPE_MISMATCH_UNKNOWN; - ServerFieldType field_type = has_empty_data ? EMPTY_TYPE : UNKNOWN_TYPE; - AutofillMetrics::LogHeuristicTypePrediction( - (heuristic_type == UNKNOWN_TYPE ? match_empty_or_unknown - : mismatch_empty_or_unknown), - field_type, metric_type); - AutofillMetrics::LogServerTypePrediction( - (server_type == NO_SERVER_DATA ? match_empty_or_unknown - : mismatch_empty_or_unknown), - field_type, metric_type); - AutofillMetrics::LogOverallTypePrediction( - (predicted_type == UNKNOWN_TYPE ? match_empty_or_unknown - : mismatch_empty_or_unknown), - field_type, metric_type); + AutofillMetrics::LogHeuristicPredictionQualityMetrics( + field_types, heuristic_type, metric_type); + AutofillMetrics::LogServerPredictionQualityMetrics(field_types, server_type, + metric_type); + AutofillMetrics::LogOverallPredictionQualityMetrics( + field_types, predicted_type, metric_type); + + if (field_types.count(EMPTY_TYPE) || field_types.count(UNKNOWN_TYPE)) continue; - } ++num_detected_field_types; if (field->is_autofilled) did_autofill_some_possible_fields = true; else did_autofill_all_possible_fields = false; - - // Collapse field types that Chrome treats as identical, e.g. home and - // billing address fields. - ServerFieldTypeSet collapsed_field_types; - for (const auto& it : field_types) { - // Since we currently only support US phone numbers, the (city code + main - // digits) number is almost always identical to the whole phone number. - // TODO(isherman): Improve this logic once we add support for - // international numbers. - if (it == PHONE_HOME_CITY_AND_NUMBER) - collapsed_field_types.insert(PHONE_HOME_WHOLE_NUMBER); - else - collapsed_field_types.insert(AutofillType(it).GetStorableType()); - } - - // Capture the field's type, if it is unambiguous. - ServerFieldType field_type = UNKNOWN_TYPE; - if (collapsed_field_types.size() == 1) - field_type = *collapsed_field_types.begin(); - - // Log heuristic, server, and overall type quality metrics. - if (heuristic_type == UNKNOWN_TYPE) { - AutofillMetrics::LogHeuristicTypePrediction(AutofillMetrics::TYPE_UNKNOWN, - field_type, metric_type); - } else if (field_types.count(heuristic_type)) { - AutofillMetrics::LogHeuristicTypePrediction(AutofillMetrics::TYPE_MATCH, - field_type, metric_type); - } else { - ++num_heuristic_mismatches; - AutofillMetrics::LogHeuristicTypePrediction( - AutofillMetrics::TYPE_MISMATCH, field_type, metric_type); - } - - if (server_type == NO_SERVER_DATA) { - AutofillMetrics::LogServerTypePrediction(AutofillMetrics::TYPE_UNKNOWN, - field_type, metric_type); - } else if (field_types.count(server_type)) { - AutofillMetrics::LogServerTypePrediction(AutofillMetrics::TYPE_MATCH, - field_type, metric_type); - } else { - ++num_server_mismatches; - AutofillMetrics::LogServerTypePrediction(AutofillMetrics::TYPE_MISMATCH, - field_type, metric_type); - } - - if (predicted_type == UNKNOWN_TYPE) { - AutofillMetrics::LogOverallTypePrediction(AutofillMetrics::TYPE_UNKNOWN, - field_type, metric_type); - } else if (field_types.count(predicted_type)) { - AutofillMetrics::LogOverallTypePrediction(AutofillMetrics::TYPE_MATCH, - field_type, metric_type); - } else { - AutofillMetrics::LogOverallTypePrediction(AutofillMetrics::TYPE_MISMATCH, - field_type, metric_type); - } } AutofillMetrics::LogNumberOfEditedAutofilledFields( @@ -852,18 +774,6 @@ AutofillMetrics::FILLABLE_FORM_AUTOFILLED_NONE_DID_SHOW_SUGGESTIONS; } - // Log some RAPPOR metrics for problematic cases. - if (num_server_mismatches >= kNumberOfMismatchesThreshold) { - rappor::SampleDomainAndRegistryFromGURL( - rappor_service, "Autofill.HighNumberOfServerMismatches", - source_url_); - } - if (num_heuristic_mismatches >= kNumberOfMismatchesThreshold) { - rappor::SampleDomainAndRegistryFromGURL( - rappor_service, "Autofill.HighNumberOfHeuristicMismatches", - source_url_); - } - // Unlike the other times, the |submission_time| should always be // available. DCHECK(!submission_time.is_null()); @@ -904,38 +814,20 @@ } void FormStructure::LogQualityMetricsBasedOnAutocomplete() const { + const AutofillMetrics::QualityMetricType metric_type = + AutofillMetrics::TYPE_AUTOCOMPLETE_BASED; for (const auto& field : fields_) { if (field->html_type() != HTML_TYPE_UNSPECIFIED && field->html_type() != HTML_TYPE_UNRECOGNIZED) { // The type inferred by the autocomplete attribute. - AutofillType type(field->html_type(), field->html_mode()); - ServerFieldType actual_field_type = type.GetStorableType(); + ServerFieldTypeSet actual_field_type_set{ + AutofillType(field->html_type(), field->html_mode()) + .GetStorableType()}; - const AutofillMetrics::QualityMetricType metric_type = - AutofillMetrics::TYPE_AUTOCOMPLETE_BASED; - // Log the quality of our heuristics predictions. - if (field->heuristic_type() == UNKNOWN_TYPE) { - AutofillMetrics::LogHeuristicTypePrediction( - AutofillMetrics::TYPE_UNKNOWN, actual_field_type, metric_type); - } else if (field->heuristic_type() == actual_field_type) { - AutofillMetrics::LogHeuristicTypePrediction( - AutofillMetrics::TYPE_MATCH, actual_field_type, metric_type); - } else { - AutofillMetrics::LogHeuristicTypePrediction( - AutofillMetrics::TYPE_MISMATCH, actual_field_type, metric_type); - } - - // Log the quality of our server predictions. - if (field->server_type() == NO_SERVER_DATA) { - AutofillMetrics::LogServerTypePrediction( - AutofillMetrics::TYPE_UNKNOWN, actual_field_type, metric_type); - } else if (field->server_type() == actual_field_type) { - AutofillMetrics::LogServerTypePrediction( - AutofillMetrics::TYPE_MATCH, actual_field_type, metric_type); - } else { - AutofillMetrics::LogServerTypePrediction( - AutofillMetrics::TYPE_MISMATCH, actual_field_type, metric_type); - } + AutofillMetrics::LogHeuristicPredictionQualityMetrics( + actual_field_type_set, field->heuristic_type(), metric_type); + AutofillMetrics::LogServerPredictionQualityMetrics( + actual_field_type_set, field->server_type(), metric_type); } } }
diff --git a/components/exo/shell_surface.cc b/components/exo/shell_surface.cc index a87a22a..b22b47bc 100644 --- a/components/exo/shell_surface.cc +++ b/components/exo/shell_surface.cc
@@ -492,6 +492,14 @@ widget_->UpdateWindowTitle(); } +void ShellSurface::SetIcon(const gfx::ImageSkia& icon) { + TRACE_EVENT0("exo", "ShellSurface::SetIcon"); + + icon_ = icon; + if (widget_) + widget_->UpdateWindowIcon(); +} + void ShellSurface::SetSystemModal(bool system_modal) { // System modal container is used by clients to implement client side // managed system modal dialogs using a single ShellSurface instance. @@ -829,6 +837,10 @@ return title_; } +gfx::ImageSkia ShellSurface::GetWindowIcon() { + return icon_; +} + void ShellSurface::SaveWindowPlacement(const gfx::Rect& bounds, ui::WindowShowState show_state) { if (bounds_mode_ != BoundsMode::CLIENT)
diff --git a/components/exo/shell_surface.h b/components/exo/shell_surface.h index d528f11..6991ccaf 100644 --- a/components/exo/shell_surface.h +++ b/components/exo/shell_surface.h
@@ -140,9 +140,12 @@ // Set whether the surface is always on top. void SetAlwaysOnTop(bool always_on_top); - // Set title for surface. + // Set title for the surface. void SetTitle(const base::string16& title); + // Set icon for the surface. + void SetIcon(const gfx::ImageSkia& icon); + // Sets the system modality. void SetSystemModal(bool system_modal); @@ -227,6 +230,7 @@ bool CanMaximize() const override; bool CanMinimize() const override; base::string16 GetWindowTitle() const override; + gfx::ImageSkia GetWindowIcon() override; void SaveWindowPlacement(const gfx::Rect& bounds, ui::WindowShowState show_state) override; bool GetSavedWindowPlacement(const views::Widget* widget, @@ -373,6 +377,7 @@ bool shadow_underlay_in_surface_ = true; bool pending_shadow_underlay_in_surface_ = true; bool system_modal_ = false; + gfx::ImageSkia icon_; DISALLOW_COPY_AND_ASSIGN(ShellSurface); };
diff --git a/components/omnibox/browser/zero_suggest_provider.cc b/components/omnibox/browser/zero_suggest_provider.cc index 1aa9dc0..e900253 100644 --- a/components/omnibox/browser/zero_suggest_provider.cc +++ b/components/omnibox/browser/zero_suggest_provider.cc
@@ -85,6 +85,32 @@ // Used for testing whether zero suggest is ever available. constexpr char kArbitraryInsecureUrlString[] = "http://www.google.com/"; +// Returns true if the folowing conditions are valid: +// * The |default_provider| is Google. +// * The user is in the ZeroSuggestRedirectToChrome field trial. +// * The field trial provides a valid server address where the suggest request +// is redirected. +// * The suggest request is over HTTPS. This avoids leaking the current page URL +// or personal data in unencrypted network traffic. +// Note: these checks are in addition to CanSendUrl() on the default contextual +// suggestion URL. +bool UseExperimentalSuggestService(const TemplateURLService& default_provider) { + const TemplateURL& default_provider_url = + *default_provider.GetDefaultSearchProvider(); + const SearchTermsData& search_terms_data = + default_provider.search_terms_data(); + if ((default_provider_url.GetEngineType(search_terms_data) != + SEARCH_ENGINE_GOOGLE) || + !OmniboxFieldTrial::InZeroSuggestRedirectToChromeFieldTrial()) + return false; + // Check that the suggest URL for redirect to chrome field trial is valid. + const GURL suggest_url( + OmniboxFieldTrial::ZeroSuggestRedirectToChromeServerAddress()); + if (!suggest_url.is_valid()) + return false; + return suggest_url.SchemeIsCryptographic(); +} + } // namespace // static @@ -120,8 +146,7 @@ current_page_classification_ = input.current_page_classification(); current_url_match_ = MatchForCurrentURL(); - std::string url_string = GetContextualSuggestionsUrl(); - GURL suggest_url(url_string); + GURL suggest_url(GetContextualSuggestionsUrl()); if (!suggest_url.is_valid()) return; @@ -153,11 +178,11 @@ !OmniboxFieldTrial::InZeroSuggestPersonalizedFieldTrial() && !OmniboxFieldTrial::InZeroSuggestMostVisitedFieldTrial()) { // Update suggest_url to include the current_page_url. - if (OmniboxFieldTrial::InZeroSuggestRedirectToChromeFieldTrial()) { - url_string += + if (UseExperimentalSuggestService(*template_url_service)) { + suggest_url = GURL( + OmniboxFieldTrial::ZeroSuggestRedirectToChromeServerAddress() + "/url=" + net::EscapePath(current_query_) + - OmniboxFieldTrial::ZeroSuggestRedirectToChromeAdditionalFields(); - suggest_url = GURL(url_string); + OmniboxFieldTrial::ZeroSuggestRedirectToChromeAdditionalFields()); } else { base::string16 prefix; TemplateURLRef::SearchTermsArgs search_term_args(prefix); @@ -553,8 +578,6 @@ } std::string ZeroSuggestProvider::GetContextualSuggestionsUrl() const { - // Without a default search provider, refuse to do anything (even if the user - // is in the redirect-to-chrome field trial). const TemplateURLService* template_url_service = client()->GetTemplateURLService(); const TemplateURL* default_provider = @@ -562,8 +585,6 @@ if (default_provider == nullptr) return std::string(); - if (OmniboxFieldTrial::InZeroSuggestRedirectToChromeFieldTrial()) - return OmniboxFieldTrial::ZeroSuggestRedirectToChromeServerAddress(); base::string16 prefix; TemplateURLRef::SearchTermsArgs search_term_args(prefix); return default_provider->suggestions_url_ref().ReplaceSearchTerms(
diff --git a/components/reading_list/ios/BUILD.gn b/components/reading_list/ios/BUILD.gn index 5d605fb..eb4ed058 100644 --- a/components/reading_list/ios/BUILD.gn +++ b/components/reading_list/ios/BUILD.gn
@@ -3,6 +3,7 @@ # found in the LICENSE file. source_set("ios") { + configs += [ "//build/config/compiler:enable_arc" ] sources = [ "favicon_web_state_dispatcher.h", "reading_list_model_bridge_observer.h",
diff --git a/components/reading_list/ios/reading_list_model_bridge_observer.h b/components/reading_list/ios/reading_list_model_bridge_observer.h index 33a433e..dde8f6c 100644 --- a/components/reading_list/ios/reading_list_model_bridge_observer.h +++ b/components/reading_list/ios/reading_list_model_bridge_observer.h
@@ -75,6 +75,8 @@ const GURL& url) override; __unsafe_unretained id<ReadingListModelBridgeObserver> observer_; + + // TODO(crbug.com/729015): Refactor to remove the naked pointer. ReadingListModel* model_; // weak DISALLOW_COPY_AND_ASSIGN(ReadingListModelBridge);
diff --git a/components/reading_list/ios/reading_list_model_bridge_observer.mm b/components/reading_list/ios/reading_list_model_bridge_observer.mm index a54a1a4..ff5836e 100644 --- a/components/reading_list/ios/reading_list_model_bridge_observer.mm +++ b/components/reading_list/ios/reading_list_model_bridge_observer.mm
@@ -7,6 +7,10 @@ #include "components/reading_list/core/reading_list_entry.h" #include "components/reading_list/core/reading_list_model.h" +#if !defined(__has_feature) || !__has_feature(objc_arc) +#error "This file requires ARC support." +#endif + ReadingListModelBridge::ReadingListModelBridge( id<ReadingListModelBridgeObserver> observer, ReadingListModel* model)
diff --git a/components/safe_browsing_db/v4_local_database_manager.cc b/components/safe_browsing_db/v4_local_database_manager.cc index 3b37d7b5..c17dbde9 100644 --- a/components/safe_browsing_db/v4_local_database_manager.cc +++ b/components/safe_browsing_db/v4_local_database_manager.cc
@@ -66,7 +66,9 @@ SB_THREAT_TYPE_URL_MALWARE), ListInfo(kSyncAlways, "UrlUws.store", GetUrlUwsId(), SB_THREAT_TYPE_URL_UNWANTED), - ListInfo(kSyncAlways, "UrlMalBin.store", GetUrlMalBinId(), + // The GetUrlMalBinId list is not working for non-GoogleChrome builds + // currently so making it Chrome-only. See: http://crbug.com/728757 + ListInfo(kSyncOnlyOnChromeBuilds, "UrlMalBin.store", GetUrlMalBinId(), SB_THREAT_TYPE_BINARY_MALWARE_URL), ListInfo(kSyncAlways, "ChromeExtMalware.store", GetChromeExtMalwareId(), SB_THREAT_TYPE_EXTENSION),
diff --git a/components/user_manager/user_manager_base.cc b/components/user_manager/user_manager_base.cc index db4ac7a..20818081 100644 --- a/components/user_manager/user_manager_base.cc +++ b/components/user_manager/user_manager_base.cc
@@ -105,7 +105,7 @@ } void UserManagerBase::Shutdown() { - DCHECK(task_runner_->RunsTasksOnCurrentThread()); + DCHECK(!task_runner_ || task_runner_->RunsTasksOnCurrentThread()); } const UserList& UserManagerBase::GetUsers() const { @@ -128,7 +128,7 @@ void UserManagerBase::UserLoggedIn(const AccountId& account_id, const std::string& username_hash, bool browser_restart) { - DCHECK(task_runner_->RunsTasksOnCurrentThread()); + DCHECK(!task_runner_ || task_runner_->RunsTasksOnCurrentThread()); if (!last_session_active_account_id_initialized_) { last_session_active_account_id_ = @@ -259,14 +259,14 @@ } void UserManagerBase::OnSessionStarted() { - DCHECK(task_runner_->RunsTasksOnCurrentThread()); + DCHECK(!task_runner_ || task_runner_->RunsTasksOnCurrentThread()); CallUpdateLoginState(); GetLocalState()->CommitPendingWrite(); } void UserManagerBase::OnProfileInitialized(User* user) { - DCHECK(task_runner_->RunsTasksOnCurrentThread()); + DCHECK(!task_runner_ || task_runner_->RunsTasksOnCurrentThread()); // Mark the user as having an initialized session and persist this in // the known_user DB. @@ -277,7 +277,7 @@ void UserManagerBase::RemoveUser(const AccountId& account_id, RemoveUserDelegate* delegate) { - DCHECK(task_runner_->RunsTasksOnCurrentThread()); + DCHECK(!task_runner_ || task_runner_->RunsTasksOnCurrentThread()); if (!CanUserBeRemoved(FindUser(account_id))) return; @@ -302,7 +302,7 @@ } void UserManagerBase::RemoveUserFromList(const AccountId& account_id) { - DCHECK(task_runner_->RunsTasksOnCurrentThread()); + DCHECK(!task_runner_ || task_runner_->RunsTasksOnCurrentThread()); RemoveNonCryptohomeData(account_id); if (user_loading_stage_ == STAGE_LOADED) { DeleteUser(RemoveRegularOrSupervisedUserFromList(account_id)); @@ -328,38 +328,38 @@ } const User* UserManagerBase::FindUser(const AccountId& account_id) const { - DCHECK(task_runner_->RunsTasksOnCurrentThread()); + DCHECK(!task_runner_ || task_runner_->RunsTasksOnCurrentThread()); if (active_user_ && active_user_->GetAccountId() == account_id) return active_user_; return FindUserInList(account_id); } User* UserManagerBase::FindUserAndModify(const AccountId& account_id) { - DCHECK(task_runner_->RunsTasksOnCurrentThread()); + DCHECK(!task_runner_ || task_runner_->RunsTasksOnCurrentThread()); if (active_user_ && active_user_->GetAccountId() == account_id) return active_user_; return FindUserInListAndModify(account_id); } const User* UserManagerBase::GetActiveUser() const { - DCHECK(task_runner_->RunsTasksOnCurrentThread()); + DCHECK(!task_runner_ || task_runner_->RunsTasksOnCurrentThread()); return active_user_; } User* UserManagerBase::GetActiveUser() { - DCHECK(task_runner_->RunsTasksOnCurrentThread()); + DCHECK(!task_runner_ || task_runner_->RunsTasksOnCurrentThread()); return active_user_; } const User* UserManagerBase::GetPrimaryUser() const { - DCHECK(task_runner_->RunsTasksOnCurrentThread()); + DCHECK(!task_runner_ || task_runner_->RunsTasksOnCurrentThread()); return primary_user_; } void UserManagerBase::SaveUserOAuthStatus( const AccountId& account_id, User::OAuthTokenStatus oauth_token_status) { - DCHECK(task_runner_->RunsTasksOnCurrentThread()); + DCHECK(!task_runner_ || task_runner_->RunsTasksOnCurrentThread()); DVLOG(1) << "Saving user OAuth token status in Local State"; User* user = FindUserAndModify(account_id); @@ -382,7 +382,7 @@ void UserManagerBase::SaveForceOnlineSignin(const AccountId& account_id, bool force_online_signin) { - DCHECK(task_runner_->RunsTasksOnCurrentThread()); + DCHECK(!task_runner_ || task_runner_->RunsTasksOnCurrentThread()); // Do not update local state if data stored or cached outside the user's // cryptohome is to be treated as ephemeral. @@ -400,7 +400,7 @@ void UserManagerBase::SaveUserDisplayName(const AccountId& account_id, const base::string16& display_name) { - DCHECK(task_runner_->RunsTasksOnCurrentThread()); + DCHECK(!task_runner_ || task_runner_->RunsTasksOnCurrentThread()); if (User* user = FindUserAndModify(account_id)) { user->set_display_name(display_name); @@ -424,7 +424,7 @@ void UserManagerBase::SaveUserDisplayEmail(const AccountId& account_id, const std::string& display_email) { - DCHECK(task_runner_->RunsTasksOnCurrentThread()); + DCHECK(!task_runner_ || task_runner_->RunsTasksOnCurrentThread()); User* user = FindUserAndModify(account_id); if (!user) { @@ -452,7 +452,7 @@ void UserManagerBase::SaveUserType(const AccountId& account_id, const UserType& user_type) { - DCHECK(task_runner_->RunsTasksOnCurrentThread()); + DCHECK(!task_runner_ || task_runner_->RunsTasksOnCurrentThread()); User* user = FindUserAndModify(account_id); if (!user) { @@ -474,7 +474,7 @@ void UserManagerBase::UpdateUserAccountData( const AccountId& account_id, const UserAccountData& account_data) { - DCHECK(task_runner_->RunsTasksOnCurrentThread()); + DCHECK(!task_runner_ || task_runner_->RunsTasksOnCurrentThread()); SaveUserDisplayName(account_id, account_data.display_name()); @@ -517,76 +517,76 @@ } bool UserManagerBase::IsCurrentUserOwner() const { - DCHECK(task_runner_->RunsTasksOnCurrentThread()); + DCHECK(!task_runner_ || task_runner_->RunsTasksOnCurrentThread()); return !owner_account_id_.empty() && active_user_ && active_user_->GetAccountId() == owner_account_id_; } bool UserManagerBase::IsCurrentUserNew() const { - DCHECK(task_runner_->RunsTasksOnCurrentThread()); + DCHECK(!task_runner_ || task_runner_->RunsTasksOnCurrentThread()); return is_current_user_new_; } bool UserManagerBase::IsCurrentUserNonCryptohomeDataEphemeral() const { - DCHECK(task_runner_->RunsTasksOnCurrentThread()); + DCHECK(!task_runner_ || task_runner_->RunsTasksOnCurrentThread()); return IsUserLoggedIn() && IsUserNonCryptohomeDataEphemeral(GetActiveUser()->GetAccountId()); } bool UserManagerBase::IsCurrentUserCryptohomeDataEphemeral() const { - DCHECK(task_runner_->RunsTasksOnCurrentThread()); + DCHECK(!task_runner_ || task_runner_->RunsTasksOnCurrentThread()); return IsUserLoggedIn() && IsUserCryptohomeDataEphemeral(GetActiveUser()->GetAccountId()); } bool UserManagerBase::CanCurrentUserLock() const { - DCHECK(task_runner_->RunsTasksOnCurrentThread()); + DCHECK(!task_runner_ || task_runner_->RunsTasksOnCurrentThread()); return IsUserLoggedIn() && active_user_->can_lock(); } bool UserManagerBase::IsUserLoggedIn() const { - DCHECK(task_runner_->RunsTasksOnCurrentThread()); + DCHECK(!task_runner_ || task_runner_->RunsTasksOnCurrentThread()); return active_user_; } bool UserManagerBase::IsLoggedInAsUserWithGaiaAccount() const { - DCHECK(task_runner_->RunsTasksOnCurrentThread()); + DCHECK(!task_runner_ || task_runner_->RunsTasksOnCurrentThread()); return IsUserLoggedIn() && active_user_->HasGaiaAccount(); } bool UserManagerBase::IsLoggedInAsChildUser() const { - DCHECK(task_runner_->RunsTasksOnCurrentThread()); + DCHECK(!task_runner_ || task_runner_->RunsTasksOnCurrentThread()); return IsUserLoggedIn() && active_user_->GetType() == USER_TYPE_CHILD; } bool UserManagerBase::IsLoggedInAsPublicAccount() const { - DCHECK(task_runner_->RunsTasksOnCurrentThread()); + DCHECK(!task_runner_ || task_runner_->RunsTasksOnCurrentThread()); return IsUserLoggedIn() && active_user_->GetType() == USER_TYPE_PUBLIC_ACCOUNT; } bool UserManagerBase::IsLoggedInAsGuest() const { - DCHECK(task_runner_->RunsTasksOnCurrentThread()); + DCHECK(!task_runner_ || task_runner_->RunsTasksOnCurrentThread()); return IsUserLoggedIn() && active_user_->GetType() == USER_TYPE_GUEST; } bool UserManagerBase::IsLoggedInAsSupervisedUser() const { - DCHECK(task_runner_->RunsTasksOnCurrentThread()); + DCHECK(!task_runner_ || task_runner_->RunsTasksOnCurrentThread()); return IsUserLoggedIn() && active_user_->GetType() == USER_TYPE_SUPERVISED; } bool UserManagerBase::IsLoggedInAsKioskApp() const { - DCHECK(task_runner_->RunsTasksOnCurrentThread()); + DCHECK(!task_runner_ || task_runner_->RunsTasksOnCurrentThread()); return IsUserLoggedIn() && active_user_->GetType() == USER_TYPE_KIOSK_APP; } bool UserManagerBase::IsLoggedInAsArcKioskApp() const { - DCHECK(task_runner_->RunsTasksOnCurrentThread()); + DCHECK(!task_runner_ || task_runner_->RunsTasksOnCurrentThread()); return IsUserLoggedIn() && active_user_->GetType() == USER_TYPE_ARC_KIOSK_APP; } bool UserManagerBase::IsLoggedInAsStub() const { - DCHECK(task_runner_->RunsTasksOnCurrentThread()); + DCHECK(!task_runner_ || task_runner_->RunsTasksOnCurrentThread()); return IsUserLoggedIn() && IsStubAccountId(active_user_->GetAccountId()); } @@ -648,41 +648,41 @@ } void UserManagerBase::AddObserver(UserManager::Observer* obs) { - DCHECK(task_runner_->RunsTasksOnCurrentThread()); + DCHECK(!task_runner_ || task_runner_->RunsTasksOnCurrentThread()); observer_list_.AddObserver(obs); } void UserManagerBase::RemoveObserver(UserManager::Observer* obs) { - DCHECK(task_runner_->RunsTasksOnCurrentThread()); + DCHECK(!task_runner_ || task_runner_->RunsTasksOnCurrentThread()); observer_list_.RemoveObserver(obs); } void UserManagerBase::AddSessionStateObserver( UserManager::UserSessionStateObserver* obs) { - DCHECK(task_runner_->RunsTasksOnCurrentThread()); + DCHECK(!task_runner_ || task_runner_->RunsTasksOnCurrentThread()); session_state_observer_list_.AddObserver(obs); } void UserManagerBase::RemoveSessionStateObserver( UserManager::UserSessionStateObserver* obs) { - DCHECK(task_runner_->RunsTasksOnCurrentThread()); + DCHECK(!task_runner_ || task_runner_->RunsTasksOnCurrentThread()); session_state_observer_list_.RemoveObserver(obs); } void UserManagerBase::NotifyLocalStateChanged() { - DCHECK(task_runner_->RunsTasksOnCurrentThread()); + DCHECK(!task_runner_ || task_runner_->RunsTasksOnCurrentThread()); for (auto& observer : observer_list_) observer.LocalStateChanged(this); } void UserManagerBase::NotifyUserImageChanged(const User& user) { - DCHECK(task_runner_->RunsTasksOnCurrentThread()); + DCHECK(!task_runner_ || task_runner_->RunsTasksOnCurrentThread()); for (auto& observer : observer_list_) observer.OnUserImageChanged(user); } void UserManagerBase::NotifyUserProfileImageUpdateFailed(const User& user) { - DCHECK(task_runner_->RunsTasksOnCurrentThread()); + DCHECK(!task_runner_ || task_runner_->RunsTasksOnCurrentThread()); for (auto& observer : observer_list_) observer.OnUserProfileImageUpdateFailed(user); } @@ -690,7 +690,7 @@ void UserManagerBase::NotifyUserProfileImageUpdated( const User& user, const gfx::ImageSkia& profile_image) { - DCHECK(task_runner_->RunsTasksOnCurrentThread()); + DCHECK(!task_runner_ || task_runner_->RunsTasksOnCurrentThread()); for (auto& observer : observer_list_) observer.OnUserProfileImageUpdated(user, profile_image); } @@ -752,7 +752,7 @@ } void UserManagerBase::EnsureUsersLoaded() { - DCHECK(task_runner_->RunsTasksOnCurrentThread()); + DCHECK(!task_runner_ || task_runner_->RunsTasksOnCurrentThread()); if (!GetLocalState()) return; @@ -863,7 +863,7 @@ } void UserManagerBase::GuestUserLoggedIn() { - DCHECK(task_runner_->RunsTasksOnCurrentThread()); + DCHECK(!task_runner_ || task_runner_->RunsTasksOnCurrentThread()); active_user_ = User::CreateGuestUser(GetGuestAccountId()); } @@ -898,14 +898,14 @@ void UserManagerBase::RegularUserLoggedInAsEphemeral( const AccountId& account_id) { - DCHECK(task_runner_->RunsTasksOnCurrentThread()); + DCHECK(!task_runner_ || task_runner_->RunsTasksOnCurrentThread()); SetIsCurrentUserNew(true); is_current_user_ephemeral_regular_user_ = true; active_user_ = User::CreateRegularUser(account_id); } void UserManagerBase::NotifyOnLogin() { - DCHECK(task_runner_->RunsTasksOnCurrentThread()); + DCHECK(!task_runner_ || task_runner_->RunsTasksOnCurrentThread()); NotifyActiveUserHashChanged(active_user_->username_hash()); NotifyActiveUserChanged(active_user_); @@ -914,7 +914,7 @@ User::OAuthTokenStatus UserManagerBase::LoadUserOAuthStatus( const AccountId& account_id) const { - DCHECK(task_runner_->RunsTasksOnCurrentThread()); + DCHECK(!task_runner_ || task_runner_->RunsTasksOnCurrentThread()); const base::DictionaryValue* prefs_oauth_status = GetLocalState()->GetDictionary(kUserOAuthTokenStatus); @@ -932,7 +932,7 @@ } bool UserManagerBase::LoadForceOnlineSignin(const AccountId& account_id) const { - DCHECK(task_runner_->RunsTasksOnCurrentThread()); + DCHECK(!task_runner_ || task_runner_->RunsTasksOnCurrentThread()); const base::DictionaryValue* prefs_force_online = GetLocalState()->GetDictionary(kUserForceOnlineSignin); @@ -997,26 +997,26 @@ } void UserManagerBase::NotifyActiveUserChanged(const User* active_user) { - DCHECK(task_runner_->RunsTasksOnCurrentThread()); + DCHECK(!task_runner_ || task_runner_->RunsTasksOnCurrentThread()); for (auto& observer : session_state_observer_list_) observer.ActiveUserChanged(active_user); } void UserManagerBase::NotifyUserAddedToSession(const User* added_user, bool user_switch_pending) { - DCHECK(task_runner_->RunsTasksOnCurrentThread()); + DCHECK(!task_runner_ || task_runner_->RunsTasksOnCurrentThread()); for (auto& observer : session_state_observer_list_) observer.UserAddedToSession(added_user); } void UserManagerBase::NotifyActiveUserHashChanged(const std::string& hash) { - DCHECK(task_runner_->RunsTasksOnCurrentThread()); + DCHECK(!task_runner_ || task_runner_->RunsTasksOnCurrentThread()); for (auto& observer : session_state_observer_list_) observer.ActiveUserHashChanged(hash); } void UserManagerBase::ChangeUserChildStatus(User* user, bool is_child) { - DCHECK(task_runner_->RunsTasksOnCurrentThread()); + DCHECK(!task_runner_ || task_runner_->RunsTasksOnCurrentThread()); if (user->IsSupervised() == is_child) return; user->SetIsChild(is_child);
diff --git a/components/variations/service/variations_service.cc b/components/variations/service/variations_service.cc index 826fe0d8..e669699 100644 --- a/components/variations/service/variations_service.cc +++ b/components/variations/service/variations_service.cc
@@ -8,6 +8,7 @@ #include <stdint.h> #include <utility> +#include <vector> #include "base/build_time.h" #include "base/command_line.h" @@ -336,9 +337,7 @@ GetChannelForVariations(client_->GetChannel()); UMA_HISTOGRAM_SPARSE_SLOWLY("Variations.UserChannel", channel); - const std::string latest_country = - local_state_->GetString(prefs::kVariationsCountry); - + const std::string latest_country = GetLatestCountry(); std::unique_ptr<const base::FieldTrial::EntropyProvider> low_entropy_provider( CreateLowEntropyProvider()); // Note that passing |&ui_string_overrider_| via base::Unretained below is @@ -780,8 +779,7 @@ variations::VariationsSeedSimulator seed_simulator(*default_provider, *low_provider); - const std::string latest_country = - local_state_->GetString(prefs::kVariationsCountry); + const std::string latest_country = GetLatestCountry(); const variations::VariationsSeedSimulator::Result result = seed_simulator.SimulateSeedStudies( *seed, client_->GetApplicationLocale(), @@ -823,6 +821,12 @@ DCHECK(thread_checker_.CalledOnValidThread()); DCHECK(version.IsValid()); + const std::string override_country = + base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII( + switches::kVariationsOverrideCountry); + if (!override_country.empty()) + return override_country; + const base::ListValue* list_value = local_state_->GetList(prefs::kVariationsPermanentConsistencyCountry); std::string stored_version_string; @@ -930,7 +934,12 @@ } std::string VariationsService::GetLatestCountry() const { - return local_state_->GetString(prefs::kVariationsCountry); + const std::string override_country = + base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII( + switches::kVariationsOverrideCountry); + return !override_country.empty() + ? override_country + : local_state_->GetString(prefs::kVariationsCountry); } } // namespace variations
diff --git a/components/variations/variations_switches.cc b/components/variations/variations_switches.cc index 0bc8e82..5b19c66 100644 --- a/components/variations/variations_switches.cc +++ b/components/variations/variations_switches.cc
@@ -26,6 +26,13 @@ // escaped for all non-alphanumeric characters. const char kForceFieldTrialParams[] = "force-fieldtrial-params"; +// Allows overriding the country used for evaluating variations. This is similar +// to the "Override Variations Country" entry on chrome://translate-internals, +// but is exposed as a command-line flag to allow testing First Run scenarios. +// Additionally, unlike chrome://translate-internals, the value isn't persisted +// across sessions. +const char kVariationsOverrideCountry[] = "variations-override-country"; + // Specifies a custom URL for the server which reports variation data to the // client. Specifying this switch enables the Variations service on // unofficial builds. See variations_service.cc.
diff --git a/components/variations/variations_switches.h b/components/variations/variations_switches.h index adebf9b1..9755dac4 100644 --- a/components/variations/variations_switches.h +++ b/components/variations/variations_switches.h
@@ -14,6 +14,7 @@ extern const char kDisableFieldTrialTestingConfig[]; extern const char kFakeVariationsChannel[]; extern const char kForceFieldTrialParams[]; +extern const char kVariationsOverrideCountry[]; extern const char kVariationsServerURL[]; } // namespace switches
diff --git a/content/browser/frame_host/render_widget_host_view_child_frame.cc b/content/browser/frame_host/render_widget_host_view_child_frame.cc index d8dfac8..59efca1 100644 --- a/content/browser/frame_host/render_widget_host_view_child_frame.cc +++ b/content/browser/frame_host/render_widget_host_view_child_frame.cc
@@ -232,6 +232,11 @@ // to be a main frame. This should be cleaned up eventually. bool is_guest = BrowserPluginGuest::IsGuest(RenderViewHostImpl::From(host_)); if (frame_connector_ && !is_guest) { + // An auto-resize set by the top-level frame overrides what would be + // reported by embedding RenderWidgetHostViews. + if (host_->delegate() && !host_->delegate()->GetAutoResizeSize().IsEmpty()) + return host_->delegate()->GetAutoResizeSize(); + RenderWidgetHostView* parent_view = frame_connector_->GetParentRenderWidgetHostView(); // The parent_view can be null in unit tests when using a TestWebContents.
diff --git a/content/browser/frame_host/render_widget_host_view_child_frame_browsertest.cc b/content/browser/frame_host/render_widget_host_view_child_frame_browsertest.cc index b27892ce..d03ebb4b 100644 --- a/content/browser/frame_host/render_widget_host_view_child_frame_browsertest.cc +++ b/content/browser/frame_host/render_widget_host_view_child_frame_browsertest.cc
@@ -3,7 +3,9 @@ // found in the LICENSE file. #include "base/macros.h" +#include "content/browser/frame_host/frame_tree_node.h" #include "content/browser/web_contents/web_contents_impl.h" +#include "content/common/view_messages.h" #include "content/public/browser/render_frame_host.h" #include "content/public/browser/web_contents.h" #include "content/public/test/browser_test_utils.h" @@ -15,6 +17,7 @@ #include "content/test/test_content_browser_client.h" #include "net/dns/mock_host_resolver.h" #include "net/test/embedded_test_server/embedded_test_server.h" +#include "ui/gfx/geometry/size.h" namespace content { @@ -73,4 +76,42 @@ base::Unretained(this))); } +// Test that auto-resize sizes in the top frame are propagated to OOPIF +// RenderWidgetHostViews. See https://crbug.com/726743. +IN_PROC_BROWSER_TEST_F(RenderWidgetHostViewChildFrameTest, + ChildFrameAutoResizeUpdate) { + EXPECT_TRUE(NavigateToURL( + shell(), embedded_test_server()->GetURL( + "a.com", "/cross_site_iframe_factory.html?a(b)"))); + + FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents()) + ->GetFrameTree() + ->root(); + root->current_frame_host()->render_view_host()->EnableAutoResize( + gfx::Size(0, 0), gfx::Size(100, 100)); + + RenderWidgetHostView* rwhv = + root->child_at(0)->current_frame_host()->GetRenderWidgetHost()->GetView(); + + // Fake an auto-resize update from the parent renderer. + int routing_id = + root->current_frame_host()->GetRenderWidgetHost()->GetRoutingID(); + ViewHostMsg_UpdateRect_Params params; + params.view_size = gfx::Size(75, 75); + params.flags = 0; + root->current_frame_host()->GetRenderWidgetHost()->OnMessageReceived( + ViewHostMsg_UpdateRect(routing_id, params)); + + // RenderWidgetHostImpl has delayed auto-resize processing. Yield here to + // let it complete. + base::RunLoop run_loop; + base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, + run_loop.QuitClosure()); + run_loop.Run(); + + // The child frame's RenderWidgetHostView should now use the auto-resize value + // for its visible viewport. + EXPECT_EQ(gfx::Size(75, 75), rwhv->GetVisibleViewportSize()); +} + } // namespace content
diff --git a/content/browser/indexed_db/database_impl.cc b/content/browser/indexed_db/database_impl.cc index 4b72469d..7d08361 100644 --- a/content/browser/indexed_db/database_impl.cc +++ b/content/browser/indexed_db/database_impl.cc
@@ -871,7 +871,10 @@ if (!transaction) return; - connection_->AbortTransaction(transaction); + connection_->AbortTransaction( + transaction, + IndexedDBDatabaseError(blink::kWebIDBDatabaseExceptionAbortError, + "Transaction aborted by user.")); } void DatabaseImpl::IDBThreadHelper::AbortWithError(
diff --git a/content/browser/indexed_db/indexed_db_connection.cc b/content/browser/indexed_db/indexed_db_connection.cc index a541a70f..c7744d4 100644 --- a/content/browser/indexed_db/indexed_db_connection.cc +++ b/content/browser/indexed_db/indexed_db_connection.cc
@@ -116,11 +116,6 @@ return transaction_ptr; } -void IndexedDBConnection::AbortTransaction(IndexedDBTransaction* transaction) { - IDB_TRACE1("IndexedDBDatabase::Abort", "txn.id", transaction->id()); - transaction->Abort(); -} - void IndexedDBConnection::AbortTransaction( IndexedDBTransaction* transaction, const IndexedDBDatabaseError& error) {
diff --git a/content/browser/indexed_db/indexed_db_connection.h b/content/browser/indexed_db/indexed_db_connection.h index e69119557..ea3b8542 100644 --- a/content/browser/indexed_db/indexed_db_connection.h +++ b/content/browser/indexed_db/indexed_db_connection.h
@@ -62,7 +62,6 @@ blink::WebIDBTransactionMode mode, IndexedDBBackingStore::Transaction* backing_store_transaction); - void AbortTransaction(IndexedDBTransaction* transaction); void AbortTransaction(IndexedDBTransaction* transaction, const IndexedDBDatabaseError& error);
diff --git a/content/browser/indexed_db/indexed_db_database_error.h b/content/browser/indexed_db/indexed_db_database_error.h index 6106f75..0cb060c 100644 --- a/content/browser/indexed_db/indexed_db_database_error.h +++ b/content/browser/indexed_db/indexed_db_database_error.h
@@ -9,10 +9,11 @@ #include "base/strings/string16.h" #include "base/strings/utf_string_conversions.h" +#include "content/common/content_export.h" namespace content { -class IndexedDBDatabaseError { +class CONTENT_EXPORT IndexedDBDatabaseError { public: IndexedDBDatabaseError(); explicit IndexedDBDatabaseError(uint16_t code);
diff --git a/content/browser/indexed_db/indexed_db_transaction.cc b/content/browser/indexed_db/indexed_db_transaction.cc index e1a3a5b..bc7bfccd 100644 --- a/content/browser/indexed_db/indexed_db_transaction.cc +++ b/content/browser/indexed_db/indexed_db_transaction.cc
@@ -177,11 +177,6 @@ ptr_factory_.GetWeakPtr())); } -void IndexedDBTransaction::Abort() { - Abort(IndexedDBDatabaseError(blink::kWebIDBDatabaseExceptionUnknownError, - "Internal error (unknown cause)")); -} - void IndexedDBTransaction::Abort(const IndexedDBDatabaseError& error) { IDB_TRACE1("IndexedDBTransaction::Abort", "txn.id", id()); DCHECK(!processing_event_queue_);
diff --git a/content/browser/indexed_db/indexed_db_transaction.h b/content/browser/indexed_db/indexed_db_transaction.h index ba1e6ce..fdd2cdb 100644 --- a/content/browser/indexed_db/indexed_db_transaction.h +++ b/content/browser/indexed_db/indexed_db_transaction.h
@@ -49,8 +49,7 @@ leveldb::Status Commit(); - // This object is destroyed by these method calls. - virtual void Abort(); + // This object is destroyed by this method. void Abort(const IndexedDBDatabaseError& error); // Called by the transaction coordinator when this transaction is unblocked.
diff --git a/content/browser/indexed_db/indexed_db_transaction_unittest.cc b/content/browser/indexed_db/indexed_db_transaction_unittest.cc index 06fe219..ee58580d 100644 --- a/content/browser/indexed_db/indexed_db_transaction_unittest.cc +++ b/content/browser/indexed_db/indexed_db_transaction_unittest.cc
@@ -14,12 +14,14 @@ #include "base/run_loop.h" #include "base/strings/utf_string_conversions.h" #include "content/browser/indexed_db/indexed_db_connection.h" +#include "content/browser/indexed_db/indexed_db_database_error.h" #include "content/browser/indexed_db/indexed_db_fake_backing_store.h" #include "content/browser/indexed_db/indexed_db_observer.h" #include "content/browser/indexed_db/mock_indexed_db_database_callbacks.h" #include "content/browser/indexed_db/mock_indexed_db_factory.h" #include "content/public/test/test_browser_thread_bundle.h" #include "testing/gtest/include/gtest/gtest.h" +#include "third_party/WebKit/public/platform/modules/indexeddb/WebIDBDatabaseException.h" namespace content { const int kFakeProcessId = 10; @@ -161,7 +163,9 @@ EXPECT_FALSE(transaction->IsTimeoutTimerRunning()); // Clean up to avoid leaks. - transaction->Abort(); + transaction->Abort(IndexedDBDatabaseError( + IndexedDBDatabaseError(blink::kWebIDBDatabaseExceptionAbortError, + "Transaction aborted by user."))); EXPECT_EQ(IndexedDBTransaction::FINISHED, transaction->state()); EXPECT_FALSE(transaction->IsTimeoutTimerRunning()); } @@ -411,7 +415,9 @@ RunPostedTasks(); - transaction->Abort(); + transaction->Abort( + IndexedDBDatabaseError(blink::kWebIDBDatabaseExceptionAbortError, + "Transaction aborted by user.")); EXPECT_EQ(IndexedDBTransaction::FINISHED, transaction->state()); EXPECT_FALSE(transaction->IsTimeoutTimerRunning()); EXPECT_EQ(0, transaction->pending_preemptive_events_);
diff --git a/content/browser/loader/resource_handler.cc b/content/browser/loader/resource_handler.cc index 961934d..0f87551 100644 --- a/content/browser/loader/resource_handler.cc +++ b/content/browser/loader/resource_handler.cc
@@ -16,7 +16,9 @@ delegate_ = delegate; } -ResourceHandler::~ResourceHandler() {} +ResourceHandler::~ResourceHandler() { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); +} ResourceHandler::ResourceHandler(net::URLRequest* request) : request_(request) {}
diff --git a/content/browser/loader/resource_handler.h b/content/browser/loader/resource_handler.h index c292cab2..2b67e0c4 100644 --- a/content/browser/loader/resource_handler.h +++ b/content/browser/loader/resource_handler.h
@@ -18,7 +18,7 @@ #include "base/compiler_specific.h" #include "base/macros.h" #include "base/memory/ref_counted.h" -#include "base/threading/non_thread_safe.h" +#include "base/sequence_checker.h" #include "content/browser/loader/resource_controller.h" #include "content/common/content_export.h" @@ -43,8 +43,7 @@ // No ResourceHandler method other than OnWillRead will ever be called // synchronously when it calls into the ResourceController passed in to it, // either to resume or cancel the request. -class CONTENT_EXPORT ResourceHandler - : public NON_EXPORTED_BASE(base::NonThreadSafe) { +class CONTENT_EXPORT ResourceHandler { public: virtual ~ResourceHandler(); @@ -176,6 +175,8 @@ Delegate* delegate_; std::unique_ptr<ResourceController> controller_; + SEQUENCE_CHECKER(sequence_checker_); + DISALLOW_COPY_AND_ASSIGN(ResourceHandler); };
diff --git a/content/browser/renderer_host/render_view_host_impl.cc b/content/browser/renderer_host/render_view_host_impl.cc index df1962ab..ee956813 100644 --- a/content/browser/renderer_host/render_view_host_impl.cc +++ b/content/browser/renderer_host/render_view_host_impl.cc
@@ -933,6 +933,10 @@ Send(new ViewMsg_DisableAutoResize(GetRoutingID(), new_size)); if (!new_size.IsEmpty()) GetWidget()->GetView()->SetSize(new_size); + // This clears the cached value in the WebContents, so that OOPIFs will + // stop using it. + if (GetWidget()->delegate()) + GetWidget()->delegate()->ResetAutoResizeSize(); } void RenderViewHostImpl::ExecuteMediaPlayerActionAtLocation(
diff --git a/content/browser/renderer_host/render_widget_host_delegate.cc b/content/browser/renderer_host/render_widget_host_delegate.cc index cb32ee9..2cad1fb9 100644 --- a/content/browser/renderer_host/render_widget_host_delegate.cc +++ b/content/browser/renderer_host/render_widget_host_delegate.cc
@@ -111,6 +111,10 @@ ukm::UkmRecorder* service, ukm::SourceId ukm_source_id) {} +gfx::Size RenderWidgetHostDelegate::GetAutoResizeSize() { + return gfx::Size(); +} + WebContents* RenderWidgetHostDelegate::GetAsWebContents() { return nullptr; }
diff --git a/content/browser/renderer_host/render_widget_host_delegate.h b/content/browser/renderer_host/render_widget_host_delegate.h index ca56a9d..29b3115 100644 --- a/content/browser/renderer_host/render_widget_host_delegate.h +++ b/content/browser/renderer_host/render_widget_host_delegate.h
@@ -266,6 +266,12 @@ // Notifies that a CompositorFrame was received from the renderer. virtual void DidReceiveCompositorFrame() {} + // Gets the size set by a top-level frame with auto-resize enabled. + virtual gfx::Size GetAutoResizeSize(); + + // Reset the auto-size value, to indicate that auto-size is no longer active. + virtual void ResetAutoResizeSize() {} + protected: virtual ~RenderWidgetHostDelegate() {} };
diff --git a/content/browser/speech/speech_recognition_engine.cc b/content/browser/speech/speech_recognition_engine.cc index b6bd1d5..bd99e7a 100644 --- a/content/browser/speech/speech_recognition_engine.cc +++ b/content/browser/speech/speech_recognition_engine.cc
@@ -102,7 +102,9 @@ use_framed_post_data_(false), state_(STATE_IDLE) {} -SpeechRecognitionEngine::~SpeechRecognitionEngine() {} +SpeechRecognitionEngine::~SpeechRecognitionEngine() { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); +} void SpeechRecognitionEngine::SetConfig(const Config& config) { config_ = config; @@ -145,7 +147,7 @@ void SpeechRecognitionEngine::DispatchHTTPResponse(const URLFetcher* source, bool end_of_response) { - DCHECK(CalledOnValidThread()); + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); DCHECK(source); const bool response_is_good = source->GetStatus().is_success() && source->GetResponseCode() == 200; @@ -214,7 +216,7 @@ } bool SpeechRecognitionEngine::IsRecognitionPending() const { - DCHECK(CalledOnValidThread()); + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); return state_ != STATE_IDLE; } @@ -226,7 +228,7 @@ void SpeechRecognitionEngine::DispatchEvent( const FSMEventArgs& event_args) { - DCHECK(CalledOnValidThread()); + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); DCHECK_LE(event_args.event, EVENT_MAX_VALUE); DCHECK_LE(state_, STATE_MAX_VALUE);
diff --git a/content/browser/speech/speech_recognition_engine.h b/content/browser/speech/speech_recognition_engine.h index e7a2535..9792d3aaa 100644 --- a/content/browser/speech/speech_recognition_engine.h +++ b/content/browser/speech/speech_recognition_engine.h
@@ -12,7 +12,7 @@ #include "base/macros.h" #include "base/memory/ref_counted.h" -#include "base/threading/non_thread_safe.h" +#include "base/sequence_checker.h" #include "content/browser/speech/audio_encoder.h" #include "content/browser/speech/chunked_byte_buffer.h" #include "content/common/content_export.h" @@ -57,9 +57,7 @@ // EndRecognition. If a recognition was started, the caller can free the // SpeechRecognitionEngine only after calling EndRecognition. -class CONTENT_EXPORT SpeechRecognitionEngine - : public net::URLFetcherDelegate, - public NON_EXPORTED_BASE(base::NonThreadSafe) { +class CONTENT_EXPORT SpeechRecognitionEngine : public net::URLFetcherDelegate { public: class Delegate { public: @@ -216,6 +214,8 @@ bool use_framed_post_data_; FSMState state_; + SEQUENCE_CHECKER(sequence_checker_); + DISALLOW_COPY_AND_ASSIGN(SpeechRecognitionEngine); };
diff --git a/content/browser/web_contents/web_contents_impl.cc b/content/browser/web_contents/web_contents_impl.cc index 626c4c8..cef65a9 100644 --- a/content/browser/web_contents/web_contents_impl.cc +++ b/content/browser/web_contents/web_contents_impl.cc
@@ -2787,10 +2787,32 @@ if (render_widget_host != GetRenderViewHost()->GetWidget()) return; + auto_resize_size_ = new_size; + + // Out-of-process iframe visible viewport sizes usually come from the + // top-level RenderWidgetHostView, but when auto-resize is enabled on the + // top frame then that size is used instead. + for (FrameTreeNode* node : frame_tree_.Nodes()) { + if (node->current_frame_host()->is_local_root()) { + RenderWidgetHostImpl* host = + node->current_frame_host()->GetRenderWidgetHost(); + if (host != render_widget_host) + host->WasResized(); + } + } + if (delegate_) delegate_->ResizeDueToAutoResize(this, new_size); } +gfx::Size WebContentsImpl::GetAutoResizeSize() { + return auto_resize_size_; +} + +void WebContentsImpl::ResetAutoResizeSize() { + auto_resize_size_ = gfx::Size(); +} + WebContents* WebContentsImpl::OpenURL(const OpenURLParams& params) { if (!delegate_) return NULL;
diff --git a/content/browser/web_contents/web_contents_impl.h b/content/browser/web_contents/web_contents_impl.h index e71d078c..3b58932 100644 --- a/content/browser/web_contents/web_contents_impl.h +++ b/content/browser/web_contents/web_contents_impl.h
@@ -668,6 +668,8 @@ bool width_changed) override; void ResizeDueToAutoResize(RenderWidgetHostImpl* render_widget_host, const gfx::Size& new_size) override; + gfx::Size GetAutoResizeSize() override; + void ResetAutoResizeSize() override; void ScreenInfoChanged() override; void UpdateDeviceScaleFactor(double device_scale_factor) override; void GetScreenInfo(ScreenInfo* screen_info) override; @@ -1446,6 +1448,10 @@ // this overrides |preferred_size_|. gfx::Size preferred_size_for_capture_; + // Size set by a top-level frame with auto-resize enabled. This is needed by + // out-of-process iframes for their visible viewport size. + gfx::Size auto_resize_size_; + #if defined(OS_ANDROID) // Date time chooser opened by this tab. // Only used in Android since all other platforms use a multi field UI.
diff --git a/content/child/fileapi/webfilesystem_impl.cc b/content/child/fileapi/webfilesystem_impl.cc index 8c55be9..f34ea12 100644 --- a/content/child/fileapi/webfilesystem_impl.cc +++ b/content/child/fileapi/webfilesystem_impl.cc
@@ -97,7 +97,7 @@ const scoped_refptr<base::SingleThreadTaskRunner>& main_thread_task_runner, Method method, const Params& params, WaitableCallbackResults* waitable_results) { - if (!main_thread_task_runner->RunsTasksInCurrentSequence()) { + if (!main_thread_task_runner->BelongsToCurrentThread()) { main_thread_task_runner->PostTask( FROM_HERE, base::Bind(&CallDispatcherOnMainThread<Method, Params>, @@ -397,7 +397,7 @@ } WebFileSystemImpl::~WebFileSystemImpl() { - DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); g_webfilesystem_tls.Pointer()->Set(NULL); } @@ -655,21 +655,21 @@ int WebFileSystemImpl::RegisterCallbacks( const WebFileSystemCallbacks& callbacks) { - DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); int id = next_callbacks_id_++; callbacks_[id] = callbacks; return id; } WebFileSystemCallbacks WebFileSystemImpl::GetCallbacks(int callbacks_id) { - DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); CallbacksMap::iterator found = callbacks_.find(callbacks_id); DCHECK(found != callbacks_.end()); return found->second; } void WebFileSystemImpl::UnregisterCallbacks(int callbacks_id) { - DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); CallbacksMap::iterator found = callbacks_.find(callbacks_id); DCHECK(found != callbacks_.end()); callbacks_.erase(found);
diff --git a/content/child/fileapi/webfilesystem_impl.h b/content/child/fileapi/webfilesystem_impl.h index 4efe2f9..133becd2 100644 --- a/content/child/fileapi/webfilesystem_impl.h +++ b/content/child/fileapi/webfilesystem_impl.h
@@ -10,7 +10,7 @@ #include "base/compiler_specific.h" #include "base/macros.h" #include "base/memory/ref_counted.h" -#include "base/sequence_checker.h" +#include "base/threading/thread_checker.h" #include "content/public/child/worker_thread.h" #include "third_party/WebKit/public/platform/WebFileSystem.h" @@ -106,7 +106,8 @@ int next_callbacks_id_; WaitableCallbackResultsMap waitable_results_; - SEQUENCE_CHECKER(sequence_checker_); + // Thread-affine per use of TLS in impl. + THREAD_CHECKER(thread_checker_); DISALLOW_COPY_AND_ASSIGN(WebFileSystemImpl); };
diff --git a/content/renderer/gpu/compositor_external_begin_frame_source.cc b/content/renderer/gpu/compositor_external_begin_frame_source.cc index 421415e4..5e14b87f 100644 --- a/content/renderer/gpu/compositor_external_begin_frame_source.cc +++ b/content/renderer/gpu/compositor_external_begin_frame_source.cc
@@ -20,11 +20,11 @@ routing_id_(routing_id) { DCHECK(begin_frame_source_filter_); DCHECK(message_sender_); - DetachFromThread(); + DETACH_FROM_THREAD(thread_checker_); } CompositorExternalBeginFrameSource::~CompositorExternalBeginFrameSource() { - DCHECK(CalledOnValidThread()); + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); if (begin_frame_source_proxy_) { begin_frame_source_proxy_->ClearBeginFrameSource(); begin_frame_source_filter_->RemoveHandlerOnCompositorThread( @@ -35,7 +35,7 @@ void CompositorExternalBeginFrameSource::AddObserver( cc::BeginFrameObserver* obs) { - DCHECK(CalledOnValidThread()); + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); if (!begin_frame_source_proxy_) { begin_frame_source_proxy_ = @@ -71,7 +71,7 @@ void CompositorExternalBeginFrameSource::OnMessageReceived( const IPC::Message& message) { - DCHECK(CalledOnValidThread()); + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); DCHECK(begin_frame_source_proxy_); IPC_BEGIN_MESSAGE_MAP(CompositorExternalBeginFrameSource, message) IPC_MESSAGE_HANDLER(ViewMsg_SetBeginFramePaused,
diff --git a/content/renderer/gpu/compositor_external_begin_frame_source.h b/content/renderer/gpu/compositor_external_begin_frame_source.h index 96520a02..7765a675 100644 --- a/content/renderer/gpu/compositor_external_begin_frame_source.h +++ b/content/renderer/gpu/compositor_external_begin_frame_source.h
@@ -10,7 +10,7 @@ #include "base/compiler_specific.h" #include "base/macros.h" #include "base/memory/ref_counted.h" -#include "base/threading/non_thread_safe.h" +#include "base/threading/thread_checker.h" #include "cc/scheduler/begin_frame_source.h" #include "content/renderer/gpu/compositor_forwarding_message_filter.h" @@ -31,8 +31,7 @@ // directly rather than proxied by this class. class CompositorExternalBeginFrameSource : public cc::BeginFrameSource, - public cc::ExternalBeginFrameSourceClient, - public NON_EXPORTED_BASE(base::NonThreadSafe) { + public cc::ExternalBeginFrameSourceClient { public: explicit CompositorExternalBeginFrameSource( CompositorForwardingMessageFilter* filter, @@ -88,6 +87,8 @@ int routing_id_; CompositorForwardingMessageFilter::Handler begin_frame_source_filter_handler_; + THREAD_CHECKER(thread_checker_); + DISALLOW_COPY_AND_ASSIGN(CompositorExternalBeginFrameSource); };
diff --git a/content/renderer/render_view_browsertest.cc b/content/renderer/render_view_browsertest.cc index a7f6ff2..868a9c16 100644 --- a/content/renderer/render_view_browsertest.cc +++ b/content/renderer/render_view_browsertest.cc
@@ -2194,7 +2194,8 @@ TEST_F(RenderViewImplTest, PreferredSizeZoomed) { LoadHTML("<body style='margin:0;'><div style='display:inline-block; " "width:400px; height:400px;'/></body>"); - view()->webview()->MainFrame()->SetCanHaveScrollbars(false); + view()->webview()->MainFrame()->ToWebLocalFrame()->SetCanHaveScrollbars( + false); EnablePreferredSizeMode(); gfx::Size size = GetPreferredSize();
diff --git a/content/renderer/render_view_impl.cc b/content/renderer/render_view_impl.cc index 39f9432e..35718fb 100644 --- a/content/renderer/render_view_impl.cc +++ b/content/renderer/render_view_impl.cc
@@ -2189,8 +2189,9 @@ webview()->HidePopups(); if (send_preferred_size_changes_ && webview()->MainFrame()->IsWebLocalFrame()) { - webview()->MainFrame()->SetCanHaveScrollbars(ShouldDisplayScrollbars( - params.new_size.width(), params.new_size.height())); + webview()->MainFrame()->ToWebLocalFrame()->SetCanHaveScrollbars( + ShouldDisplayScrollbars(params.new_size.width(), + params.new_size.height())); } if (display_mode_ != params.display_mode) { display_mode_ = params.display_mode;
diff --git a/extensions/browser/api/app_window/app_window_apitest.cc b/extensions/browser/api/app_window/app_window_apitest.cc index 2ad9886..f3685fb 100644 --- a/extensions/browser/api/app_window/app_window_apitest.cc +++ b/extensions/browser/api/app_window/app_window_apitest.cc
@@ -30,61 +30,28 @@ namespace extensions { -namespace { - -class TestAppWindowRegistryObserver : public AppWindowRegistry::Observer { - public: - explicit TestAppWindowRegistryObserver(Profile* profile) - : profile_(profile), icon_updates_(0) { - AppWindowRegistry::Get(profile_)->AddObserver(this); - } - ~TestAppWindowRegistryObserver() override { - AppWindowRegistry::Get(profile_)->RemoveObserver(this); - } - - // Overridden from AppWindowRegistry::Observer: - void OnAppWindowIconChanged(AppWindow* app_window) override { - ++icon_updates_; - } - - int icon_updates() { return icon_updates_; } - - private: - Profile* profile_; - int icon_updates_; - - DISALLOW_COPY_AND_ASSIGN(TestAppWindowRegistryObserver); -}; - -} // namespace - using AppWindowApiTest = PlatformAppBrowserTest; using ExperimentalAppWindowApiTest = ExperimentalPlatformAppBrowserTest; // Tests chrome.app.window.setIcon. -// Flaky test crbug.com/716726 -IN_PROC_BROWSER_TEST_F(ExperimentalAppWindowApiTest, DISABLED_SetIcon) { - std::unique_ptr<TestAppWindowRegistryObserver> test_observer( - new TestAppWindowRegistryObserver(browser()->profile())); +IN_PROC_BROWSER_TEST_F(ExperimentalAppWindowApiTest, SetIcon) { ExtensionTestMessageListener listener("ready", true); // Launch the app and wait for it to be ready. LoadAndLaunchPlatformApp("windows_api_set_icon", &listener); - EXPECT_EQ(0, test_observer->icon_updates()); listener.Reply(""); + AppWindow* app_window = GetFirstAppWindow(); + ASSERT_TRUE(app_window); + // Now wait until the WebContent has decoded the icon and chrome has // processed it. This needs to be in a loop since the renderer runs in a // different process. - while (test_observer->icon_updates() < 1) { - base::RunLoop run_loop; - run_loop.RunUntilIdle(); - } - AppWindow* app_window = GetFirstAppWindow(); - ASSERT_TRUE(app_window); + while (app_window->custom_app_icon().IsEmpty()) + base::RunLoop().RunUntilIdle(); + EXPECT_NE(std::string::npos, app_window->app_icon_url().spec().find("icon.png")); - EXPECT_EQ(1, test_observer->icon_updates()); } // TODO(asargent) - Figure out what to do about the fact that minimize events
diff --git a/extensions/browser/app_window/app_delegate.h b/extensions/browser/app_window/app_delegate.h index 356f1ec7..1cdd50f2 100644 --- a/extensions/browser/app_window/app_delegate.h +++ b/extensions/browser/app_window/app_delegate.h
@@ -70,7 +70,7 @@ const GURL& security_origin, content::MediaStreamType type, const Extension* extension) = 0; - virtual int PreferredIconSize() = 0; + virtual int PreferredIconSize() const = 0; // Web contents modal dialog support. virtual void SetWebContentsBlocked(content::WebContents* web_contents,
diff --git a/extensions/browser/app_window/app_window.cc b/extensions/browser/app_window/app_window.cc index 86fe183..a0e4b1d 100644 --- a/extensions/browser/app_window/app_window.cc +++ b/extensions/browser/app_window/app_window.cc
@@ -49,13 +49,11 @@ #include "extensions/common/extension.h" #include "extensions/common/manifest_handlers/icons_handler.h" #include "extensions/common/permissions/permissions_data.h" -#include "extensions/grit/extensions_browser_resources.h" +#include "third_party/skia/include/core/SkBitmap.h" #include "third_party/skia/include/core/SkRegion.h" -#include "ui/base/resource/resource_bundle.h" #include "ui/display/display.h" #include "ui/display/screen.h" #include "ui/events/keycodes/keyboard_codes.h" -#include "ui/gfx/image/image_skia_operations.h" #if !defined(OS_MACOSX) #include "components/prefs/pref_service.h" @@ -293,7 +291,6 @@ requested_alpha_enabled_ = new_params.alpha_enabled; is_ime_window_ = params.is_ime_window; show_in_shelf_ = params.show_in_shelf; - window_icon_url_ = params.window_icon_url; AppWindowClient* app_window_client = AppWindowClient::Get(); native_app_window_.reset( @@ -302,10 +299,10 @@ helper_.reset(new AppWebContentsHelper( browser_context_, extension_id_, web_contents(), app_delegate_.get())); - UpdateExtensionAppIcon(); - // Download showInShelf=true window icon. - if (window_icon_url_.is_valid()) - SetAppIconUrl(window_icon_url_); + native_app_window_->UpdateWindowIcon(); + + if (params.window_icon_url.is_valid()) + SetAppIconUrl(params.window_icon_url); AppWindowRegistry::Get(browser_context_)->AddAppWindow(this); @@ -561,22 +558,10 @@ return title; } -bool AppWindow::HasCustomIcon() const { - return window_icon_url_.is_valid() || app_icon_url_.is_valid(); -} - void AppWindow::SetAppIconUrl(const GURL& url) { // Avoid using any previous icons that were being downloaded. image_loader_ptr_factory_.InvalidateWeakPtrs(); - - // Reset |app_icon_image_| to abort pending image load (if any). - if (!show_in_shelf_) { - app_icon_image_.reset(); - app_icon_url_ = url; - } else { - window_icon_url_ = url; - } - + app_icon_url_ = url; web_contents()->DownloadImage( url, true, // is a favicon @@ -596,38 +581,10 @@ } void AppWindow::UpdateAppIcon(const gfx::Image& image) { - // Set the showInShelf=true window icon and add the app_icon_image_ - // as a badge. If the image is empty, set the default app icon placeholder - // as the base image. - if (window_icon_url_.is_valid() && app_icon_image_ && - !app_icon_image_->image().IsEmpty()) { - gfx::Image base_image = - !image.IsEmpty() - ? image - : gfx::Image(*ResourceBundle::GetSharedInstance().GetImageSkiaNamed( - IDR_APP_DEFAULT_ICON)); - // Scale the icon to EXTENSION_ICON_LARGE. - const int large_icon_size = extension_misc::EXTENSION_ICON_LARGE; - if (base_image.Width() != large_icon_size || - base_image.Height() != large_icon_size) { - gfx::ImageSkia resized_image = - gfx::ImageSkiaOperations::CreateResizedImage( - base_image.AsImageSkia(), skia::ImageOperations::RESIZE_BEST, - gfx::Size(large_icon_size, large_icon_size)); - app_icon_ = gfx::Image(gfx::ImageSkiaOperations::CreateIconWithBadge( - resized_image, app_icon_image_->image_skia())); - } else { - app_icon_ = gfx::Image(gfx::ImageSkiaOperations::CreateIconWithBadge( - base_image.AsImageSkia(), app_icon_image_->image_skia())); - } - } else { - if (image.IsEmpty()) - return; - - app_icon_ = image; - } + if (image.IsEmpty()) + return; + custom_app_icon_ = image; native_app_window_->UpdateWindowIcon(); - AppWindowRegistry::Get(browser_context_)->AppWindowIconChanged(this); } void AppWindow::SetFullscreen(FullscreenType type, bool enable) { @@ -812,10 +769,8 @@ const GURL& image_url, const std::vector<SkBitmap>& bitmaps, const std::vector<gfx::Size>& original_bitmap_sizes) { - if (((image_url != app_icon_url_) && (image_url != window_icon_url_)) || - bitmaps.empty()) { + if (image_url != app_icon_url_ || bitmaps.empty()) return; - } // Bitmaps are ordered largest to smallest. Choose the smallest bitmap // whose height >= the preferred size. @@ -829,38 +784,6 @@ UpdateAppIcon(gfx::Image::CreateFrom1xBitmap(largest)); } -void AppWindow::OnExtensionIconImageChanged(IconImage* image) { - DCHECK_EQ(app_icon_image_.get(), image); - - // Update app_icon if no valid window icon url is set. - if (!window_icon_url_.is_valid()) - UpdateAppIcon(gfx::Image(app_icon_image_->image_skia())); -} - -void AppWindow::UpdateExtensionAppIcon() { - // Avoid using any previous app icons were being downloaded. - image_loader_ptr_factory_.InvalidateWeakPtrs(); - - const Extension* extension = GetExtension(); - if (!extension) - return; - - gfx::ImageSkia app_default_icon = - *ResourceBundle::GetSharedInstance().GetImageSkiaNamed( - IDR_APP_DEFAULT_ICON); - - app_icon_image_.reset(new IconImage(browser_context(), - extension, - IconsInfo::GetIcons(extension), - app_delegate_->PreferredIconSize(), - app_default_icon, - this)); - - // Triggers actual image loading with 1x resources. The 2x resource will - // be handled by IconImage class when requested. - app_icon_image_->image_skia().GetRepresentation(1.0f); -} - void AppWindow::SetNativeWindowFullscreen() { native_app_window_->SetFullscreen(fullscreen_types_);
diff --git a/extensions/browser/app_window/app_window.h b/extensions/browser/app_window/app_window.h index a850d713..ab812c2 100644 --- a/extensions/browser/app_window/app_window.h +++ b/extensions/browser/app_window/app_window.h
@@ -19,7 +19,6 @@ #include "content/public/browser/web_contents_delegate.h" #include "content/public/browser/web_contents_observer.h" #include "extensions/browser/extension_function_dispatcher.h" -#include "extensions/browser/extension_icon_image.h" #include "extensions/browser/extension_registry_observer.h" #include "ui/base/ui_base_types.h" // WindowShowState #include "ui/gfx/geometry/rect.h" @@ -87,7 +86,6 @@ class AppWindow : public content::WebContentsDelegate, public content::WebContentsObserver, public web_modal::WebContentsModalDialogManagerDelegate, - public IconImage::Observer, public ExtensionFunctionDispatcher::Delegate, public ExtensionRegistryObserver { public: @@ -236,7 +234,7 @@ return window_type_ == WINDOW_TYPE_PANEL; } content::BrowserContext* browser_context() const { return browser_context_; } - const gfx::Image& app_icon() const { return app_icon_; } + const gfx::Image& custom_app_icon() const { return custom_app_icon_; } const GURL& app_icon_url() const { return app_icon_url_; } const GURL& initial_url() const { return initial_url_; } bool is_hidden() const { return is_hidden_; } @@ -357,10 +355,6 @@ // unblock resource requests. void NotifyRenderViewReady(); - // Returns true if window has custom icon in case either |window_icon_url_| or - // |app_icon_url_| is set. Custom icon may be not loaded yet. - bool HasCustomIcon() const; - // Whether the app window wants to be alpha enabled. bool requested_alpha_enabled() const { return requested_alpha_enabled_; } @@ -372,7 +366,7 @@ bool show_in_shelf() const { return show_in_shelf_; } - const GURL& window_icon_url() const { return window_icon_url_; } + AppDelegate* app_delegate() { return app_delegate_.get(); } void SetAppWindowContentsForTesting( std::unique_ptr<AppWindowContents> contents) { @@ -473,9 +467,6 @@ // CreateParams that should be used to create the window. CreateParams LoadDefaults(CreateParams params) const; - // Load the app's image, firing a load state change when loaded. - void UpdateExtensionAppIcon(); - // Set the fullscreen state in the native app window. void SetNativeWindowFullscreen(); @@ -501,9 +492,6 @@ const std::vector<SkBitmap>& bitmaps, const std::vector<gfx::Size>& original_bitmap_sizes); - // IconImage::Observer implementation. - void OnExtensionIconImageChanged(IconImage* image) override; - // The browser context with which this window is associated. AppWindow does // not own this object. content::BrowserContext* browser_context_; @@ -517,16 +505,13 @@ const SessionID session_id_; WindowType window_type_; - // Icon shown in the task bar. - gfx::Image app_icon_; + // Custom icon shown in the task bar or in Chrome OS shelf. + gfx::Image custom_app_icon_; // Icon URL to be used for setting the app icon. If not empty, app_icon_ will // be fetched and set using this URL. GURL app_icon_url_; - // An object to load the app's icon as an extension resource. - std::unique_ptr<IconImage> app_icon_image_; - std::unique_ptr<NativeAppWindow> native_app_window_; std::unique_ptr<AppWindowContents> app_window_contents_; std::unique_ptr<AppDelegate> app_delegate_; @@ -565,11 +550,6 @@ // Whether |show_in_shelf| was set in the CreateParams. bool show_in_shelf_; - // Icon URL to be used for setting the window icon. If not empty, - // app_icon_ will be fetched and set using this URL and will have - // app_icon_image_ as a badge. - GURL window_icon_url_; - // PlzNavigate: this is called when the first navigation is ready to commit. base::Closure on_first_commit_callback_;
diff --git a/extensions/browser/app_window/app_window_registry.cc b/extensions/browser/app_window/app_window_registry.cc index 3eb52ca..bd259b0b 100644 --- a/extensions/browser/app_window/app_window_registry.cc +++ b/extensions/browser/app_window/app_window_registry.cc
@@ -24,10 +24,6 @@ void AppWindowRegistry::Observer::OnAppWindowAdded(AppWindow* app_window) { } -void AppWindowRegistry::Observer::OnAppWindowIconChanged( - AppWindow* app_window) { -} - void AppWindowRegistry::Observer::OnAppWindowRemoved(AppWindow* app_window) { } @@ -64,12 +60,6 @@ observer.OnAppWindowAdded(app_window); } -void AppWindowRegistry::AppWindowIconChanged(AppWindow* app_window) { - AddAppWindowToList(app_window); - for (auto& observer : observers_) - observer.OnAppWindowIconChanged(app_window); -} - void AppWindowRegistry::AppWindowActivated(AppWindow* app_window) { BringToFront(app_window); for (auto& observer : observers_)
diff --git a/extensions/browser/app_window/app_window_registry.h b/extensions/browser/app_window/app_window_registry.h index 799c4f6..e63b48b 100644 --- a/extensions/browser/app_window/app_window_registry.h +++ b/extensions/browser/app_window/app_window_registry.h
@@ -37,8 +37,6 @@ public: // Called just after a app window was added. virtual void OnAppWindowAdded(AppWindow* app_window); - // Called when the window icon changes. - virtual void OnAppWindowIconChanged(AppWindow* app_window); // Called just after a app window was removed. virtual void OnAppWindowRemoved(AppWindow* app_window); // Called just after a app window was hidden. This is different from @@ -67,7 +65,6 @@ static AppWindowRegistry* Get(content::BrowserContext* context); void AddAppWindow(AppWindow* app_window); - void AppWindowIconChanged(AppWindow* app_window); // Called by |app_window| when it is activated. void AppWindowActivated(AppWindow* app_window); void AppWindowHidden(AppWindow* app_window);
diff --git a/extensions/browser/extension_function_histogram_value.h b/extensions/browser/extension_function_histogram_value.h index 287f3ac..9eb80d4 100644 --- a/extensions/browser/extension_function_histogram_value.h +++ b/extensions/browser/extension_function_histogram_value.h
@@ -1238,6 +1238,7 @@ MEDIAPERCEPTIONPRIVATE_SETSTATE, MEDIAPERCEPTIONPRIVATE_GETDIAGNOSTICS, NETWORKINGPRIVATE_GETCERTIFICATELISTS, + ACCESSIBILITY_PRIVATE_SETSWITCHACCESSKEYS, // Last entry: Add new entries above, then run: // python tools/metrics/histograms/update_extension_histograms.py ENUM_BOUNDARY
diff --git a/extensions/common/manifest_handlers/icons_handler.cc b/extensions/common/manifest_handlers/icons_handler.cc index 2825ae9..6fb5ce5 100644 --- a/extensions/common/manifest_handlers/icons_handler.cc +++ b/extensions/common/manifest_handlers/icons_handler.cc
@@ -28,6 +28,7 @@ // static const ExtensionIconSet& IconsInfo::GetIcons(const Extension* extension) { + DCHECK(extension); IconsInfo* info = static_cast<IconsInfo*>( extension->GetManifestData(keys::kIcons)); return info ? info->icons : g_empty_icon_set.Get();
diff --git a/extensions/renderer/api/display_source/wifi_display/wifi_display_transport_stream_packetizer.cc b/extensions/renderer/api/display_source/wifi_display/wifi_display_transport_stream_packetizer.cc index 22e1bcf..824719f 100644 --- a/extensions/renderer/api/display_source/wifi_display/wifi_display_transport_stream_packetizer.cc +++ b/extensions/renderer/api/display_source/wifi_display/wifi_display_transport_stream_packetizer.cc
@@ -434,7 +434,9 @@ CHECK(SetElementaryStreams(stream_infos)); } -WiFiDisplayTransportStreamPacketizer::~WiFiDisplayTransportStreamPacketizer() {} +WiFiDisplayTransportStreamPacketizer::~WiFiDisplayTransportStreamPacketizer() { + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); +} bool WiFiDisplayTransportStreamPacketizer::EncodeElementaryStreamUnit( unsigned stream_index, @@ -444,7 +446,7 @@ base::TimeTicks pts, base::TimeTicks dts, bool flush) { - DCHECK(CalledOnValidThread()); + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); DCHECK_LT(stream_index, stream_states_.size()); ElementaryStreamState& stream_state = stream_states_[stream_index]; @@ -549,7 +551,7 @@ } bool WiFiDisplayTransportStreamPacketizer::EncodeMetaInformation(bool flush) { - DCHECK(CalledOnValidThread()); + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); return (EncodeProgramAssociationTable(false) && EncodeProgramMapTables(false) && EncodeProgramClockReference(flush)); @@ -557,7 +559,7 @@ bool WiFiDisplayTransportStreamPacketizer::EncodeProgramAssociationTable( bool flush) { - DCHECK(CalledOnValidThread()); + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); // Fill in a packet header. uint8_t header_data[ts::kPacketHeaderSize]; @@ -576,7 +578,7 @@ bool WiFiDisplayTransportStreamPacketizer::EncodeProgramClockReference( bool flush) { - DCHECK(CalledOnValidThread()); + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); program_clock_reference_ = base::TimeTicks::Now(); @@ -607,7 +609,7 @@ } bool WiFiDisplayTransportStreamPacketizer::EncodeProgramMapTables(bool flush) { - DCHECK(CalledOnValidThread()); + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); DCHECK(!program_map_table_.empty()); // Fill in a packet header. @@ -633,7 +635,7 @@ void WiFiDisplayTransportStreamPacketizer::NormalizeUnitTimeStamps( base::TimeTicks* pts, base::TimeTicks* dts) const { - DCHECK(CalledOnValidThread()); + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); // Normalize a presentation time stamp. if (!pts || pts->is_null()) @@ -651,7 +653,7 @@ bool WiFiDisplayTransportStreamPacketizer::SetElementaryStreams( const std::vector<WiFiDisplayElementaryStreamInfo>& stream_infos) { - DCHECK(CalledOnValidThread()); + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); std::vector<ElementaryStreamState> new_stream_states; new_stream_states.reserve(stream_infos.size()); @@ -717,7 +719,7 @@ void WiFiDisplayTransportStreamPacketizer::UpdateDelayForUnitTimeStamps( const base::TimeTicks& pts, const base::TimeTicks& dts) { - DCHECK(CalledOnValidThread()); + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); if (pts.is_null()) return;
diff --git a/extensions/renderer/api/display_source/wifi_display/wifi_display_transport_stream_packetizer.h b/extensions/renderer/api/display_source/wifi_display/wifi_display_transport_stream_packetizer.h index c7a883c..797785b 100644 --- a/extensions/renderer/api/display_source/wifi_display/wifi_display_transport_stream_packetizer.h +++ b/extensions/renderer/api/display_source/wifi_display/wifi_display_transport_stream_packetizer.h
@@ -7,7 +7,7 @@ #include <vector> -#include "base/threading/non_thread_safe.h" +#include "base/threading/thread_checker.h" #include "base/time/time.h" #include "extensions/renderer/api/display_source/wifi_display/wifi_display_stream_packet_part.h" @@ -63,7 +63,7 @@ // Whenever a Transport Stream (TS) packet is fully created and thus ready for // further processing, a pure virtual member function // |OnPacketizedTransportStreamPacket| is called. -class WiFiDisplayTransportStreamPacketizer : public base::NonThreadSafe { +class WiFiDisplayTransportStreamPacketizer { public: struct ElementaryStreamState; @@ -134,7 +134,7 @@ bool SetElementaryStreams( const std::vector<WiFiDisplayElementaryStreamInfo>& stream_infos); - void DetachFromThread() { base::NonThreadSafe::DetachFromThread(); } + void DetachFromThread() { DETACH_FROM_THREAD(thread_checker_); } protected: bool EncodeProgramAssociationTable(bool flush); @@ -170,6 +170,8 @@ std::vector<ElementaryStreamState> stream_states_; std::vector<uint8_t> program_association_table_; std::vector<uint8_t> program_map_table_; + + THREAD_CHECKER(thread_checker_); }; } // namespace extensions
diff --git a/extensions/shell/browser/shell_app_delegate.cc b/extensions/shell/browser/shell_app_delegate.cc index 5e5669d..245cc2f 100644 --- a/extensions/shell/browser/shell_app_delegate.cc +++ b/extensions/shell/browser/shell_app_delegate.cc
@@ -81,7 +81,7 @@ return true; } -int ShellAppDelegate::PreferredIconSize() { +int ShellAppDelegate::PreferredIconSize() const { return extension_misc::EXTENSION_ICON_SMALL; }
diff --git a/extensions/shell/browser/shell_app_delegate.h b/extensions/shell/browser/shell_app_delegate.h index 599ebe93..ff124c1c 100644 --- a/extensions/shell/browser/shell_app_delegate.h +++ b/extensions/shell/browser/shell_app_delegate.h
@@ -46,7 +46,7 @@ const GURL& security_origin, content::MediaStreamType type, const Extension* extension) override; - int PreferredIconSize() override; + int PreferredIconSize() const override; void SetWebContentsBlocked(content::WebContents* web_contents, bool blocked) override; bool IsWebContentsVisible(content::WebContents* web_contents) override;
diff --git a/ios/chrome/browser/ui/settings/clear_browsing_data_collection_view_controller.h b/ios/chrome/browser/ui/settings/clear_browsing_data_collection_view_controller.h index 2d577fe..95216a1 100644 --- a/ios/chrome/browser/ui/settings/clear_browsing_data_collection_view_controller.h +++ b/ios/chrome/browser/ui/settings/clear_browsing_data_collection_view_controller.h
@@ -21,6 +21,8 @@ extern NSString* const kClearSavedPasswordsCellId; extern NSString* const kClearAutofillCellId; +// CollectionView for clearing browsing data (including history, +// cookies, caches, passwords, and autofill). @interface ClearBrowsingDataCollectionViewController : SettingsRootCollectionViewController
diff --git a/ios/chrome/browser/ui/webui/about_ui.h b/ios/chrome/browser/ui/webui/about_ui.h index 76b07d9..6a5495b 100644 --- a/ios/chrome/browser/ui/webui/about_ui.h +++ b/ios/chrome/browser/ui/webui/about_ui.h
@@ -14,6 +14,8 @@ class WebUIIOS; } +// The WebUI controller for chrome://chrome-urls, chrome://histograms, +// and chrome://credits. class AboutUI : public web::WebUIIOSController { public: explicit AboutUI(web::WebUIIOS* web_ui, const std::string& name);
diff --git a/ios/chrome/browser/voice/BUILD.gn b/ios/chrome/browser/voice/BUILD.gn index c2a0f1d..5d81ae3 100644 --- a/ios/chrome/browser/voice/BUILD.gn +++ b/ios/chrome/browser/voice/BUILD.gn
@@ -3,6 +3,7 @@ # found in the LICENSE file. source_set("voice") { + configs += [ "//build/config/compiler:enable_arc" ] sources = [ "speech_input_locale.h", "speech_input_locale_config.h",
diff --git a/ios/chrome/browser/voice/speech_input_locale_config.mm b/ios/chrome/browser/voice/speech_input_locale_config.mm index a4941b3..32c063a8 100644 --- a/ios/chrome/browser/voice/speech_input_locale_config.mm +++ b/ios/chrome/browser/voice/speech_input_locale_config.mm
@@ -6,6 +6,10 @@ #include "ios/chrome/browser/voice/speech_input_locale_config_impl.h" +#if !defined(__has_feature) || !__has_feature(objc_arc) +#error "This file requires ARC support." +#endif + namespace voice { // static
diff --git a/ios/chrome/browser/voice/speech_input_locale_config_impl.mm b/ios/chrome/browser/voice/speech_input_locale_config_impl.mm index 4cee9e5..6a83c23e 100644 --- a/ios/chrome/browser/voice/speech_input_locale_config_impl.mm +++ b/ios/chrome/browser/voice/speech_input_locale_config_impl.mm
@@ -16,6 +16,10 @@ #include "ios/public/provider/chrome/browser/voice/voice_search_language.h" #include "ios/public/provider/chrome/browser/voice/voice_search_provider.h" +#if !defined(__has_feature) || !__has_feature(objc_arc) +#error "This file requires ARC support." +#endif + namespace { // Returns the language portion of |locale_code|.
diff --git a/ios/chrome/browser/voice/speech_input_locale_match_config.mm b/ios/chrome/browser/voice/speech_input_locale_match_config.mm index e53a8a0..661bce5eb 100644 --- a/ios/chrome/browser/voice/speech_input_locale_match_config.mm +++ b/ios/chrome/browser/voice/speech_input_locale_match_config.mm
@@ -5,7 +5,10 @@ #import "ios/chrome/browser/voice/speech_input_locale_match_config.h" #import "base/mac/foundation_util.h" -#import "base/mac/scoped_nsobject.h" + +#if !defined(__has_feature) || !__has_feature(objc_arc) +#error "This file requires ARC support." +#endif namespace { @@ -18,10 +21,7 @@ #pragma mark - SpeechInputLocaleMatchConfig -@interface SpeechInputLocaleMatchConfig () { - // Backing object for the property of the same name. - base::scoped_nsobject<NSArray> _matches; -} +@interface SpeechInputLocaleMatchConfig () // Loads |_matches| from config file |plistFileName|. - (void)loadConfigFile:(NSString*)plistFileName; @@ -29,6 +29,7 @@ @end @implementation SpeechInputLocaleMatchConfig +@synthesize matches = _matches; + (instancetype)sharedInstance { static SpeechInputLocaleMatchConfig* matchConfig; @@ -47,11 +48,6 @@ return self; } -#pragma mark Accessors - -- (NSArray*)matches { - return _matches.get(); -} #pragma mark - Private @@ -63,49 +59,29 @@ NSMutableArray* matches = [NSMutableArray array]; for (id item in configData) { NSDictionary* matchDict = base::mac::ObjCCastStrict<NSDictionary>(item); - base::scoped_nsobject<SpeechInputLocaleMatch> match( - [[SpeechInputLocaleMatch alloc] initWithDictionary:matchDict]); + SpeechInputLocaleMatch* match = + [[SpeechInputLocaleMatch alloc] initWithDictionary:matchDict]; [matches addObject:match]; } - _matches.reset([matches copy]); + _matches = [matches copy]; } @end #pragma mark - SpeechInputLocaleMatch -@interface SpeechInputLocaleMatch () { - // Backing objects for properties of the same name. - base::scoped_nsobject<NSString> _matchedLocaleCode; - base::scoped_nsobject<NSArray> _matchingLocaleCodes; - base::scoped_nsobject<NSArray> _matchingLanguages; -} - -@end - @implementation SpeechInputLocaleMatch +@synthesize matchedLocaleCode = _matchedLocaleCode; +@synthesize matchingLocaleCodes = _matchingLocaleCodes; +@synthesize matchingLanguages = _matchingLanguages; - (instancetype)initWithDictionary:(NSDictionary*)matchDict { if ((self = [super init])) { - _matchedLocaleCode.reset([matchDict[kMatchedLocaleKey] copy]); - _matchingLocaleCodes.reset([matchDict[kMatchingLocalesKey] copy]); - _matchingLanguages.reset([matchDict[kMatchingLanguagesKey] copy]); + _matchedLocaleCode = [matchDict[kMatchedLocaleKey] copy]; + _matchingLocaleCodes = [matchDict[kMatchingLocalesKey] copy]; + _matchingLanguages = [matchDict[kMatchingLanguagesKey] copy]; } return self; } -#pragma mark Accessors - -- (NSString*)matchedLocaleCode { - return _matchedLocaleCode; -} - -- (NSArray*)matchingLocaleCodes { - return _matchingLocaleCodes; -} - -- (NSArray*)matchingLanguages { - return _matchingLanguages; -} - @end
diff --git a/ios/clean/chrome/browser/ui/context_menu/context_menu_view_controller.mm b/ios/clean/chrome/browser/ui/context_menu/context_menu_view_controller.mm index d1d120a..441ae48 100644 --- a/ios/clean/chrome/browser/ui/context_menu/context_menu_view_controller.mm +++ b/ios/clean/chrome/browser/ui/context_menu/context_menu_view_controller.mm
@@ -20,11 +20,16 @@ ContextMenuContext* context) { DCHECK(dispatcher); DCHECK(context); +// |-performSelector:withObject:| throws a warning in ARC because the compiler +// doesn't know how to handle the memory management of the returned values. +// Since all ContextMenuCommands return void, these warning can be ignored +// here. +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Warc-performSelector-leaks" for (SEL command : commands) { - IMP command_imp = [dispatcher methodForSelector:command]; - DCHECK(command_imp); - command_imp(dispatcher, command, context); + [dispatcher performSelector:command withObject:context]; } +#pragma clang diagnostic pop } }
diff --git a/ios/clean/chrome/browser/ui/find_in_page/find_in_page_mediator.mm b/ios/clean/chrome/browser/ui/find_in_page/find_in_page_mediator.mm index 4f1be95..2bc00224 100644 --- a/ios/clean/chrome/browser/ui/find_in_page/find_in_page_mediator.mm +++ b/ios/clean/chrome/browser/ui/find_in_page/find_in_page_mediator.mm
@@ -72,9 +72,11 @@ - (void)stopFinding { web::WebState* webState = self.webStateList->GetActiveWebState(); - FindTabHelper* helper = FindTabHelper::FromWebState(webState); - DCHECK(helper); - helper->StopFinding(nil); + if (webState) { + FindTabHelper* helper = FindTabHelper::FromWebState(webState); + DCHECK(helper); + helper->StopFinding(nil); + } } - (void)findResultsAvailable:(FindInPageModel*)model {
diff --git a/ios/clean/chrome/browser/ui/tab_collection/tab_collection_consumer.h b/ios/clean/chrome/browser/ui/tab_collection/tab_collection_consumer.h index 1ca74ee..c771697 100644 --- a/ios/clean/chrome/browser/ui/tab_collection/tab_collection_consumer.h +++ b/ios/clean/chrome/browser/ui/tab_collection/tab_collection_consumer.h
@@ -10,23 +10,32 @@ // Interface to support insert/delete/updates to a tab collection. @protocol TabCollectionConsumer -// Inserts |item| into tab collection at |index|. -- (void)insertItem:(TabCollectionItem*)item atIndex:(int)index; +// Inserts |item| into tab collection at |index|. |SelectedIndex| is the index +// of the selected item in the tab collection. +- (void)insertItem:(TabCollectionItem*)item + atIndex:(int)index + selectedIndex:(int)selectedIndex; -// Deletes |index| from tab collection. -- (void)deleteItemAtIndex:(int)index; +// Deletes |index| from tab collection. |SelectedIndex| is the index +// of the selected tab in the tab collection. +- (void)deleteItemAtIndex:(int)index selectedIndex:(int)selectedIndex; -// Moves item from |fromIndex| to |toIndex|. -- (void)moveItemFromIndex:(int)fromIndex toIndex:(int)toIndex; +// Moves item from |fromIndex| to |toIndex|. |SelectedIndex| is the index +// of the selected tab in the tab collection. +- (void)moveItemFromIndex:(int)fromIndex + toIndex:(int)toIndex + selectedIndex:(int)selectedIndex; // Replaces item at |index| with |item|. - (void)replaceItemAtIndex:(int)index withItem:(TabCollectionItem*)item; -// Selects the item at |index|. -- (void)selectItemAtIndex:(int)index; +// Selects the item at |selectedIndex|. +- (void)setSelectedIndex:(int)selectedIndex; -// Populates tab collection with |items|. -- (void)populateItems:(NSArray<TabCollectionItem*>*)items; +// Populates tab collection with |items|. |SelectedIndex| is the index +// of the selected item in the tab collection. +- (void)populateItems:(NSArray<TabCollectionItem*>*)items + selectedIndex:(int)selectedIndex; @end #endif // IOS_CLEAN_CHROME_BROWSER_UI_TAB_COLLECTION_TAB_COLLECTION_CONSUMER_H_
diff --git a/ios/clean/chrome/browser/ui/tab_collection/tab_collection_mediator.mm b/ios/clean/chrome/browser/ui/tab_collection/tab_collection_mediator.mm index 41ac68e..e6a8eebc 100644 --- a/ios/clean/chrome/browser/ui/tab_collection/tab_collection_mediator.mm +++ b/ios/clean/chrome/browser/ui/tab_collection/tab_collection_mediator.mm
@@ -11,15 +11,20 @@ #import "ios/clean/chrome/browser/ui/tab_collection/tab_collection_consumer.h" #import "ios/clean/chrome/browser/ui/tab_collection/tab_collection_item.h" #include "ios/web/public/web_state/web_state.h" +#import "ios/web/public/web_state/web_state_observer_bridge.h" #if !defined(__has_feature) || !__has_feature(objc_arc) #error "This file requires ARC support." #endif +@interface TabCollectionMediator ()<CRWWebStateObserver> +@end + @implementation TabCollectionMediator { std::unique_ptr<WebStateListObserverBridge> _webStateListObserver; std::unique_ptr<ScopedObserver<WebStateList, WebStateListObserverBridge>> _scopedWebStateListObserver; + std::unique_ptr<web::WebStateObserverBridge> _webStateObserver; } @synthesize webStateList = _webStateList; @@ -43,22 +48,24 @@ #pragma mark - Public - (void)disconnect { - self.webStateList = nullptr; + _webStateList = nullptr; + _webStateObserver.reset(); } #pragma mark - Properties - (void)setWebStateList:(WebStateList*)webStateList { - // TODO(crbug.com/727427):Add support for DCHECK(webStateList). + DCHECK(webStateList); _scopedWebStateListObserver->RemoveAll(); _webStateList = webStateList; + _scopedWebStateListObserver->Add(_webStateList); + _webStateObserver = base::MakeUnique<web::WebStateObserverBridge>( + self.webStateList->GetActiveWebState(), self); [self populateConsumerItems]; - if (_webStateList) { - _scopedWebStateListObserver->Add(_webStateList); - } } - (void)setConsumer:(id<TabCollectionConsumer>)consumer { + DCHECK(consumer); _consumer = consumer; [self populateConsumerItems]; } @@ -70,7 +77,8 @@ atIndex:(int)index { DCHECK(self.consumer); [self.consumer insertItem:[self tabCollectionItemFromWebState:webState] - atIndex:index]; + atIndex:index + selectedIndex:webStateList->active_index()]; } - (void)webStateList:(WebStateList*)webStateList @@ -78,7 +86,9 @@ fromIndex:(int)fromIndex toIndex:(int)toIndex { DCHECK(self.consumer); - [self.consumer moveItemFromIndex:fromIndex toIndex:toIndex]; + [self.consumer moveItemFromIndex:fromIndex + toIndex:toIndex + selectedIndex:webStateList->active_index()]; } - (void)webStateList:(WebStateList*)webStateList @@ -95,7 +105,8 @@ didDetachWebState:(web::WebState*)webState atIndex:(int)index { DCHECK(self.consumer); - [self.consumer deleteItemAtIndex:index]; + [self.consumer deleteItemAtIndex:index + selectedIndex:webStateList->active_index()]; } - (void)webStateList:(WebStateList*)webStateList @@ -104,11 +115,27 @@ atIndex:(int)atIndex userAction:(BOOL)userAction { DCHECK(self.consumer); - [self.consumer selectItemAtIndex:atIndex]; + [self.consumer setSelectedIndex:atIndex]; + _webStateObserver = + base::MakeUnique<web::WebStateObserverBridge>(newWebState, self); +} + +#pragma mark - CRWWebStateObserver + +// Navigational changes to the web state update the tab collection, such as +// the title and snapshot. +- (void)webState:(web::WebState*)webState didLoadPageWithSuccess:(BOOL)success { + DCHECK(self.webStateList); + DCHECK(self.consumer); + int index = self.webStateList->GetIndexOfWebState(webState); + [self.consumer + replaceItemAtIndex:index + withItem:[self tabCollectionItemFromWebState:webState]]; } #pragma mark - Private +// Constructs a TabCollectionItem from a |webState|. - (TabCollectionItem*)tabCollectionItemFromWebState: (const web::WebState*)webState { // PLACEHOLDER: Use real webstate title in the future. @@ -123,24 +150,26 @@ return item; } +// Constructs an array of TabCollectionItems from a |webStateList|. - (NSArray<TabCollectionItem*>*)tabCollectionItemsFromWebStateList: (const WebStateList*)webStateList { DCHECK(webStateList); NSMutableArray<TabCollectionItem*>* items = [[NSMutableArray alloc] init]; for (int i = 0; i < webStateList->count(); i++) { - [items - addObject:[self - tabCollectionItemFromWebState:webStateList->GetWebStateAt( - i)]]; + web::WebState* webState = webStateList->GetWebStateAt(i); + [items addObject:[self tabCollectionItemFromWebState:webState]]; } return [items copy]; } +// Constructs an array of TabCollectionItems from the current webStateList +// and pushes them to the consumer. - (void)populateConsumerItems { if (self.consumer && self.webStateList) { - [self.consumer populateItems:[self tabCollectionItemsFromWebStateList: - self.webStateList]]; - [self.consumer selectItemAtIndex:self.webStateList->active_index()]; + [self.consumer + populateItems:[self + tabCollectionItemsFromWebStateList:self.webStateList] + selectedIndex:self.webStateList->active_index()]; } }
diff --git a/ios/clean/chrome/browser/ui/tab_collection/tab_collection_mediator_unittest.mm b/ios/clean/chrome/browser/ui/tab_collection/tab_collection_mediator_unittest.mm index 7b266361..827a315 100644 --- a/ios/clean/chrome/browser/ui/tab_collection/tab_collection_mediator_unittest.mm +++ b/ios/clean/chrome/browser/ui/tab_collection/tab_collection_mediator_unittest.mm
@@ -63,14 +63,14 @@ // Tests that the consumer is notified of an insert into webStateList. TEST_F(TabCollectionMediatorTest, TestInsertWebState) { InsertWebState(2); - [[consumer_ verify] insertItem:[OCMArg any] atIndex:2]; + [[consumer_ verify] insertItem:[OCMArg any] atIndex:2 selectedIndex:0]; } // Tests that the consumer is notified that a web state has been moved in // webStateList. TEST_F(TabCollectionMediatorTest, TestMoveWebState) { web_state_list_->MoveWebStateAt(0, 2); - [[consumer_ verify] moveItemFromIndex:0 toIndex:2]; + [[consumer_ verify] moveItemFromIndex:0 toIndex:2 selectedIndex:2]; } // Tests that the consumer is notified that a web state has been replaced in @@ -85,12 +85,12 @@ // webStateList. TEST_F(TabCollectionMediatorTest, TestDetachWebState) { web_state_list_->CloseWebStateAt(1); - [[consumer_ verify] deleteItemAtIndex:1]; + [[consumer_ verify] deleteItemAtIndex:1 selectedIndex:0]; } // Tests that the consumer is notified that the active web state has changed in // webStateList. TEST_F(TabCollectionMediatorTest, TestChangeActiveWebState) { web_state_list_->ActivateWebStateAt(2); - [[consumer_ verify] selectItemAtIndex:2]; + [[consumer_ verify] setSelectedIndex:2]; }
diff --git a/ios/clean/chrome/browser/ui/tab_collection/tab_collection_tab_cell.mm b/ios/clean/chrome/browser/ui/tab_collection/tab_collection_tab_cell.mm index f904ac5..ff06540a 100644 --- a/ios/clean/chrome/browser/ui/tab_collection/tab_collection_tab_cell.mm +++ b/ios/clean/chrome/browser/ui/tab_collection/tab_collection_tab_cell.mm
@@ -9,6 +9,7 @@ #endif namespace { +const CGFloat kBorderMargin = 6.0f; const CGFloat kSelectedBorderCornerRadius = 8.0f; const CGFloat kSelectedBorderWidth = 4.0f; } @@ -17,16 +18,36 @@ - (instancetype)initWithFrame:(CGRect)frame { if ((self = [super initWithFrame:frame])) { - self.selectedBackgroundView = [[UIView alloc] init]; - self.selectedBackgroundView.backgroundColor = [UIColor blackColor]; - self.selectedBackgroundView.layer.cornerRadius = - kSelectedBorderCornerRadius; - self.selectedBackgroundView.layer.borderWidth = kSelectedBorderWidth; - self.selectedBackgroundView.layer.borderColor = self.tintColor.CGColor; - self.selectedBackgroundView.transform = CGAffineTransformScale( - self.selectedBackgroundView.transform, 1.08, 1.08); + [self setupSelectedBackgroundView]; } return self; } +- (void)setupSelectedBackgroundView { + self.selectedBackgroundView = [[UIView alloc] init]; + self.selectedBackgroundView.backgroundColor = [UIColor blackColor]; + + UIView* border = [[UIView alloc] init]; + border.translatesAutoresizingMaskIntoConstraints = NO; + border.backgroundColor = [UIColor blackColor]; + border.layer.cornerRadius = kSelectedBorderCornerRadius; + border.layer.borderWidth = kSelectedBorderWidth; + border.layer.borderColor = self.tintColor.CGColor; + [self.selectedBackgroundView addSubview:border]; + [NSLayoutConstraint activateConstraints:@[ + [border.topAnchor + constraintEqualToAnchor:self.selectedBackgroundView.topAnchor + constant:-kBorderMargin], + [border.leadingAnchor + constraintEqualToAnchor:self.selectedBackgroundView.leadingAnchor + constant:-kBorderMargin], + [border.trailingAnchor + constraintEqualToAnchor:self.selectedBackgroundView.trailingAnchor + constant:kBorderMargin], + [border.bottomAnchor + constraintEqualToAnchor:self.selectedBackgroundView.bottomAnchor + constant:kBorderMargin] + ]]; +} + @end
diff --git a/ios/clean/chrome/browser/ui/tab_collection/tab_collection_view_controller.h b/ios/clean/chrome/browser/ui/tab_collection/tab_collection_view_controller.h index d7dada96..907f4b99 100644 --- a/ios/clean/chrome/browser/ui/tab_collection/tab_collection_view_controller.h +++ b/ios/clean/chrome/browser/ui/tab_collection/tab_collection_view_controller.h
@@ -9,8 +9,6 @@ #import "ios/clean/chrome/browser/ui/tab_collection/tab_collection_consumer.h" -@protocol TabCollectionDataSource; - // Controller for a scrolling view displaying square cells that represent // the user's open tabs. @interface TabCollectionViewController
diff --git a/ios/clean/chrome/browser/ui/tab_collection/tab_collection_view_controller.mm b/ios/clean/chrome/browser/ui/tab_collection/tab_collection_view_controller.mm index 5f64f9d..4fa101e 100644 --- a/ios/clean/chrome/browser/ui/tab_collection/tab_collection_view_controller.mm +++ b/ios/clean/chrome/browser/ui/tab_collection/tab_collection_view_controller.mm
@@ -16,8 +16,11 @@ @interface TabCollectionViewController ()<UICollectionViewDelegate, SessionCellDelegate> +// Collection view of tabs. @property(nonatomic, readwrite) UICollectionView* tabs; +// The model backing the collection view. @property(nonatomic, readwrite) NSMutableArray<TabCollectionItem*>* items; +// Selected index of tab collection. @property(nonatomic, assign) int selectedIndex; @end @@ -50,13 +53,27 @@ [self.tabs.trailingAnchor constraintEqualToAnchor:self.view.trailingAnchor], ]]; - [self selectItemAtIndex:self.selectedIndex]; + [self.tabs + selectItemAtIndexPath:[NSIndexPath indexPathForItem:self.selectedIndex + inSection:0] + animated:NO + scrollPosition:UICollectionViewScrollPositionNone]; } - (UIStatusBarStyle)preferredStatusBarStyle { return UIStatusBarStyleLightContent; } +#pragma mark - Setters + +- (void)setSelectedIndex:(int)selectedIndex { + [self.tabs selectItemAtIndexPath:[NSIndexPath indexPathForItem:selectedIndex + inSection:0] + animated:YES + scrollPosition:UICollectionViewScrollPositionNone]; + _selectedIndex = selectedIndex; +} + #pragma mark - Required subclass override - (UICollectionViewLayout*)collectionViewLayout { @@ -138,47 +155,55 @@ #pragma mark - TabCollectionConsumer methods -- (void)insertItem:(TabCollectionItem*)item atIndex:(int)index { +- (void)insertItem:(TabCollectionItem*)item + atIndex:(int)index + selectedIndex:(int)selectedIndex { + DCHECK_GE(index, 0); DCHECK_LE(static_cast<NSUInteger>(index), self.items.count); [self.items insertObject:item atIndex:index]; - [self.tabs insertItemsAtIndexPaths:@[ [self indexPathForIndex:index] ]]; + [self.tabs insertItemsAtIndexPaths:@[ [NSIndexPath indexPathForItem:index + inSection:0] ]]; + self.selectedIndex = selectedIndex; } -- (void)deleteItemAtIndex:(int)index { +- (void)deleteItemAtIndex:(int)index selectedIndex:(int)selectedIndex { + DCHECK_GE(index, 0); DCHECK_LT(static_cast<NSUInteger>(index), self.items.count); [self.items removeObjectAtIndex:index]; - [self.tabs deleteItemsAtIndexPaths:@[ [self indexPathForIndex:index] ]]; + [self.tabs deleteItemsAtIndexPaths:@[ [NSIndexPath indexPathForItem:index + inSection:0] ]]; + self.selectedIndex = selectedIndex; } -- (void)moveItemFromIndex:(int)fromIndex toIndex:(int)toIndex { +- (void)moveItemFromIndex:(int)fromIndex + toIndex:(int)toIndex + selectedIndex:(int)selectedIndex { TabCollectionItem* item = self.items[fromIndex]; [self.items removeObjectAtIndex:fromIndex]; [self.items insertObject:item atIndex:toIndex]; - [self.tabs moveItemAtIndexPath:[self indexPathForIndex:fromIndex] - toIndexPath:[self indexPathForIndex:toIndex]]; + [self.tabs + moveItemAtIndexPath:[NSIndexPath indexPathForItem:fromIndex inSection:0] + toIndexPath:[NSIndexPath indexPathForItem:toIndex inSection:0]]; + self.selectedIndex = selectedIndex; } - (void)replaceItemAtIndex:(int)index withItem:(TabCollectionItem*)item { - [self.items removeObjectAtIndex:index]; - [self.items insertObject:item atIndex:index]; + DCHECK_GE(index, 0); + DCHECK_LT(static_cast<NSUInteger>(index), self.items.count); + self.items[index] = item; + TabCollectionTabCell* cell = base::mac::ObjCCastStrict<TabCollectionTabCell>( + [self.tabs cellForItemAtIndexPath:[NSIndexPath indexPathForItem:index + inSection:0]]); + [cell setAppearanceForTabTitle:self.items[index].title + favicon:nil + cellSize:CGSizeZero]; } -- (void)selectItemAtIndex:(int)index { - self.selectedIndex = index; - [self.tabs selectItemAtIndexPath:[self indexPathForIndex:index] - animated:YES - scrollPosition:UITableViewScrollPositionNone]; -} - -- (void)populateItems:(NSArray<TabCollectionItem*>*)items { +- (void)populateItems:(NSArray<TabCollectionItem*>*)items + selectedIndex:(int)selectedIndex { self.items = [items mutableCopy]; - [self.tabs reloadData]; -} - -#pragma mark - Private - -- (NSIndexPath*)indexPathForIndex:(int)index { - return [NSIndexPath indexPathForItem:index inSection:0]; + [self.tabs reloadItemsAtIndexPaths:[self.tabs indexPathsForVisibleItems]]; + self.selectedIndex = selectedIndex; } @end
diff --git a/ios/clean/chrome/browser/ui/tab_collection/tab_collection_view_controller_unittest.mm b/ios/clean/chrome/browser/ui/tab_collection/tab_collection_view_controller_unittest.mm index 7d61f0a..f6b5cf8 100644 --- a/ios/clean/chrome/browser/ui/tab_collection/tab_collection_view_controller_unittest.mm +++ b/ios/clean/chrome/browser/ui/tab_collection/tab_collection_view_controller_unittest.mm
@@ -40,19 +40,21 @@ // Tests that an item is inserted. TEST_F(TabCollectionViewControllerTest, TestInsertItem) { - [view_controller_ insertItem:[[TabCollectionItem alloc] init] atIndex:0]; + [view_controller_ insertItem:[[TabCollectionItem alloc] init] + atIndex:0 + selectedIndex:0]; EXPECT_EQ(3, static_cast<int>(view_controller_.items.count)); } // Tests that an item is deleted. TEST_F(TabCollectionViewControllerTest, TestDeleteItem) { - [view_controller_ deleteItemAtIndex:0]; + [view_controller_ deleteItemAtIndex:0 selectedIndex:0]; EXPECT_EQ(1, static_cast<int>(view_controller_.items.count)); } // Tests that an item is moved. TEST_F(TabCollectionViewControllerTest, TestMoveItem) { - [view_controller_ moveItemFromIndex:0 toIndex:1]; + [view_controller_ moveItemFromIndex:0 toIndex:1 selectedIndex:0]; EXPECT_NSEQ(@"Item1", view_controller_.items[0].title); } @@ -68,6 +70,6 @@ TEST_F(TabCollectionViewControllerTest, TestInitializeItems) { TabCollectionItem* item = [[TabCollectionItem alloc] init]; item.title = @"NewItem"; - [view_controller_ populateItems:@[ item ]]; + [view_controller_ populateItems:@[ item ] selectedIndex:0]; EXPECT_NSEQ(@"NewItem", view_controller_.items[0].title); }
diff --git a/ios/clean/chrome/browser/ui/tab_strip/tab_strip_coordinator.mm b/ios/clean/chrome/browser/ui/tab_strip/tab_strip_coordinator.mm index 1688f3e2..8478ce5 100644 --- a/ios/clean/chrome/browser/ui/tab_strip/tab_strip_coordinator.mm +++ b/ios/clean/chrome/browser/ui/tab_strip/tab_strip_coordinator.mm
@@ -5,6 +5,7 @@ #import "ios/clean/chrome/browser/ui/tab_strip/tab_strip_coordinator.h" #import "ios/chrome/browser/web_state_list/web_state_list.h" +#import "ios/clean/chrome/browser/ui/commands/tab_grid_commands.h" #import "ios/clean/chrome/browser/ui/commands/tab_strip_commands.h" #import "ios/clean/chrome/browser/ui/tab_collection/tab_collection_mediator.h" #import "ios/clean/chrome/browser/ui/tab_strip/tab_strip_view_controller.h" @@ -64,6 +65,9 @@ - (void)closeTabStripTabAtIndex:(int)index { self.webStateList.CloseWebStateAt(index); + if (self.webStateList.empty()) { + [static_cast<id<TabGridCommands>>(self.browser->dispatcher()) showTabGrid]; + } } @end
diff --git a/ios/showcase/tab_grid/sc_tab_grid_coordinator.mm b/ios/showcase/tab_grid/sc_tab_grid_coordinator.mm index 846f101c..830c61e 100644 --- a/ios/showcase/tab_grid/sc_tab_grid_coordinator.mm +++ b/ios/showcase/tab_grid/sc_tab_grid_coordinator.mm
@@ -42,7 +42,7 @@ TabCollectionItem* item0 = [[TabCollectionItem alloc] init]; item0.title = @"Tab 0"; - [self.viewController populateItems:@[ item0 ]]; + [self.viewController populateItems:@[ item0 ] selectedIndex:0]; [self.baseViewController setHidesBarsOnSwipe:YES]; [self.baseViewController pushViewController:self.viewController animated:YES];
diff --git a/media/audio/audio_output_proxy.cc b/media/audio/audio_output_proxy.cc index b215b47d..c3551b1 100644 --- a/media/audio/audio_output_proxy.cc +++ b/media/audio/audio_output_proxy.cc
@@ -18,12 +18,12 @@ } AudioOutputProxy::~AudioOutputProxy() { - DCHECK(CalledOnValidThread()); + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); DCHECK(state_ == kCreated || state_ == kClosed) << "State is: " << state_; } bool AudioOutputProxy::Open() { - DCHECK(CalledOnValidThread()); + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); DCHECK_EQ(state_, kCreated); if (!dispatcher_ || !dispatcher_->OpenStream()) { @@ -36,7 +36,7 @@ } void AudioOutputProxy::Start(AudioSourceCallback* callback) { - DCHECK(CalledOnValidThread()); + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); // We need to support both states since the callback may not handle OnError() // immediately (or at all). It's also possible for subsequent StartStream() @@ -52,7 +52,7 @@ } void AudioOutputProxy::Stop() { - DCHECK(CalledOnValidThread()); + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); if (state_ != kPlaying) return; @@ -62,7 +62,7 @@ } void AudioOutputProxy::SetVolume(double volume) { - DCHECK(CalledOnValidThread()); + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); volume_ = volume; if (dispatcher_) @@ -70,12 +70,12 @@ } void AudioOutputProxy::GetVolume(double* volume) { - DCHECK(CalledOnValidThread()); + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); *volume = volume_; } void AudioOutputProxy::Close() { - DCHECK(CalledOnValidThread()); + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); DCHECK(state_ == kCreated || state_ == kOpenError || state_ == kOpened || state_ == kStartError);
diff --git a/media/audio/audio_output_proxy.h b/media/audio/audio_output_proxy.h index 16a0628..d68622f84b 100644 --- a/media/audio/audio_output_proxy.h +++ b/media/audio/audio_output_proxy.h
@@ -8,7 +8,7 @@ #include "base/compiler_specific.h" #include "base/macros.h" #include "base/memory/weak_ptr.h" -#include "base/threading/non_thread_safe.h" +#include "base/sequence_checker.h" #include "media/audio/audio_io.h" #include "media/base/audio_parameters.h" @@ -24,9 +24,7 @@ // // AudioOutputProxy uses AudioOutputDispatcher to open and close // physical output streams. -class MEDIA_EXPORT AudioOutputProxy - : public AudioOutputStream, - public NON_EXPORTED_BASE(base::NonThreadSafe) { +class MEDIA_EXPORT AudioOutputProxy : public AudioOutputStream { public: // Caller keeps ownership of |dispatcher|. explicit AudioOutputProxy(base::WeakPtr<AudioOutputDispatcher> dispatcher); @@ -62,6 +60,8 @@ // is stopped, and then started again. double volume_; + SEQUENCE_CHECKER(sequence_checker_); + DISALLOW_COPY_AND_ASSIGN(AudioOutputProxy); };
diff --git a/media/base/android/java/src/org/chromium/media/MediaCodecBridge.java b/media/base/android/java/src/org/chromium/media/MediaCodecBridge.java index 4cae7313..99b47b5 100644 --- a/media/base/android/java/src/org/chromium/media/MediaCodecBridge.java +++ b/media/base/android/java/src/org/chromium/media/MediaCodecBridge.java
@@ -420,7 +420,7 @@ return MediaCodecStatus.ERROR; } boolean usesCbcs = cipherMode == MediaCodec.CRYPTO_MODE_AES_CBC; - if (usesCbcs && !MediaCodecUtil.platformSupportsCbcsEncryption()) { + if (usesCbcs && !MediaCodecUtil.platformSupportsCbcsEncryption(Build.VERSION.SDK_INT)) { Log.e(TAG, "Encryption scheme 'cbcs' not supported on this platform."); return MediaCodecStatus.ERROR; }
diff --git a/media/base/android/java/src/org/chromium/media/MediaCodecUtil.java b/media/base/android/java/src/org/chromium/media/MediaCodecUtil.java index 8f67ebba..f8be531f 100644 --- a/media/base/android/java/src/org/chromium/media/MediaCodecUtil.java +++ b/media/base/android/java/src/org/chromium/media/MediaCodecUtil.java
@@ -627,14 +627,14 @@ } /** - * Returns true if and only if the platform we are running on supports the 'cbcs' - * encryption scheme, specifically AES CBC encryption with possibility of pattern - * encryption. + * Returns true if and only if a platform with the given SDK API level supports the 'cbcs' + * encryption scheme, specifically AES CBC encryption with possibility of pattern encryption. * While 'cbcs' scheme was originally implemented in N, there was a bug (in the * DRM code) which means that it didn't really work properly until N-MR1). */ - static boolean platformSupportsCbcsEncryption() { - return Build.VERSION.SDK_INT >= Build.VERSION_CODES.N_MR1; + @CalledByNative + static boolean platformSupportsCbcsEncryption(int sdk) { + return sdk >= Build.VERSION_CODES.N_MR1; } /**
diff --git a/media/base/android/java/src/org/chromium/media/MediaPlayerBridge.java b/media/base/android/java/src/org/chromium/media/MediaPlayerBridge.java index c6dacedf..58f669a4 100644 --- a/media/base/android/java/src/org/chromium/media/MediaPlayerBridge.java +++ b/media/base/android/java/src/org/chromium/media/MediaPlayerBridge.java
@@ -59,10 +59,7 @@ @CalledByNative protected void destroy() { - if (mLoadDataUriTask != null) { - mLoadDataUriTask.cancel(true); - mLoadDataUriTask = null; - } + cancelLoadDataUriTask(); mNativeMediaPlayerBridge = 0; } @@ -152,6 +149,7 @@ @CalledByNative protected void release() { + cancelLoadDataUriTask(); getLocalPlayer().release(); } @@ -212,10 +210,7 @@ @CalledByNative protected boolean setDataUriDataSource(final String url) { - if (mLoadDataUriTask != null) { - mLoadDataUriTask.cancel(true); - mLoadDataUriTask = null; - } + cancelLoadDataUriTask(); if (!url.startsWith("data:")) return false; int headerStop = url.indexOf(','); @@ -394,4 +389,11 @@ private native void nativeOnDidSetDataUriDataSource(long nativeMediaPlayerBridge, boolean success); + + private void cancelLoadDataUriTask() { + if (mLoadDataUriTask != null) { + mLoadDataUriTask.cancel(true); + mLoadDataUriTask = null; + } + } }
diff --git a/media/base/android/media_codec_util.cc b/media/base/android/media_codec_util.cc index 101d1696..62c5e8fc 100644 --- a/media/base/android/media_codec_util.cc +++ b/media/base/android/media_codec_util.cc
@@ -198,6 +198,12 @@ } // static +bool MediaCodecUtil::PlatformSupportsCbcsEncryption(int sdk) { + JNIEnv* env = AttachCurrentThread(); + return Java_MediaCodecUtil_platformSupportsCbcsEncryption(env, sdk); +} + +// static std::set<int> MediaCodecUtil::GetEncoderColorFormats( const std::string& mime_type) { std::set<int> color_formats;
diff --git a/media/base/android/media_codec_util.h b/media/base/android/media_codec_util.h index 4b122e3..c1b8c4be 100644 --- a/media/base/android/media_codec_util.h +++ b/media/base/android/media_codec_util.h
@@ -43,6 +43,9 @@ // Returns true if MediaCodec.setParameters() is available on the device. static bool SupportsSetParameters(); + // Returns true if MediaCodec supports CBCS Encryption. + static bool PlatformSupportsCbcsEncryption(int sdk); + // Returns whether it's possible to create a MediaCodec for the given codec // and secureness. static bool CanDecode(VideoCodec codec, bool is_secure);
diff --git a/media/base/android/media_codec_util_unittest.cc b/media/base/android/media_codec_util_unittest.cc index 879180df..7c935e91 100644 --- a/media/base/android/media_codec_util_unittest.cc +++ b/media/base/android/media_codec_util_unittest.cc
@@ -18,6 +18,7 @@ using base::android::SDK_VERSION_LOLLIPOP_MR1; using base::android::SDK_VERSION_MARSHMALLOW; using base::android::SDK_VERSION_NOUGAT; +using base::android::SDK_VERSION_NOUGAT_MR1; class MediaCodecUtilTest : public testing::Test { public: @@ -73,4 +74,13 @@ } } +TEST_F(MediaCodecUtilTest, TestCbcsAvailableIfNewerVersion) { + EXPECT_FALSE( + MediaCodecUtil::PlatformSupportsCbcsEncryption(SDK_VERSION_MARSHMALLOW)); + EXPECT_FALSE( + MediaCodecUtil::PlatformSupportsCbcsEncryption(SDK_VERSION_NOUGAT)); + EXPECT_TRUE( + MediaCodecUtil::PlatformSupportsCbcsEncryption(SDK_VERSION_NOUGAT_MR1)); +} + } // namespace media
diff --git a/net/cert/internal/nist_pkits_unittest.cc b/net/cert/internal/nist_pkits_unittest.cc index 8980709..6697ded9 100644 --- a/net/cert/internal/nist_pkits_unittest.cc +++ b/net/cert/internal/nist_pkits_unittest.cc
@@ -57,15 +57,18 @@ } void PkitsTestInfo::SetInitialExplicitPolicy(bool b) { - initial_explicit_policy = b; + initial_explicit_policy = + b ? InitialExplicitPolicy::kTrue : InitialExplicitPolicy::kFalse; } void PkitsTestInfo::SetInitialPolicyMappingInhibit(bool b) { - initial_policy_mapping_inhibit = b; + initial_policy_mapping_inhibit = b ? InitialPolicyMappingInhibit::kTrue + : InitialPolicyMappingInhibit::kFalse; } void PkitsTestInfo::SetInitialInhibitAnyPolicy(bool b) { - initial_inhibit_any_policy = b; + initial_inhibit_any_policy = + b ? InitialAnyPolicyInhibit::kTrue : InitialAnyPolicyInhibit::kFalse; } PkitsTestInfo::~PkitsTestInfo() = default;
diff --git a/net/cert/internal/nist_pkits_unittest.h b/net/cert/internal/nist_pkits_unittest.h index adc064b6..8f9ef42 100644 --- a/net/cert/internal/nist_pkits_unittest.h +++ b/net/cert/internal/nist_pkits_unittest.h
@@ -46,13 +46,15 @@ std::set<der::Input> initial_policy_set; // The value of "initial-explicit-policy". - bool initial_explicit_policy = false; + InitialExplicitPolicy initial_explicit_policy = InitialExplicitPolicy::kFalse; // The value of "initial-policy-mapping-inhibit". - bool initial_policy_mapping_inhibit = false; + InitialPolicyMappingInhibit initial_policy_mapping_inhibit = + InitialPolicyMappingInhibit::kFalse; // The value of "initial-inhibit-any-policy". - bool initial_inhibit_any_policy = false; + InitialAnyPolicyInhibit initial_inhibit_any_policy = + InitialAnyPolicyInhibit::kFalse; // This is the time when PKITS was published. der::GeneralizedTime time = {2011, 4, 15, 0, 0, 0};
diff --git a/net/cert/internal/path_builder.cc b/net/cert/internal/path_builder.cc index d1ce0bdb..05b66d6 100644 --- a/net/cert/internal/path_builder.cc +++ b/net/cert/internal/path_builder.cc
@@ -604,9 +604,12 @@ // Verify the entire certificate chain. auto result_path = base::MakeUnique<ResultPath>(); - VerifyCertificateChain(next_path_.certs, next_path_.last_cert_trust, - signature_policy_, time_, key_purpose_, - &result_path->errors); + // TODO(eroman): don't pass placeholder for policy. + VerifyCertificateChain( + next_path_.certs, next_path_.last_cert_trust, signature_policy_, time_, + key_purpose_, InitialExplicitPolicy::kFalse, {AnyPolicy()}, + InitialPolicyMappingInhibit::kFalse, InitialAnyPolicyInhibit::kFalse, + nullptr /*user_constrained_policy_set*/, &result_path->errors); bool verify_result = !result_path->errors.ContainsHighSeverityErrors(); DVLOG(1) << "CertPathBuilder VerifyCertificateChain result = "
diff --git a/net/cert/internal/path_builder_verify_certificate_chain_unittest.cc b/net/cert/internal/path_builder_verify_certificate_chain_unittest.cc index e6dfa424e..ca3d81b 100644 --- a/net/cert/internal/path_builder_verify_certificate_chain_unittest.cc +++ b/net/cert/internal/path_builder_verify_certificate_chain_unittest.cc
@@ -30,7 +30,7 @@ trust_store.AddTrustAnchorWithConstraints(test.chain.back()); break; case CertificateTrustType::UNSPECIFIED: - LOG(ERROR) << "Unexpected CertificateTrustType"; + trust_store.AddCertificateWithUnspecifiedTrust(test.chain.back()); break; case CertificateTrustType::DISTRUSTED: trust_store.AddDistrustedCertificateForTest(test.chain.back());
diff --git a/net/cert/internal/test_helpers.cc b/net/cert/internal/test_helpers.cc index 16c39cf1..70bd6447 100644 --- a/net/cert/internal/test_helpers.cc +++ b/net/cert/internal/test_helpers.cc
@@ -125,7 +125,8 @@ return ::testing::AssertionSuccess(); } -VerifyCertChainTest::VerifyCertChainTest() = default; +VerifyCertChainTest::VerifyCertChainTest() + : user_initial_policy_set{AnyPolicy()} {} VerifyCertChainTest::~VerifyCertChainTest() = default; bool VerifyCertChainTest::HasHighSeverityErrors() const {
diff --git a/net/cert/internal/test_helpers.h b/net/cert/internal/test_helpers.h index dceb068..d8b1c69 100644 --- a/net/cert/internal/test_helpers.h +++ b/net/cert/internal/test_helpers.h
@@ -95,6 +95,16 @@ // The Key Purpose to use when verifying the chain. KeyPurpose key_purpose = KeyPurpose::ANY_EKU; + InitialExplicitPolicy initial_explicit_policy = InitialExplicitPolicy::kFalse; + + std::set<der::Input> user_initial_policy_set; + + InitialPolicyMappingInhibit initial_policy_mapping_inhibit = + InitialPolicyMappingInhibit::kFalse; + + InitialAnyPolicyInhibit initial_any_policy_inhibit = + InitialAnyPolicyInhibit::kFalse; + // The expected errors/warnings from verification (as a string). std::string expected_errors;
diff --git a/net/cert/internal/trust_store_in_memory.cc b/net/cert/internal/trust_store_in_memory.cc index 34f53b57..09efd721 100644 --- a/net/cert/internal/trust_store_in_memory.cc +++ b/net/cert/internal/trust_store_in_memory.cc
@@ -28,6 +28,11 @@ AddCertificate(std::move(cert), CertificateTrust::ForDistrusted()); } +void TrustStoreInMemory::AddCertificateWithUnspecifiedTrust( + scoped_refptr<ParsedCertificate> cert) { + AddCertificate(std::move(cert), CertificateTrust::ForUnspecified()); +} + void TrustStoreInMemory::SyncGetIssuersOf(const ParsedCertificate* cert, ParsedCertificateList* issuers) { auto range = entries_.equal_range(cert->normalized_issuer().AsStringPiece());
diff --git a/net/cert/internal/trust_store_in_memory.h b/net/cert/internal/trust_store_in_memory.h index 19d542f..6c705b7 100644 --- a/net/cert/internal/trust_store_in_memory.h +++ b/net/cert/internal/trust_store_in_memory.h
@@ -37,6 +37,10 @@ // issuer/serial is probably what we would want for a real implementation). void AddDistrustedCertificateForTest(scoped_refptr<ParsedCertificate> cert); + // Adds a certificate to the store, that is neither trusted nor untrusted. + void AddCertificateWithUnspecifiedTrust( + scoped_refptr<ParsedCertificate> cert); + // TrustStore implementation: void SyncGetIssuersOf(const ParsedCertificate* cert, ParsedCertificateList* issuers) override;
diff --git a/net/cert/internal/verify_certificate_chain.cc b/net/cert/internal/verify_certificate_chain.cc index 2560b942..d4f6bc8 100644 --- a/net/cert/internal/verify_certificate_chain.cc +++ b/net/cert/internal/verify_certificate_chain.cc
@@ -4,6 +4,7 @@ #include "net/cert/internal/verify_certificate_chain.h" +#include <algorithm> #include <memory> #include "base/logging.h" @@ -63,6 +64,9 @@ "The extended key usage does not include client auth"); DEFINE_CERT_ERROR_ID(kCertIsNotTrustAnchor, "Certificate is not a trust anchor"); +DEFINE_CERT_ERROR_ID(kNoValidPolicy, "No valid policy"); +DEFINE_CERT_ERROR_ID(kPolicyMappingAnyPolicy, + "PolicyMappings must not map anyPolicy"); bool IsHandledCriticalExtensionOid(const der::Input& oid) { if (oid == BasicConstraintsOid()) @@ -78,8 +82,19 @@ return true; if (oid == SubjectAltNameOid()) return true; + // TODO(eroman): The policy qualifiers are not processed (or in some cases + // even parsed). This is fine when the policies extension is non-critical, + // however if it is critical the code should also ensure that the policy + // qualifiers are only recognized ones (CPS and User Notice). + if (oid == CertificatePoliciesOid()) + return true; + if (oid == PolicyMappingsOid()) + return true; + if (oid == PolicyConstraintsOid()) + return true; + if (oid == InhibitAnyPolicyOid()) + return true; - // TODO(eroman): Make this more complete. return false; } @@ -120,7 +135,7 @@ // The validity period for a certificate is the period of time from // notBefore through notAfter, inclusive. void VerifyTimeValidity(const ParsedCertificate& cert, - const der::GeneralizedTime time, + const der::GeneralizedTime& time, CertErrors* errors) { if (time < cert.tbs().validity_not_before) errors->AddError(kValidityFailedNotBefore); @@ -216,16 +231,546 @@ } } -// This function corresponds to RFC 5280 section 6.1.3's "Basic Certificate -// Processing" procedure. -void BasicCertificateProcessing( +// Returns |true| if |policies| contains the OID |search_oid|. +bool SetContains(const std::set<der::Input>& policies, + const der::Input& search_oid) { + return policies.count(search_oid) > 0; +} + +// Representation of RFC 5280's "valid_policy_tree", used to keep track of the +// valid policies and policy re-mappings. +// +// ValidPolicyTree differs slightly from RFC 5280's description in that: +// +// (1) It does not track "qualifier_set". This is not needed as it is not +// output by this implementation. +// +// (2) It only stores the most recent level of the policy tree rather than +// the full tree of nodes. +class ValidPolicyTree { + public: + ValidPolicyTree() {} + + struct Node { + // |root_policy| is equivalent to |valid_policy|, but in the domain of the + // caller. + // + // The reason for this distinction is the Policy Mappings extension. + // + // So whereas |valid_policy| is in the remapped domain defined by the + // issuing certificate, |root_policy| is in the fixed domain of the caller. + // + // OIDs in "user_initial_policy_set" and "user_constrained_policy_set" are + // directly comparable to |root_policy| values, but not necessarily to + // |valid_policy|. + // + // In terms of the valid policy tree, |root_policy| can be found by + // starting at the node's root ancestor, and finding the first node with a + // valid_policy other than anyPolicy. This is effectively the same process + // as used during policy tree intersection in RFC 5280 6.1.5.g.iii.1 + der::Input root_policy; + + // The same as RFC 5280's "valid_policy" variable. + der::Input valid_policy; + + // The same as RFC 5280s "expected_policy_set" variable. + std::set<der::Input> expected_policy_set; + + // Note that RFC 5280's "qualifier_set" is omitted. + }; + + // Level represents all the nodes at depth "i" in the valid_policy_tree. + using Level = std::vector<Node>; + + // Initializes the ValidPolicyTree for the given "user_initial_policy_set". + // + // In RFC 5280, the valid_policy_tree is initialized to a root node at depth + // 0 of "anyPolicy"; the intersection with the "user_initial_policy_set" is + // done at the end (Wrap Up) as described in section 6.1.5 step g. + // + // Whereas in this implementation, the restriction on policies is added here, + // and intersecting the valid policy tree during Wrap Up is no longer needed. + // + // The final "user_constrained_policy_set" obtained will be the same. The + // advantages of this approach is simpler code. + void Init(const std::set<der::Input>& user_initial_policy_set) { + Clear(); + for (const der::Input& policy_oid : user_initial_policy_set) + AddRootNode(policy_oid); + } + + // Returns the current level (i.e. all nodes at depth i in the valid + // policy tree). + const Level& current_level() const { return current_level_; } + Level& current_level() { return current_level_; } + + // In RFC 5280 valid_policy_tree may be set to null. That is represented here + // by emptiness. + bool IsNull() const { return current_level_.empty(); } + void SetNull() { Clear(); } + + // This implementation keeps only the last level of the valid policy + // tree. Calling StartLevel() returns the nodes for the previous + // level, and starts a new level. + Level StartLevel() { + Level prev_level; + std::swap(prev_level, current_level_); + return prev_level; + } + + // Gets the set of policies (in terms of root authority's policy domain) that + // are valid at the curent level of the policy tree. + // + // For example: + // + // * If the valid policy tree was initialized with anyPolicy, then this + // function returns what X.509 calls "authorities-constrained-policy-set". + // + // * If the valid policy tree was instead initialized with the + // "user-initial-policy_set", then this function returns what X.509 + // calls "user-constrained-policy-set" + // ("authorities-constrained-policy-set" intersected with the + // "user-initial-policy-set"). + void GetValidRootPolicySet(std::set<der::Input>* policy_set) { + policy_set->clear(); + for (const Node& node : current_level_) + policy_set->insert(node.root_policy); + + // If the result includes anyPolicy, simplify it to a set of size 1. + if (policy_set->size() > 1 && SetContains(*policy_set, AnyPolicy())) + *policy_set = {AnyPolicy()}; + } + + // Adds a node |n| to the current level which is a child of |parent| + // such that: + // * n.valid_policy = policy_oid + // * n.expected_policy_set = {policy_oid} + void AddNode(const Node& parent, const der::Input& policy_oid) { + AddNodeWithExpectedPolicySet(parent, policy_oid, {policy_oid}); + } + + // Adds a node |n| to the current level which is a child of |parent| + // such that: + // * n.valid_policy = policy_oid + // * n.expected_policy_set = expected_policy_set + void AddNodeWithExpectedPolicySet( + const Node& parent, + const der::Input& policy_oid, + const std::set<der::Input>& expected_policy_set) { + Node new_node; + new_node.valid_policy = policy_oid; + new_node.expected_policy_set = expected_policy_set; + + // Consider the root policy as the first policy other than anyPolicy (or + // anyPolicy if it hasn't been restricted yet). + new_node.root_policy = + (parent.root_policy == AnyPolicy()) ? policy_oid : parent.root_policy; + + current_level_.push_back(std::move(new_node)); + } + + // Returns the first node having valid_policy == anyPolicy in |level|, or + // nullptr if there is none. + static const Node* FindAnyPolicyNode(const Level& level) { + for (const Node& node : level) { + if (node.valid_policy == AnyPolicy()) + return &node; + } + return nullptr; + } + + // Deletes all nodes |n| in |level| where |n.valid_policy| matches the given + // |valid_policy|. This may re-order the nodes in |level|. + static void DeleteNodesMatchingValidPolicy(const der::Input& valid_policy, + Level* level) { + // This works by swapping nodes to the end of the vector, and then doing a + // single resize to delete them all. + auto cur = level->begin(); + auto end = level->end(); + while (cur != end) { + bool should_delete_node = cur->valid_policy == valid_policy; + if (should_delete_node) { + end = std::prev(end); + if (cur != end) + std::iter_swap(cur, end); + } else { + ++cur; + } + } + level->erase(end, level->end()); + } + + private: + // Deletes all nodes in the valid policy tree. + void Clear() { current_level_.clear(); } + + // Adds a node to the current level for OID |policy_oid|. The current level + // is assumed to be the root level. + void AddRootNode(const der::Input& policy_oid) { + Node new_node; + new_node.root_policy = policy_oid; + new_node.valid_policy = policy_oid; + new_node.expected_policy_set = {policy_oid}; + current_level_.push_back(std::move(new_node)); + } + + Level current_level_; + + DISALLOW_COPY_AND_ASSIGN(ValidPolicyTree); +}; + +// Class that encapsulates the state variables used by certificate path +// validation. +class PathVerifier { + public: + // Same parameters and meaning as VerifyCertificateChain(). + void Run(const ParsedCertificateList& certs, + const CertificateTrust& last_cert_trust, + const SignaturePolicy* signature_policy, + const der::GeneralizedTime& time, + KeyPurpose required_key_purpose, + InitialExplicitPolicy initial_explicit_policy, + const std::set<der::Input>& user_initial_policy_set, + InitialPolicyMappingInhibit initial_policy_mapping_inhibit, + InitialAnyPolicyInhibit initial_any_policy_inhibit, + std::set<der::Input>* user_constrained_policy_set, + CertPathErrors* errors); + + private: + // Verifies and updates the valid policies. This corresponds with RFC 5280 + // section 6.1.3 steps d-f. + void VerifyPolicies(const ParsedCertificate& cert, + bool is_target_cert, + CertErrors* errors); + + // Applies the policy mappings. This corresponds with RFC 5280 section 6.1.4 + // steps a-b. + void VerifyPolicyMappings(const ParsedCertificate& cert, CertErrors* errors); + + // This function corresponds to RFC 5280 section 6.1.3's "Basic Certificate + // Processing" procedure. + void BasicCertificateProcessing(const ParsedCertificate& cert, + bool is_target_cert, + const SignaturePolicy* signature_policy, + const der::GeneralizedTime& time, + KeyPurpose required_key_purpose, + CertErrors* errors); + + // This function corresponds to RFC 5280 section 6.1.4's "Preparation for + // Certificate i+1" procedure. |cert| is expected to be an intermediate. + void PrepareForNextCertificate(const ParsedCertificate& cert, + CertErrors* errors); + + // This function corresponds with RFC 5280 section 6.1.5's "Wrap-Up + // Procedure". It does processing for the final certificate (the target cert). + void WrapUp(const ParsedCertificate& cert, CertErrors* errors); + + // Enforces trust anchor constraints compatibile with RFC 5937. + // + // Note that the anchor constraints are encoded via the attached certificate + // itself. + void ApplyTrustAnchorConstraints(const ParsedCertificate& cert, + KeyPurpose required_key_purpose, + CertErrors* errors); + + // Initializes the path validation algorithm given anchor constraints. This + // follows the description in RFC 5937 + void ProcessRootCertificate(const ParsedCertificate& cert, + const CertificateTrust& trust, + KeyPurpose required_key_purpose, + CertErrors* errors); + + ValidPolicyTree valid_policy_tree_; + + // Will contain a NameConstraints for each previous cert in the chain which + // had nameConstraints. This corresponds to the permitted_subtrees and + // excluded_subtrees state variables from RFC 5280. + std::vector<const NameConstraints*> name_constraints_list_; + + // |explicit_policy_| corresponds with the same named variable from RFC 5280 + // section 6.1.2: + // + // explicit_policy: an integer that indicates if a non-NULL + // valid_policy_tree is required. The integer indicates the + // number of non-self-issued certificates to be processed before + // this requirement is imposed. Once set, this variable may be + // decreased, but may not be increased. That is, if a certificate in the + // path requires a non-NULL valid_policy_tree, a later certificate cannot + // remove this requirement. If initial-explicit-policy is set, then the + // initial value is 0, otherwise the initial value is n+1. + size_t explicit_policy_; + + // |inhibit_any_policy_| corresponds with the same named variable from RFC + // 5280 section 6.1.2: + // + // inhibit_anyPolicy: an integer that indicates whether the + // anyPolicy policy identifier is considered a match. The + // integer indicates the number of non-self-issued certificates + // to be processed before the anyPolicy OID, if asserted in a + // certificate other than an intermediate self-issued + // certificate, is ignored. Once set, this variable may be + // decreased, but may not be increased. That is, if a + // certificate in the path inhibits processing of anyPolicy, a + // later certificate cannot permit it. If initial-any-policy- + // inhibit is set, then the initial value is 0, otherwise the + // initial value is n+1. + size_t inhibit_any_policy_; + + // |policy_mapping_| corresponds with the same named variable from RFC 5280 + // section 6.1.2: + // + // policy_mapping: an integer that indicates if policy mapping + // is permitted. The integer indicates the number of non-self- + // issued certificates to be processed before policy mapping is + // inhibited. Once set, this variable may be decreased, but may + // not be increased. That is, if a certificate in the path + // specifies that policy mapping is not permitted, it cannot be + // overridden by a later certificate. If initial-policy- + // mapping-inhibit is set, then the initial value is 0, + // otherwise the initial value is n+1. + size_t policy_mapping_; + + // |working_spki_| is an amalgamation of 3 separate variables from RFC 5280: + // * working_public_key + // * working_public_key_algorithm + // * working_public_key_parameters + // + // They are combined for simplicity since the signature verification takes an + // SPKI, and the parameter inheritence is not applicable for the supported + // key types. + // + // An approximate explanation of |working_spki| is this description from RFC + // 5280 section 6.1.2: + // + // working_public_key: the public key used to verify the + // signature of a certificate. + der::Input working_spki_; + + // |working_normalized_issuer_name_| is the normalized value of the + // working_issuer_name variable in RFC 5280 section 6.1.2: + // + // working_issuer_name: the issuer distinguished name expected + // in the next certificate in the chain. + der::Input working_normalized_issuer_name_; + + // |max_path_length_| corresponds with the same named variable in RFC 5280 + // section 6.1.2. + // + // max_path_length: this integer is initialized to n, is + // decremented for each non-self-issued certificate in the path, + // and may be reduced to the value in the path length constraint + // field within the basic constraints extension of a CA + // certificate. + size_t max_path_length_; +}; + +void PathVerifier::VerifyPolicies(const ParsedCertificate& cert, + bool is_target_cert, + CertErrors* errors) { + // From RFC 5280 section 6.1.3: + // + // (d) If the certificate policies extension is present in the + // certificate and the valid_policy_tree is not NULL, process + // the policy information by performing the following steps in + // order: + if (cert.has_policy_oids() && !valid_policy_tree_.IsNull()) { + ValidPolicyTree::Level previous_level = valid_policy_tree_.StartLevel(); + + // Identify if there was a node with valid_policy == anyPolicy at depth i-1. + const ValidPolicyTree::Node* any_policy_node_prev_level = + ValidPolicyTree::FindAnyPolicyNode(previous_level); + + // (1) For each policy P not equal to anyPolicy in the + // certificate policies extension, let P-OID denote the OID + // for policy P and P-Q denote the qualifier set for policy + // P. Perform the following steps in order: + bool cert_has_any_policy = false; + for (const der::Input& p_oid : cert.policy_oids()) { + if (p_oid == AnyPolicy()) { + cert_has_any_policy = true; + continue; + } + + // (i) For each node of depth i-1 in the valid_policy_tree + // where P-OID is in the expected_policy_set, create a + // child node as follows: set the valid_policy to P-OID, + // set the qualifier_set to P-Q, and set the + // expected_policy_set to {P-OID}. + bool found_match = false; + for (const ValidPolicyTree::Node& prev_node : previous_level) { + if (SetContains(prev_node.expected_policy_set, p_oid)) { + valid_policy_tree_.AddNode(prev_node, p_oid); + found_match = true; + } + } + + // (ii) If there was no match in step (i) and the + // valid_policy_tree includes a node of depth i-1 with + // the valid_policy anyPolicy, generate a child node with + // the following values: set the valid_policy to P-OID, + // set the qualifier_set to P-Q, and set the + // expected_policy_set to {P-OID}. + if (!found_match && any_policy_node_prev_level) + valid_policy_tree_.AddNode(*any_policy_node_prev_level, p_oid); + } + + // (2) If the certificate policies extension includes the policy + // anyPolicy with the qualifier set AP-Q and either (a) + // inhibit_anyPolicy is greater than 0 or (b) i<n and the + // certificate is self-issued, then: + // + // For each node in the valid_policy_tree of depth i-1, for + // each value in the expected_policy_set (including + // anyPolicy) that does not appear in a child node, create a + // child node with the following values: set the valid_policy + // to the value from the expected_policy_set in the parent + // node, set the qualifier_set to AP-Q, and set the + // expected_policy_set to the value in the valid_policy from + // this node. + if (cert_has_any_policy && ((inhibit_any_policy_ > 0) || + (!is_target_cert && IsSelfIssued(cert)))) { + // Keep track of the existing policies at depth i. + std::set<der::Input> child_node_policies; + for (const ValidPolicyTree::Node& node : + valid_policy_tree_.current_level()) + child_node_policies.insert(node.valid_policy); + + for (const ValidPolicyTree::Node& prev_node : previous_level) { + for (const der::Input& expected_policy : + prev_node.expected_policy_set) { + if (!SetContains(child_node_policies, expected_policy)) { + child_node_policies.insert(expected_policy); + valid_policy_tree_.AddNode(prev_node, expected_policy); + } + } + } + } + + // (3) If there is a node in the valid_policy_tree of depth i-1 + // or less without any child nodes, delete that node. Repeat + // this step until there are no nodes of depth i-1 or less + // without children. + // + // Nothing needs to be done for this step, since this implementation only + // stores the nodes at depth i, and the entire level has already been + // calculated. + } + + // (e) If the certificate policies extension is not present, set the + // valid_policy_tree to NULL. + if (!cert.has_policy_oids()) + valid_policy_tree_.SetNull(); + + // (f) Verify that either explicit_policy is greater than 0 or the + // valid_policy_tree is not equal to NULL; + if (!((explicit_policy_ > 0) || !valid_policy_tree_.IsNull())) + errors->AddError(kNoValidPolicy); +} + +void PathVerifier::VerifyPolicyMappings(const ParsedCertificate& cert, + CertErrors* errors) { + if (!cert.has_policy_mappings()) + return; + + // From RFC 5280 section 6.1.4: + // + // (a) If a policy mappings extension is present, verify that the + // special value anyPolicy does not appear as an + // issuerDomainPolicy or a subjectDomainPolicy. + for (const ParsedPolicyMapping& mapping : cert.policy_mappings()) { + if (mapping.issuer_domain_policy == AnyPolicy() || + mapping.subject_domain_policy == AnyPolicy()) { + // Because this implementation continues processing certificates after + // this error, clear the valid policy tree to ensure the + // "user_constrained_policy_set" output upon failure is empty. + valid_policy_tree_.SetNull(); + errors->AddError(kPolicyMappingAnyPolicy); + } + } + + // (b) If a policy mappings extension is present, then for each + // issuerDomainPolicy ID-P in the policy mappings extension: + // + // (1) If the policy_mapping variable is greater than 0, for each + // node in the valid_policy_tree of depth i where ID-P is the + // valid_policy, set expected_policy_set to the set of + // subjectDomainPolicy values that are specified as + // equivalent to ID-P by the policy mappings extension. + // + // If no node of depth i in the valid_policy_tree has a + // valid_policy of ID-P but there is a node of depth i with a + // valid_policy of anyPolicy, then generate a child node of + // the node of depth i-1 that has a valid_policy of anyPolicy + // as follows: + // + // (i) set the valid_policy to ID-P; + // + // (ii) set the qualifier_set to the qualifier set of the + // policy anyPolicy in the certificate policies + // extension of certificate i; and + // + // (iii) set the expected_policy_set to the set of + // subjectDomainPolicy values that are specified as + // equivalent to ID-P by the policy mappings extension. + // + if (policy_mapping_ > 0) { + const ValidPolicyTree::Node* any_policy_node = + ValidPolicyTree::FindAnyPolicyNode(valid_policy_tree_.current_level()); + + // Group mappings by issuer domain policy. + std::map<der::Input, std::set<der::Input>> mappings; + for (const ParsedPolicyMapping& mapping : cert.policy_mappings()) { + mappings[mapping.issuer_domain_policy].insert( + mapping.subject_domain_policy); + } + + for (const auto& it : mappings) { + const der::Input& issuer_domain_policy = it.first; + const std::set<der::Input>& subject_domain_policies = it.second; + bool found_node = false; + + for (ValidPolicyTree::Node& node : valid_policy_tree_.current_level()) { + if (node.valid_policy == issuer_domain_policy) { + node.expected_policy_set = subject_domain_policies; + found_node = true; + } + } + + if (!found_node && any_policy_node) { + valid_policy_tree_.AddNodeWithExpectedPolicySet( + *any_policy_node, issuer_domain_policy, subject_domain_policies); + } + } + } + + // (b) If a policy mappings extension is present, then for each + // issuerDomainPolicy ID-P in the policy mappings extension: + // + // ... + // + // (2) If the policy_mapping variable is equal to 0: + // + // (i) delete each node of depth i in the valid_policy_tree + // where ID-P is the valid_policy. + // + // (ii) If there is a node in the valid_policy_tree of depth + // i-1 or less without any child nodes, delete that + // node. Repeat this step until there are no nodes of + // depth i-1 or less without children. + if (policy_mapping_ == 0) { + for (const ParsedPolicyMapping& mapping : cert.policy_mappings()) { + ValidPolicyTree::DeleteNodesMatchingValidPolicy( + mapping.issuer_domain_policy, &valid_policy_tree_.current_level()); + } + } +} + +void PathVerifier::BasicCertificateProcessing( const ParsedCertificate& cert, bool is_target_cert, const SignaturePolicy* signature_policy, const der::GeneralizedTime& time, - const der::Input& working_spki, - const der::Input& working_normalized_issuer_name, - const std::vector<const NameConstraints*>& name_constraints_list, + KeyPurpose required_key_purpose, CertErrors* errors) { // Check that the signature algorithms in Certificate vs TBSCertificate // match. This isn't part of RFC 5280 section 6.1.3, but is mandated by @@ -235,7 +780,7 @@ // Verify the digital signature using the previous certificate's key (RFC // 5280 section 6.1.3 step a.1). if (!VerifySignedData(cert.signature_algorithm(), cert.tbs_certificate_tlv(), - cert.signature_value(), working_spki, signature_policy, + cert.signature_value(), working_spki_, signature_policy, errors)) { errors->AddError(kVerifySignedDataFailed); } @@ -249,15 +794,15 @@ // Verify the certificate's issuer name matches the issuing certificate's // subject name. (RFC 5280 section 6.1.3 step a.4) - if (cert.normalized_issuer() != working_normalized_issuer_name) + if (cert.normalized_issuer() != working_normalized_issuer_name_) errors->AddError(kSubjectDoesNotMatchIssuer); // Name constraints (RFC 5280 section 6.1.3 step b & c) // If certificate i is self-issued and it is not the final certificate in the // path, skip this step for certificate i. - if (!name_constraints_list.empty() && + if (!name_constraints_list_.empty() && (!IsSelfIssued(cert) || is_target_cert)) { - for (const NameConstraints* nc : name_constraints_list) { + for (const NameConstraints* nc : name_constraints_list_) { if (!nc->IsPermittedCert(cert.normalized_subject(), cert.subject_alt_names())) { errors->AddError(kNotPermittedByNameConstraints); @@ -265,31 +810,30 @@ } } - // TODO(eroman): Steps d-f are omitted, as policy constraints are not yet - // implemented. + // RFC 5280 section 6.1.3 step d - f. + VerifyPolicies(cert, is_target_cert, errors); + + // The key purpose is checked not just for the end-entity certificate, but + // also interpreted as a constraint when it appears in intermediates. This + // goes beyond what RFC 5280 describes, but is the de-facto standard. See + // https://wiki.mozilla.org/CA:CertificatePolicyV2.1#Frequently_Asked_Questions + VerifyExtendedKeyUsage(cert, required_key_purpose, errors); } -// This function corresponds to RFC 5280 section 6.1.4's "Preparation for -// Certificate i+1" procedure. |cert| is expected to be an intermediate. -void PrepareForNextCertificate( - const ParsedCertificate& cert, - size_t* max_path_length_ptr, - der::Input* working_spki, - der::Input* working_normalized_issuer_name, - std::vector<const NameConstraints*>* name_constraints_list, - CertErrors* errors) { - // TODO(crbug.com/634456): Steps a-b are omitted, as policy mappings are not - // yet implemented. +void PathVerifier::PrepareForNextCertificate(const ParsedCertificate& cert, + CertErrors* errors) { + // RFC 5280 section 6.1.4 step a-b + VerifyPolicyMappings(cert, errors); // From RFC 5280 section 6.1.4 step c: // // Assign the certificate subject name to working_normalized_issuer_name. - *working_normalized_issuer_name = cert.normalized_subject(); + working_normalized_issuer_name_ = cert.normalized_subject(); // From RFC 5280 section 6.1.4 step d: // // Assign the certificate subjectPublicKey to working_public_key. - *working_spki = cert.tbs().spki_tlv; + working_spki_ = cert.tbs().spki_tlv; // Note that steps e and f are omitted as they are handled by // the assignment to |working_spki| above. See the definition @@ -297,10 +841,53 @@ // From RFC 5280 section 6.1.4 step g: if (cert.has_name_constraints()) - name_constraints_list->push_back(&cert.name_constraints()); + name_constraints_list_.push_back(&cert.name_constraints()); - // TODO(eroman): Steps h-j are omitted as policy - // constraints/mappings/inhibitAnyPolicy are not yet implemented. + // (h) If certificate i is not self-issued: + if (!IsSelfIssued(cert)) { + // (1) If explicit_policy is not 0, decrement explicit_policy by + // 1. + if (explicit_policy_ > 0) + explicit_policy_ -= 1; + + // (2) If policy_mapping is not 0, decrement policy_mapping by 1. + if (policy_mapping_ > 0) + policy_mapping_ -= 1; + + // (3) If inhibit_anyPolicy is not 0, decrement inhibit_anyPolicy + // by 1. + if (inhibit_any_policy_ > 0) + inhibit_any_policy_ -= 1; + } + + // (i) If a policy constraints extension is included in the + // certificate, modify the explicit_policy and policy_mapping + // state variables as follows: + if (cert.has_policy_constraints()) { + // (1) If requireExplicitPolicy is present and is less than + // explicit_policy, set explicit_policy to the value of + // requireExplicitPolicy. + if (cert.policy_constraints().has_require_explicit_policy && + cert.policy_constraints().require_explicit_policy < explicit_policy_) { + explicit_policy_ = cert.policy_constraints().require_explicit_policy; + } + + // (2) If inhibitPolicyMapping is present and is less than + // policy_mapping, set policy_mapping to the value of + // inhibitPolicyMapping. + if (cert.policy_constraints().has_inhibit_policy_mapping && + cert.policy_constraints().inhibit_policy_mapping < policy_mapping_) { + policy_mapping_ = cert.policy_constraints().inhibit_policy_mapping; + } + } + + // (j) If the inhibitAnyPolicy extension is included in the + // certificate and is less than inhibit_anyPolicy, set + // inhibit_anyPolicy to the value of inhibitAnyPolicy. + if (cert.has_inhibit_any_policy() && + cert.inhibit_any_policy() < inhibit_any_policy_) { + inhibit_any_policy_ = cert.inhibit_any_policy(); + } // From RFC 5280 section 6.1.4 step k: // @@ -327,10 +914,10 @@ // max_path_length is greater than zero and decrement // max_path_length by 1. if (!IsSelfIssued(cert)) { - if (*max_path_length_ptr == 0) { + if (max_path_length_ == 0) { errors->AddError(kMaxPathLengthViolated); } else { - --(*max_path_length_ptr); + --max_path_length_; } } @@ -340,8 +927,8 @@ // less than max_path_length, set max_path_length to the value // of pathLenConstraint. if (cert.has_basic_constraints() && cert.basic_constraints().has_path_len && - cert.basic_constraints().path_len < *max_path_length_ptr) { - *max_path_length_ptr = cert.basic_constraints().path_len; + cert.basic_constraints().path_len < max_path_length_) { + max_path_length_ = cert.basic_constraints().path_len; } // From RFC 5280 section 6.1.4 step n: @@ -408,13 +995,22 @@ } } -// This function corresponds with RFC 5280 section 6.1.5's "Wrap-Up Procedure". -// It does processing for the final certificate (the target cert). -void WrapUp(const ParsedCertificate& cert, CertErrors* errors) { - // TODO(crbug.com/634452): Steps a-b are omitted as policy constraints are not - // yet implemented. +void PathVerifier::WrapUp(const ParsedCertificate& cert, CertErrors* errors) { + // From RFC 5280 section 6.1.5: + // (a) If explicit_policy is not 0, decrement explicit_policy by 1. + if (explicit_policy_ > 0) + explicit_policy_ -= 1; - // Note step c-e are omitted the verification function does + // (b) If a policy constraints extension is included in the + // certificate and requireExplicitPolicy is present and has a + // value of 0, set the explicit_policy state variable to 0. + if (cert.has_policy_constraints() && + cert.policy_constraints().has_require_explicit_policy && + cert.policy_constraints().require_explicit_policy == 0) { + explicit_policy_ = 0; + } + + // Note step c-e are omitted as the verification function does // not output the working public key. // From RFC 5280 section 6.1.5 step f: @@ -428,24 +1024,24 @@ // directly match the procedures in RFC 5280's section 6.1. VerifyNoUnconsumedCriticalExtensions(cert, errors); - // TODO(eroman): Step g is omitted, as policy constraints are not yet - // implemented. + // RFC 5280 section 6.1.5 step g is skipped, as the intersection of valid + // policies was computed during previous steps. + // + // If either (1) the value of explicit_policy variable is greater than + // zero or (2) the valid_policy_tree is not NULL, then path processing + // has succeeded. + if (!(explicit_policy_ > 0 || !valid_policy_tree_.IsNull())) { + errors->AddError(kNoValidPolicy); + } // The following check is NOT part of RFC 5280 6.1.5's "Wrap-Up Procedure", // however is implied by RFC 5280 section 4.2.1.9. VerifyTargetCertHasConsistentCaBits(cert, errors); } -// Enforces trust anchor constraints compatibile with RFC 5937. -// -// Note that the anchor constraints are encoded via the attached certificate -// itself. -void ApplyTrustAnchorConstraints( - const ParsedCertificate& cert, - KeyPurpose required_key_purpose, - size_t* max_path_length_ptr, - std::vector<const NameConstraints*>* name_constraints_list, - CertErrors* errors) { +void PathVerifier::ApplyTrustAnchorConstraints(const ParsedCertificate& cert, + KeyPurpose required_key_purpose, + CertErrors* errors) { // This is not part of RFC 5937 nor RFC 5280, but matches the EKU handling // done for intermediates (described in Web PKI's Baseline Requirements). VerifyExtendedKeyUsage(cert, required_key_purpose, errors); @@ -454,7 +1050,7 @@ // Initialize name constraints initial-permitted/excluded-subtrees. if (cert.has_name_constraints()) - name_constraints_list->push_back(&cert.name_constraints()); + name_constraints_list_.push_back(&cert.name_constraints()); // TODO(eroman): Initialize user-initial-policy-set based on anchor // constraints. @@ -477,7 +1073,7 @@ // NOTE: RFC 5937 does not say to enforce the CA=true part of basic // constraints. if (cert.has_basic_constraints() && cert.basic_constraints().has_path_len) - *max_path_length_ptr = cert.basic_constraints().path_len; + max_path_length_ = cert.basic_constraints().path_len; // From RFC 5937 section 2: // @@ -487,22 +1083,15 @@ VerifyNoUnconsumedCriticalExtensions(cert, errors); } -// Initializes the path validation algorithm given anchor constraints. This -// follows the description in RFC 5937 -void ProcessRootCertificate( - const ParsedCertificate& cert, - const CertificateTrust& trust, - KeyPurpose required_key_purpose, - size_t* max_path_length_ptr, - std::vector<const NameConstraints*>* name_constraints_list, - der::Input* working_spki, - der::Input* working_normalized_issuer_name, - CertErrors* errors) { +void PathVerifier::ProcessRootCertificate(const ParsedCertificate& cert, + const CertificateTrust& trust, + KeyPurpose required_key_purpose, + CertErrors* errors) { // Use the certificate's SPKI and subject when verifying the next certificate. // Note this is initialized even in the case of untrusted roots (they already // emit an error for the distrust). - *working_spki = cert.tbs().spki_tlv; - *working_normalized_issuer_name = cert.normalized_subject(); + working_spki_ = cert.tbs().spki_tlv; + working_normalized_issuer_name_ = cert.normalized_subject(); switch (trust.type) { case CertificateTrustType::UNSPECIFIED: @@ -517,24 +1106,26 @@ case CertificateTrustType::TRUSTED_ANCHOR_WITH_CONSTRAINTS: // If the trust anchor has constraints, enforce them. if (trust.type == CertificateTrustType::TRUSTED_ANCHOR_WITH_CONSTRAINTS) { - ApplyTrustAnchorConstraints(cert, required_key_purpose, - max_path_length_ptr, name_constraints_list, - errors); + ApplyTrustAnchorConstraints(cert, required_key_purpose, errors); } break; } } -} // namespace - -// This implementation is structured to mimic the description of certificate -// path verification given by RFC 5280 section 6.1. -void VerifyCertificateChain(const ParsedCertificateList& certs, - const CertificateTrust& last_cert_trust, - const SignaturePolicy* signature_policy, - const der::GeneralizedTime& time, - KeyPurpose required_key_purpose, - CertPathErrors* errors) { +void PathVerifier::Run( + const ParsedCertificateList& certs, + const CertificateTrust& last_cert_trust, + const SignaturePolicy* signature_policy, + const der::GeneralizedTime& time, + KeyPurpose required_key_purpose, + InitialExplicitPolicy initial_explicit_policy, + const std::set<der::Input>& user_initial_policy_set, + InitialPolicyMappingInhibit initial_policy_mapping_inhibit, + InitialAnyPolicyInhibit initial_any_policy_inhibit, + std::set<der::Input>* user_constrained_policy_set, + CertPathErrors* errors) { + // This implementation is structured to mimic the description of certificate + // path verification given by RFC 5280 section 6.1. DCHECK(signature_policy); DCHECK(errors); @@ -551,50 +1142,48 @@ return; } - // Will contain a NameConstraints for each previous cert in the chain which - // had nameConstraints. This corresponds to the permitted_subtrees and - // excluded_subtrees state variables from RFC 5280. - std::vector<const NameConstraints*> name_constraints_list; + // RFC 5280's "n" variable is the length of the path, which does not count + // the trust anchor. (Although in practice it doesn't really change behaviors + // if n is used in place of n+1). + const size_t n = certs.size() - 1; - // |working_spki| is an amalgamation of 3 separate variables from RFC 5280: - // * working_public_key - // * working_public_key_algorithm - // * working_public_key_parameters - // - // They are combined for simplicity since the signature verification takes an - // SPKI, and the parameter inheritence is not applicable for the supported - // key types. - // - // An approximate explanation of |working_spki| is this description from RFC - // 5280 section 6.1.2: - // - // working_public_key: the public key used to verify the - // signature of a certificate. - der::Input working_spki; + valid_policy_tree_.Init(user_initial_policy_set); - // |working_normalized_issuer_name| is the normalized value of the - // working_issuer_name variable in RFC 5280 section 6.1.2: + // RFC 5280 section section 6.1.2: // - // working_issuer_name: the issuer distinguished name expected - // in the next certificate in the chain. - der::Input working_normalized_issuer_name; + // If initial-explicit-policy is set, then the initial value + // [of explicit_policy] is 0, otherwise the initial value is n+1. + explicit_policy_ = + initial_explicit_policy == InitialExplicitPolicy::kTrue ? 0 : n + 1; - // |max_path_length| corresponds with the same named variable in RFC 5280 - // section 6.1.2: + // RFC 5280 section section 6.1.2: // - // max_path_length: this integer is initialized to n, is - // decremented for each non-self-issued certificate in the path, - // and may be reduced to the value in the path length constraint - // field within the basic constraints extension of a CA - // certificate. - size_t max_path_length = certs.size(); + // If initial-any-policy-inhibit is set, then the initial value + // [of inhibit_anyPolicy] is 0, otherwise the initial value is n+1. + inhibit_any_policy_ = + initial_any_policy_inhibit == InitialAnyPolicyInhibit::kTrue ? 0 : n + 1; + + // RFC 5280 section section 6.1.2: + // + // If initial-policy-mapping-inhibit is set, then the initial value + // [of policy_mapping] is 0, otherwise the initial value is n+1. + policy_mapping_ = + initial_policy_mapping_inhibit == InitialPolicyMappingInhibit::kTrue + ? 0 + : n + 1; + + // RFC 5280 section section 6.1.2: + // + // max_path_length: this integer is initialized to n, ... + max_path_length_ = n; // Iterate over all the certificates in the reverse direction: starting from // the root certificate and progressing towards the target certificate. // - // * i=0 : Root certificate (i.e. trust anchor) - // * i=1 : Certificated signed by the root certificate - // * i=certs.size()-1 : Target certificate. + // * i=0 : Root certificate (i.e. trust anchor) + // * i=1 : Certificate issued by root + // * i=x : Certificate i=x is issued by certificate i=x-1 + // * i=n : Target certificate. for (size_t i = 0; i < certs.size(); ++i) { const size_t index_into_certs = certs.size() - i - 1; @@ -612,8 +1201,6 @@ if (is_root_cert) { ProcessRootCertificate(cert, last_cert_trust, required_key_purpose, - &max_path_length, &name_constraints_list, - &working_spki, &working_normalized_issuer_name, cert_errors); // Don't do any other checks for root certificates. @@ -626,28 +1213,45 @@ // - Then run "Wrap up" // - Otherwise run "Prepare for Next cert" BasicCertificateProcessing(cert, is_target_cert, signature_policy, time, - working_spki, working_normalized_issuer_name, - name_constraints_list, cert_errors); - - // The key purpose is checked not just for the end-entity certificate, but - // also interpreted as a constraint when it appears in intermediates. This - // goes beyond what RFC 5280 describes, but is the de-facto standard. See - // https://wiki.mozilla.org/CA:CertificatePolicyV2.1#Frequently_Asked_Questions - VerifyExtendedKeyUsage(cert, required_key_purpose, cert_errors); - + required_key_purpose, cert_errors); if (!is_target_cert) { - PrepareForNextCertificate(cert, &max_path_length, &working_spki, - &working_normalized_issuer_name, - &name_constraints_list, cert_errors); + PrepareForNextCertificate(cert, cert_errors); } else { WrapUp(cert, cert_errors); } } + if (user_constrained_policy_set) { + // valid_policy_tree_ already contains the intersection of valid policies + // with user_initial_policy_set. + valid_policy_tree_.GetValidRootPolicySet(user_constrained_policy_set); + } + // TODO(eroman): RFC 5280 forbids duplicate certificates per section 6.1: // // A certificate MUST NOT appear more than once in a prospective // certification path. } +} // namespace + +void VerifyCertificateChain( + const ParsedCertificateList& certs, + const CertificateTrust& last_cert_trust, + const SignaturePolicy* signature_policy, + const der::GeneralizedTime& time, + KeyPurpose required_key_purpose, + InitialExplicitPolicy initial_explicit_policy, + const std::set<der::Input>& user_initial_policy_set, + InitialPolicyMappingInhibit initial_policy_mapping_inhibit, + InitialAnyPolicyInhibit initial_any_policy_inhibit, + std::set<der::Input>* user_constrained_policy_set, + CertPathErrors* errors) { + PathVerifier verifier; + verifier.Run(certs, last_cert_trust, signature_policy, time, + required_key_purpose, initial_explicit_policy, + user_initial_policy_set, initial_policy_mapping_inhibit, + initial_any_policy_inhibit, user_constrained_policy_set, errors); +} + } // namespace net
diff --git a/net/cert/internal/verify_certificate_chain.h b/net/cert/internal/verify_certificate_chain.h index 8d1f044..a8b2917 100644 --- a/net/cert/internal/verify_certificate_chain.h +++ b/net/cert/internal/verify_certificate_chain.h
@@ -5,7 +5,7 @@ #ifndef NET_CERT_INTERNAL_VERIFY_CERTIFICATE_CHAIN_H_ #define NET_CERT_INTERNAL_VERIFY_CERTIFICATE_CHAIN_H_ -#include <vector> +#include <set> #include "base/compiler_specific.h" #include "base/memory/ref_counted.h" @@ -30,72 +30,160 @@ CLIENT_AUTH, }; +enum class InitialExplicitPolicy { + kFalse, + kTrue, +}; + +enum class InitialPolicyMappingInhibit { + kFalse, + kTrue, +}; + +enum class InitialAnyPolicyInhibit { + kFalse, + kTrue, +}; + // VerifyCertificateChain() verifies an ordered certificate path in accordance -// with RFC 5280 (with some modifications [1]). +// with RFC 5280's "Certification Path Validation" algorithm (section 6). // -// [1] Deviations from RFC 5280: +// ----------------------------------------- +// Deviations from RFC 5280 +// ----------------------------------------- // -// * If Extended Key Usage appears on intermediates it is treated as a -// restriction on subordinate certificates. +// * If Extended Key Usage appears on intermediates, it is treated as +// a restriction on subordinate certificates. // -// The caller is responsible for additionally checking: +// ----------------------------------------- +// Additional responsibilities of the caller +// ----------------------------------------- +// +// After successful path verification, the caller is responsible for +// subsequently checking: // // * The end-entity's KeyUsage before using its SPKI. -// * The end-entity's name/subjectAltName (note that name constraints from -// intermediates will have already been applied, so just need to check -// the end-entity for a match). -// * Policies -// -// WARNING: This implementation is in progress, and is currently incomplete. -// Consult an OWNER before using it. -// -// TODO(eroman): Take a CertPath instead of ParsedCertificateList + -// TrustAnchor. +// * The end-entity's name/subjectAltName. Name constraints from intermediates +// will have already been applied, so it is sufficient to check the +// end-entity for a match. // // --------- // Inputs // --------- // -// cert_chain: -// A non-empty chain of N DER-encoded certificates, listed in the -// "forward" direction. The first certificate is the target certificate to -// verify, and the last certificate has trustedness given by -// |last_cert_trust|. +// certs: +// A non-empty chain of DER-encoded certificates, listed in the +// "forward" direction. The first certificate is the target +// certificate to verify, and the last certificate has trustedness +// given by |last_cert_trust| (generally a trust anchor). // -// * cert_chain[0] is the target certificate to verify. -// * cert_chain[i+1] holds the certificate that issued cert_chain[i]. -// * cert_chain[N-1] the root certificate +// * certs[0] is the target certificate to verify. +// * certs[i+1] holds the certificate that issued cert_chain[i]. +// * certs[N-1] the root certificate +// +// Note that THIS IS NOT identical in meaning to the same named +// "certs" input defined in RFC 5280 section 6.1.1.a. The differences +// are: +// +// * The order of certificates is reversed +// * In RFC 5280 "certs" DOES NOT include the trust anchor // // last_cert_trust: -// Trustedness of certs.back(). The trustedness of certs.back() MUST BE -// decided by the caller -- this function takes it purely as an input. -// Moreover, the CertificateTrust can be used to specify trust anchor -// constraints [1] +// Trustedness of |certs.back()|. The trustedness of |certs.back()| +// MUST BE decided by the caller -- this function takes it purely as +// an input. Moreover, the CertificateTrust can be used to specify +// trust anchor constraints. +// +// This combined with |certs.back()| (the root certificate) fills a +// similar role to "trust anchor information" defined in RFC 5280 +// section 6.1.1.d. // // signature_policy: // The policy to use when verifying signatures (what hash algorithms are // allowed, what length keys, what named curves, etc). // // time: -// The UTC time to use for expiration checks. +// The UTC time to use for expiration checks. This is equivalent to +// the input from RFC 5280 section 6.1.1: // -// key_purpose: +// (b) the current date/time. +// +// required_key_purpose: // The key purpose that the target certificate needs to be valid for. // +// user_initial_policy_set: +// This is equivalent to the same named input in RFC 5280 section +// 6.1.1: +// +// (c) user-initial-policy-set: A set of certificate policy +// identifiers naming the policies that are acceptable to the +// certificate user. The user-initial-policy-set contains the +// special value any-policy if the user is not concerned about +// certificate policy. +// +// initial_policy_mapping_inhibit: +// This is equivalent to the same named input in RFC 5280 section +// 6.1.1: +// +// (e) initial-policy-mapping-inhibit, which indicates if policy +// mapping is allowed in the certification path. +// +// initial_explicit_policy: +// This is equivalent to the same named input in RFC 5280 section +// 6.1.1: +// +// (f) initial-explicit-policy, which indicates if the path must be +// valid for at least one of the certificate policies in the +// user-initial-policy-set. +// +// initial_any_policy_inhibit: +// This is equivalent to the same named input in RFC 5280 section +// 6.1.1: +// +// (g) initial-any-policy-inhibit, which indicates whether the +// anyPolicy OID should be processed if it is included in a +// certificate. +// // --------- // Outputs // --------- +// +// user_constrained_policy_set: +// Can be null. If non-null, |user_constrained_policy_set| will be filled +// with the matching policies (intersected with user_initial_policy_set). +// This is equivalent to the same named output in X.509 section 10.2. +// Note that it is OK for this to point to input user_initial_policy_set. +// // errors: // Must be non-null. The set of errors/warnings encountered while // validating the path are appended to this structure. If verification // failed, then there is guaranteed to be at least 1 high severity error // written to |errors|. // -// [1] Conceptually VerifyCertificateChain() sets RFC 5937's -// "enforceTrustAnchorConstraints" to true. And one specifies whether to -// interpret a root certificate as having trust anchor constraints through the -// |last_cert_trust| parameter. The constraints are just a subset of the -// extensions present in the certificate: +// ------------------------- +// Trust Anchor constraints +// ------------------------- +// +// Conceptually, VerifyCertificateChain() sets RFC 5937's +// "enforceTrustAnchorConstraints" to true. +// +// One specifies trust anchor constraints using the |last_cert_trust| +// parameter in conjunction with extensions appearing in |certs.back()|. +// +// The trust anchor |certs.back()| is always passed as a certificate to +// this function, however the manner in which that certificate is +// interpreted depends on |last_cert_trust|: +// +// TRUSTED_ANCHOR: +// +// No properties from the root certificate, other than its Subject and +// SPKI, are checked during verification. This is the usual +// interpretation for a "trust anchor". +// +// TRUSTED_ANCHOR_WITH_CONSTRAINTS: +// +// Only a subset of extensions and properties from the certificate are checked, +// as described by RFC 5937. // // * Signature: No // * Validity (expiration): No @@ -104,17 +192,24 @@ // * Basic constraints: Yes, but only the pathlen (CA=false is accepted) // * Name constraints: Yes // * Certificate policies: Not currently, TODO(crbug.com/634453) +// * Policy Mappings: No // * inhibitAnyPolicy: Not currently, TODO(crbug.com/634453) // * PolicyConstraints: Not currently, TODO(crbug.com/634452) // // The presence of any other unrecognized extension marked as critical fails // validation. -NET_EXPORT void VerifyCertificateChain(const ParsedCertificateList& certs, - const CertificateTrust& last_cert_trust, - const SignaturePolicy* signature_policy, - const der::GeneralizedTime& time, - KeyPurpose required_key_purpose, - CertPathErrors* errors); +NET_EXPORT void VerifyCertificateChain( + const ParsedCertificateList& certs, + const CertificateTrust& last_cert_trust, + const SignaturePolicy* signature_policy, + const der::GeneralizedTime& time, + KeyPurpose required_key_purpose, + InitialExplicitPolicy initial_explicit_policy, + const std::set<der::Input>& user_initial_policy_set, + InitialPolicyMappingInhibit initial_policy_mapping_inhibit, + InitialAnyPolicyInhibit initial_any_policy_inhibit, + std::set<der::Input>* user_constrained_policy_set, + CertPathErrors* errors); // TODO(crbug.com/634443): Move exported errors to a central location? extern CertErrorId kValidityFailedNotAfter;
diff --git a/net/cert/internal/verify_certificate_chain_pkits_unittest.cc b/net/cert/internal/verify_certificate_chain_pkits_unittest.cc index 8138dae9..f86e1e9e 100644 --- a/net/cert/internal/verify_certificate_chain_pkits_unittest.cc +++ b/net/cert/internal/verify_certificate_chain_pkits_unittest.cc
@@ -67,12 +67,19 @@ SimpleSignaturePolicy signature_policy(1024); + std::set<der::Input> user_constrained_policy_set; + CertPathErrors path_errors; - VerifyCertificateChain(input_chain, CertificateTrust::ForTrustAnchor(), - &signature_policy, info.time, KeyPurpose::ANY_EKU, - &path_errors); + VerifyCertificateChain( + input_chain, CertificateTrust::ForTrustAnchor(), &signature_policy, + info.time, KeyPurpose::ANY_EKU, info.initial_explicit_policy, + info.initial_policy_set, info.initial_policy_mapping_inhibit, + info.initial_inhibit_any_policy, &user_constrained_policy_set, + &path_errors); bool did_succeed = !path_errors.ContainsHighSeverityErrors(); + EXPECT_EQ(info.user_constrained_policy_set, user_constrained_policy_set); + // TODO(crbug.com/634443): Test errors on failure? if (info.should_validate != did_succeed) { ASSERT_EQ(info.should_validate, did_succeed) @@ -222,6 +229,21 @@ PkitsTest07KeyUsage, VerifyCertificateChainPkitsTestDelegate); INSTANTIATE_TYPED_TEST_CASE_P(VerifyCertificateChain, + PkitsTest08CertificatePolicies, + VerifyCertificateChainPkitsTestDelegate); +INSTANTIATE_TYPED_TEST_CASE_P(VerifyCertificateChain, + PkitsTest09RequireExplicitPolicy, + VerifyCertificateChainPkitsTestDelegate); +INSTANTIATE_TYPED_TEST_CASE_P(VerifyCertificateChain, + PkitsTest10PolicyMappings, + VerifyCertificateChainPkitsTestDelegate); +INSTANTIATE_TYPED_TEST_CASE_P(VerifyCertificateChain, + PkitsTest11InhibitPolicyMapping, + VerifyCertificateChainPkitsTestDelegate); +INSTANTIATE_TYPED_TEST_CASE_P(VerifyCertificateChain, + PkitsTest12InhibitAnyPolicy, + VerifyCertificateChainPkitsTestDelegate); +INSTANTIATE_TYPED_TEST_CASE_P(VerifyCertificateChain, PkitsTest13NameConstraints, VerifyCertificateChainPkitsTestDelegate); INSTANTIATE_TYPED_TEST_CASE_P(VerifyCertificateChain, @@ -232,8 +254,4 @@ // PkitsTest05VerifyingPathswithSelfIssuedCertificates, // PkitsTest14DistributionPoints, PkitsTest15DeltaCRLs -// TODO(mattm): Certificate Policies support: PkitsTest08CertificatePolicies, -// PkitsTest09RequireExplicitPolicy PkitsTest10PolicyMappings, -// PkitsTest11InhibitPolicyMapping, PkitsTest12InhibitAnyPolicy - } // namespace net
diff --git a/net/cert/internal/verify_certificate_chain_unittest.cc b/net/cert/internal/verify_certificate_chain_unittest.cc index 13c689f..82851d0 100644 --- a/net/cert/internal/verify_certificate_chain_unittest.cc +++ b/net/cert/internal/verify_certificate_chain_unittest.cc
@@ -19,8 +19,13 @@ SimpleSignaturePolicy signature_policy(1024); CertPathErrors errors; - VerifyCertificateChain(test.chain, test.last_cert_trust, &signature_policy, - test.time, test.key_purpose, &errors); + // TODO(eroman): Check user_constrained_policy_set. + VerifyCertificateChain( + test.chain, test.last_cert_trust, &signature_policy, test.time, + test.key_purpose, test.initial_explicit_policy, + test.user_initial_policy_set, test.initial_policy_mapping_inhibit, + test.initial_any_policy_inhibit, + nullptr /*user_constrained_policy_set*/, &errors); EXPECT_EQ(test.expected_errors, errors.ToDebugString(test.chain)) << "Test file: " << test_file_path; }
diff --git a/net/third_party/nist-pkits/generate_tests.py b/net/third_party/nist-pkits/generate_tests.py index 04afc6f8..8083d62a 100644 --- a/net/third_party/nist-pkits/generate_tests.py +++ b/net/third_party/nist-pkits/generate_tests.py
@@ -688,6 +688,17 @@ user_constrained_policy_set=[]), ], + '4.10.7': [ # Invalid Mapping From anyPolicy Test7 + # Procedure: Validate Invalid Mapping From anyPolicy Test7 EE using the + # default settings or open and verify Signed Test Message 6.2.2.100 using + # the default settings. + # + # Expected Result: The path should not validate successfully since the + # intermediate certificate includes a policy mapping extension in which + # anyPolicy appears as an issuerDomainPolicy. + TestInfo(False, user_constrained_policy_set=[]), + ], + '4.10.8': [ # Invalid Mapping To anyPolicy Test8 # Procedure: Validate Invalid Mapping To anyPolicy Test8 EE using the # default settings or open and verify Signed Test Message 6.2.2.101 using @@ -696,8 +707,6 @@ # Expected Result: The path should not validate successfully since the # intermediate certificate includes a policy mapping extension in which # anyPolicy appears as an subjectDomainPolicy. - # - # TODO(eroman): What should user_constrained_policy_set be? TestInfo(False, user_constrained_policy_set=[]), ],
diff --git a/net/third_party/nist-pkits/pkits_testcases-inl.h b/net/third_party/nist-pkits/pkits_testcases-inl.h index d4b709d..8ddf7c6 100644 --- a/net/third_party/nist-pkits/pkits_testcases-inl.h +++ b/net/third_party/nist-pkits/pkits_testcases-inl.h
@@ -2113,6 +2113,7 @@ "MappingFromanyPolicyCACRL"}; PkitsTestInfo info; info.should_validate = false; + info.SetUserConstrainedPolicySet(""); this->RunTest(certs, crls, info); }
diff --git a/remoting/host/heartbeat_sender.cc b/remoting/host/heartbeat_sender.cc index d5d38a5..3c54ea5 100644 --- a/remoting/host/heartbeat_sender.cc +++ b/remoting/host/heartbeat_sender.cc
@@ -48,10 +48,16 @@ const char kSetIntervalTag[] = "set-interval"; const char kExpectedSequenceIdTag[] = "expected-sequence-id"; -const int64_t kDefaultHeartbeatIntervalMs = 5 * 60 * 1000; // 5 minutes. -const int64_t kResendDelayMs = 10 * 1000; // 10 seconds. -const int64_t kResendDelayOnHostNotFoundMs = 10 * 1000; // 10 seconds. +constexpr base::TimeDelta kDefaultHeartbeatInterval = + base::TimeDelta::FromMinutes(5); +constexpr base::TimeDelta kHeartbeatResponseTimeout = + base::TimeDelta::FromSeconds(30); +constexpr base::TimeDelta kResendDelay = base::TimeDelta::FromSeconds(10); +constexpr base::TimeDelta kResendDelayOnHostNotFound = + base::TimeDelta::FromSeconds(10); + const int kMaxResendOnHostNotFoundCount = 12; // 2 minutes (12 x 10 seconds). +const int kMaxHeartbeatTimeouts = 2; } // namespace @@ -68,12 +74,7 @@ signal_strategy_(signal_strategy), host_key_pair_(host_key_pair), directory_bot_jid_(directory_bot_jid), - interval_ms_(kDefaultHeartbeatIntervalMs), - sequence_id_(0), - sequence_id_was_set_(false), - sequence_id_recent_set_num_(0), - heartbeat_succeeded_(false), - failed_startup_heartbeat_count_(0) { + interval_(kDefaultHeartbeatInterval) { DCHECK(signal_strategy_); DCHECK(host_key_pair_.get()); DCHECK(thread_checker_.CalledOnValidThread()); @@ -92,10 +93,9 @@ void HeartbeatSender::OnSignalStrategyStateChange(SignalStrategy::State state) { DCHECK(thread_checker_.CalledOnValidThread()); if (state == SignalStrategy::CONNECTED) { - iq_sender_.reset(new IqSender(signal_strategy_)); + iq_sender_ = base::MakeUnique<IqSender>(signal_strategy_); SendStanza(); - timer_.Start(FROM_HERE, base::TimeDelta::FromMilliseconds(interval_ms_), - this, &HeartbeatSender::SendStanza); + timer_.Start(FROM_HERE, interval_, this, &HeartbeatSender::SendStanza); } else if (state == SignalStrategy::DISCONNECTED) { request_.reset(); iq_sender_.reset(); @@ -169,18 +169,32 @@ request_ = iq_sender_->SendIq( buzz::STR_SET, directory_bot_jid_, CreateHeartbeatMessage(), - base::Bind(&HeartbeatSender::ProcessResponse, - base::Unretained(this), + base::Bind(&HeartbeatSender::ProcessResponse, base::Unretained(this), !host_offline_reason_.empty())); + request_->SetTimeout(kHeartbeatResponseTimeout); ++sequence_id_; } -void HeartbeatSender::ProcessResponse( - bool is_offline_heartbeat_response, - IqRequest* request, - const XmlElement* response) { +void HeartbeatSender::ProcessResponse(bool is_offline_heartbeat_response, + IqRequest* request, + const XmlElement* response) { DCHECK(thread_checker_.CalledOnValidThread()); + if (!response) { + timed_out_heartbeats_count_++; + if (timed_out_heartbeats_count_ >= kMaxHeartbeatTimeouts) { + LOG(ERROR) << "Heartbeat timed out. Reconnecting XMPP."; + timed_out_heartbeats_count_ = 0; + // SignalingConnector will reconnect SignalStrategy. + signal_strategy_->Disconnect(); + } else { + LOG(ERROR) << "Heartbeat timed out."; + } + return; + } else { + timed_out_heartbeats_count_ = 0; + } + std::string type = response->Attr(buzz::QN_TYPE); if (type == buzz::STR_ERROR) { const XmlElement* error_element = @@ -195,11 +209,8 @@ // exit. failed_startup_heartbeat_count_++; if (!heartbeat_succeeded_ && (failed_startup_heartbeat_count_ <= - kMaxResendOnHostNotFoundCount)) { - timer_resend_.Start(FROM_HERE, - base::TimeDelta::FromMilliseconds( - kResendDelayOnHostNotFoundMs), - this, + kMaxResendOnHostNotFoundCount)) { + timer_resend_.Start(FROM_HERE, kResendDelayOnHostNotFound, this, &HeartbeatSender::ResendStanza); return; } @@ -224,12 +235,13 @@ kSetIntervalTag)); if (set_interval_element) { const std::string& interval_str = set_interval_element->BodyText(); - int interval; - if (!base::StringToInt(interval_str, &interval) || interval <= 0) { + int interval_seconds; + if (!base::StringToInt(interval_str, &interval_seconds) || + interval_seconds <= 0) { LOG(ERROR) << "Received invalid set-interval: " << set_interval_element->Str(); } else { - SetInterval(interval * base::Time::kMillisecondsPerSecond); + SetInterval(base::TimeDelta::FromSeconds(interval_seconds)); } } @@ -270,15 +282,14 @@ } } -void HeartbeatSender::SetInterval(int interval) { - if (interval != interval_ms_) { - interval_ms_ = interval; +void HeartbeatSender::SetInterval(base::TimeDelta interval) { + if (interval != interval_) { + interval_ = interval; // Restart the timer with the new interval. if (timer_.IsRunning()) { timer_.Stop(); - timer_.Start(FROM_HERE, base::TimeDelta::FromMilliseconds(interval_ms_), - this, &HeartbeatSender::SendStanza); + timer_.Start(FROM_HERE, interval_, this, &HeartbeatSender::SendStanza); } } } @@ -296,11 +307,11 @@ } else { HOST_LOG << "The heartbeat sequence ID has been set more than once: " << "the new value is " << sequence_id; - double delay = pow(2.0, sequence_id_recent_set_num_) * - (1 + base::RandDouble()) * kResendDelayMs; - if (delay <= interval_ms_) { - timer_resend_.Start(FROM_HERE, base::TimeDelta::FromMilliseconds(delay), - this, &HeartbeatSender::ResendStanza); + base::TimeDelta delay = pow(2.0, sequence_id_recent_set_num_) * + (1 + base::RandDouble()) * kResendDelay; + if (delay <= interval_) { + timer_resend_.Start(FROM_HERE, delay, this, + &HeartbeatSender::ResendStanza); } } sequence_id_was_set_ = true;
diff --git a/remoting/host/heartbeat_sender.h b/remoting/host/heartbeat_sender.h index da5ef091..3553a86f 100644 --- a/remoting/host/heartbeat_sender.h +++ b/remoting/host/heartbeat_sender.h
@@ -131,6 +131,7 @@ FRIEND_TEST_ALL_PREFIXES(HeartbeatSenderTest, ProcessResponseSetInterval); FRIEND_TEST_ALL_PREFIXES(HeartbeatSenderTest, ProcessResponseExpectedSequenceId); + FRIEND_TEST_ALL_PREFIXES(HeartbeatSenderTest, ResponseTimeout); friend class HeartbeatSenderTest; void SendStanza(); @@ -139,7 +140,7 @@ void ProcessResponse(bool is_offline_heartbeat_response, IqRequest* request, const buzz::XmlElement* response); - void SetInterval(int interval); + void SetInterval(base::TimeDelta interval); void SetSequenceId(int sequence_id); // Handlers for host-offline-reason completion and timeout. @@ -158,14 +159,15 @@ std::string directory_bot_jid_; std::unique_ptr<IqSender> iq_sender_; std::unique_ptr<IqRequest> request_; - int interval_ms_; + base::TimeDelta interval_; base::RepeatingTimer timer_; base::OneShotTimer timer_resend_; - int sequence_id_; - bool sequence_id_was_set_; - int sequence_id_recent_set_num_; - bool heartbeat_succeeded_; - int failed_startup_heartbeat_count_; + int sequence_id_ = 0; + bool sequence_id_was_set_ = false; + int sequence_id_recent_set_num_ = 0; + bool heartbeat_succeeded_ = false; + int failed_startup_heartbeat_count_ = 0; + int timed_out_heartbeats_count_ = 0; // Fields to send and indicate completion of sending host-offline-reason. std::string host_offline_reason_;
diff --git a/remoting/host/heartbeat_sender_unittest.cc b/remoting/host/heartbeat_sender_unittest.cc index 18f9126..55de05f 100644 --- a/remoting/host/heartbeat_sender_unittest.cc +++ b/remoting/host/heartbeat_sender_unittest.cc
@@ -41,8 +41,9 @@ const char kTestJid[] = "User@gmail.com/chromotingABC123"; const char kTestJidNormalized[] = "user@gmail.com/chromotingABC123"; const char kStanzaId[] = "123"; -const int kTestInterval = 123; -const base::TimeDelta kTestTimeout = base::TimeDelta::FromSeconds(123); +constexpr base::TimeDelta kTestInterval = base::TimeDelta::FromSeconds(123); +constexpr base::TimeDelta kOfflineReasonTimeout = + base::TimeDelta::FromSeconds(123); } // namespace @@ -86,9 +87,8 @@ const char* expected_sequence_id, const char* expected_host_offline_reason); - void ProcessResponseWithInterval( - bool is_offline_heartbeat_response, - int interval); + void ProcessResponseWithInterval(bool is_offline_heartbeat_response, + base::TimeDelta interval); base::MessageLoop message_loop_; MockSignalStrategy signal_strategy_; @@ -206,7 +206,7 @@ void HeartbeatSenderTest::ProcessResponseWithInterval( bool is_offline_heartbeat_response, - int interval) { + base::TimeDelta interval) { std::unique_ptr<XmlElement> response(new XmlElement(buzz::QN_IQ)); response->AddAttr(QName(std::string(), "type"), "result"); @@ -218,7 +218,7 @@ QName(kChromotingXmlNamespace, "set-interval")); result->AddElement(set_interval); - set_interval->AddText(base::IntToString(interval)); + set_interval->AddText(base::IntToString(interval.InSeconds())); heartbeat_sender_->ProcessResponse( is_offline_heartbeat_response, nullptr, response.get()); @@ -230,7 +230,7 @@ ProcessResponseWithInterval(false, kTestInterval); - EXPECT_EQ(kTestInterval * 1000, heartbeat_sender_->interval_ms_); + EXPECT_EQ(kTestInterval, heartbeat_sender_->interval_); } // Make sure SetHostOfflineReason sends a correct stanza. @@ -247,7 +247,7 @@ .WillRepeatedly(Return(SignalStrategy::CONNECTED)); EXPECT_CALL(mock_ack_callback, Run(_)).Times(0); - heartbeat_sender_->SetHostOfflineReason("test_error", kTestTimeout, + heartbeat_sender_->SetHostOfflineReason("test_error", kOfflineReasonTimeout, mock_ack_callback.Get()); heartbeat_sender_->OnSignalStrategyStateChange(SignalStrategy::CONNECTED); base::RunLoop().RunUntilIdle(); @@ -277,7 +277,7 @@ // Callback should not run, until response to offline-reason. EXPECT_CALL(mock_ack_callback, Run(_)).Times(0); - heartbeat_sender_->SetHostOfflineReason("test_error", kTestTimeout, + heartbeat_sender_->SetHostOfflineReason("test_error", kOfflineReasonTimeout, mock_ack_callback.Get()); heartbeat_sender_->OnSignalStrategyStateChange(SignalStrategy::CONNECTED); base::RunLoop().RunUntilIdle(); @@ -372,4 +372,34 @@ EXPECT_EQ(expected_signature, signature->BodyText()); } +TEST_F(HeartbeatSenderTest, ResponseTimeout) { + XmlElement* sent_iq = nullptr; + EXPECT_CALL(signal_strategy_, GetNextId()).WillOnce(Return(kStanzaId)); + EXPECT_CALL(signal_strategy_, SendStanzaPtr(NotNull())) + .WillOnce(DoAll(SaveArg<0>(&sent_iq), Return(true))); + EXPECT_CALL(signal_strategy_, GetState()) + .WillRepeatedly(Return(SignalStrategy::CONNECTED)); + + heartbeat_sender_->OnSignalStrategyStateChange(SignalStrategy::CONNECTED); + base::RunLoop().RunUntilIdle(); + + std::unique_ptr<XmlElement> stanza(sent_iq); + ASSERT_TRUE(stanza); + + XmlElement* sent_iq2 = nullptr; + EXPECT_CALL(signal_strategy_, GetNextId()).WillOnce(Return(kStanzaId + 1)); + EXPECT_CALL(signal_strategy_, SendStanzaPtr(NotNull())) + .WillOnce(DoAll(SaveArg<0>(&sent_iq2), Return(true))); + + heartbeat_sender_->ProcessResponse(false, nullptr, nullptr /* timeout */); + heartbeat_sender_->DoSendStanza(); + base::RunLoop().RunUntilIdle(); + + std::unique_ptr<XmlElement> stanza2(sent_iq2); + ASSERT_TRUE(stanza2); + + EXPECT_CALL(signal_strategy_, Disconnect()); + heartbeat_sender_->ProcessResponse(false, nullptr, nullptr /* timeout */); +} + } // namespace remoting
diff --git a/services/resource_coordinator/public/interfaces/BUILD.gn b/services/resource_coordinator/public/interfaces/BUILD.gn index d68debb..35c4ca5 100644 --- a/services/resource_coordinator/public/interfaces/BUILD.gn +++ b/services/resource_coordinator/public/interfaces/BUILD.gn
@@ -27,6 +27,13 @@ export_header = "services/resource_coordinator/public/cpp/resource_coordinator_export.h" + export_class_attribute_blink = + "SERVICES_RESOURCE_COORDINATOR_PUBLIC_CPP_EXPORT" + export_define_blink = + "SERVICES_RESOURCE_COORDINATOR_PUBLIC_CPP_IMPLEMENTATION=1" + export_header_blink = + "services/resource_coordinator/public/cpp/resource_coordinator_export.h" + # TODO(crbug.com/714018): Convert the implementation to use OnceCallback. use_once_callback = false }
diff --git a/services/ui/public/interfaces/window_manager.mojom b/services/ui/public/interfaces/window_manager.mojom index 3ddbe2c..e3896e35 100644 --- a/services/ui/public/interfaces/window_manager.mojom +++ b/services/ui/public/interfaces/window_manager.mojom
@@ -323,6 +323,10 @@ // clear. WmSetGlobalOverrideCursor(CursorData? cursor); + // Moves the cursor to the given location on the given display. + WmMoveCursorToDisplayLocation(gfx.mojom.Point display_pixels, + int64 display_id); + // Response from WmCreateTopLevelWindow() informing the client of the id for // the new window. OnWmCreatedTopLevelWindow(uint32 change_id, uint32 window_id);
diff --git a/services/ui/ws/platform_display.h b/services/ui/ws/platform_display.h index bdfb5b4..a33f638 100644 --- a/services/ui/ws/platform_display.h +++ b/services/ui/ws/platform_display.h
@@ -48,6 +48,8 @@ virtual void SetCursor(const ui::CursorData& cursor) = 0; + virtual void MoveCursorTo(const gfx::Point& window_pixel_location) = 0; + virtual void UpdateTextInputState(const ui::TextInputState& state) = 0; virtual void SetImeVisibility(bool visible) = 0;
diff --git a/services/ui/ws/platform_display_default.cc b/services/ui/ws/platform_display_default.cc index b474dcf..a807396a 100644 --- a/services/ui/ws/platform_display_default.cc +++ b/services/ui/ws/platform_display_default.cc
@@ -139,6 +139,11 @@ platform_window_->SetCursor(native_cursor.platform()); } +void PlatformDisplayDefault::MoveCursorTo( + const gfx::Point& window_pixel_location) { + platform_window_->MoveCursorTo(window_pixel_location); +} + void PlatformDisplayDefault::UpdateTextInputState( const ui::TextInputState& state) { ui::PlatformImeController* ime = platform_window_->GetPlatformImeController();
diff --git a/services/ui/ws/platform_display_default.h b/services/ui/ws/platform_display_default.h index 3e28a60f..5f942b1 100644 --- a/services/ui/ws/platform_display_default.h +++ b/services/ui/ws/platform_display_default.h
@@ -44,6 +44,7 @@ void SetCapture() override; void ReleaseCapture() override; void SetCursor(const ui::CursorData& cursor) override; + void MoveCursorTo(const gfx::Point& window_pixel_location) override; void UpdateTextInputState(const ui::TextInputState& state) override; void SetImeVisibility(bool visible) override; void UpdateViewportMetrics(const display::ViewportMetrics& metrics) override;
diff --git a/services/ui/ws/test_utils.cc b/services/ui/ws/test_utils.cc index 73d969b..3f903fb10 100644 --- a/services/ui/ws/test_utils.cc +++ b/services/ui/ws/test_utils.cc
@@ -46,6 +46,7 @@ void SetCursor(const ui::CursorData& cursor) override { *cursor_storage_ = cursor; } + void MoveCursorTo(const gfx::Point& window_pixel_location) override {} void UpdateTextInputState(const ui::TextInputState& state) override {} void SetImeVisibility(bool visible) override {} void UpdateViewportMetrics(const display::ViewportMetrics& metrics) override {
diff --git a/services/ui/ws/window_manager_state.cc b/services/ui/ws/window_manager_state.cc index a36a9b1..eec94676 100644 --- a/services/ui/ws/window_manager_state.cc +++ b/services/ui/ws/window_manager_state.cc
@@ -192,6 +192,20 @@ event_dispatcher_.ReleaseCaptureBlockedByAnyModalWindow(); } +void WindowManagerState::SetCursorLocation(const gfx::Point& display_pixels, + int64_t display_id) { + Display* display = display_manager()->GetDisplayById(display_id); + if (!display) { + NOTIMPLEMENTED() << "Window manager sent invalid display_id!"; + return; + } + + event_dispatcher()->SetMousePointerDisplayLocation(display_pixels, + display_id); + UpdateNativeCursorFromDispatcher(); + display->platform_display()->MoveCursorTo(display_pixels); +} + void WindowManagerState::SetDragDropSourceWindow( DragSource* drag_source, ServerWindow* window,
diff --git a/services/ui/ws/window_manager_state.h b/services/ui/ws/window_manager_state.h index 68e808b..818c179 100644 --- a/services/ui/ws/window_manager_state.h +++ b/services/ui/ws/window_manager_state.h
@@ -68,6 +68,9 @@ void ReleaseCaptureBlockedByModalWindow(const ServerWindow* modal_window); void ReleaseCaptureBlockedByAnyModalWindow(); + // Sets the location of the cursor to a location on display |display_id|. + void SetCursorLocation(const gfx::Point& display_pixels, int64_t display_id); + void SetDragDropSourceWindow( DragSource* drag_source, ServerWindow* window,
diff --git a/services/ui/ws/window_tree.cc b/services/ui/ws/window_tree.cc index f6b0756..5b7166a 100644 --- a/services/ui/ws/window_tree.cc +++ b/services/ui/ws/window_tree.cc
@@ -2367,6 +2367,12 @@ window_manager_state_->cursor_state().SetGlobalOverrideCursor(cursor); } +void WindowTree::WmMoveCursorToDisplayLocation(const gfx::Point& display_pixels, + int64_t display_id) { + DCHECK(window_manager_state_); + window_manager_state_->SetCursorLocation(display_pixels, display_id); +} + void WindowTree::OnWmCreatedTopLevelWindow(uint32_t change_id, Id transport_window_id) { ServerWindow* window =
diff --git a/services/ui/ws/window_tree.h b/services/ui/ws/window_tree.h index 42b596c7..3bbcd09b 100644 --- a/services/ui/ws/window_tree.h +++ b/services/ui/ws/window_tree.h
@@ -539,6 +539,8 @@ void WmSetCursorVisible(bool visible) override; void WmSetGlobalOverrideCursor( base::Optional<ui::CursorData> cursor) override; + void WmMoveCursorToDisplayLocation(const gfx::Point& display_pixels, + int64_t display_id) override; void OnWmCreatedTopLevelWindow(uint32_t change_id, Id transport_window_id) override; void OnAcceleratorAck(
diff --git a/services/ui/ws/window_tree_unittest.cc b/services/ui/ws/window_tree_unittest.cc index 83b9de0..8350e1f 100644 --- a/services/ui/ws/window_tree_unittest.cc +++ b/services/ui/ws/window_tree_unittest.cc
@@ -1493,6 +1493,45 @@ EXPECT_TRUE(wm_internal.on_set_modal_type_called()); } +TEST_F(WindowTreeTest, TestWindowManagerSettingCursorLocation) { + const ClientWindowId embed_window_id = BuildClientWindowId(wm_tree(), 1); + EXPECT_TRUE( + wm_tree()->NewWindow(embed_window_id, ServerWindow::Properties())); + ServerWindow* embed_window = wm_tree()->GetWindowByClientId(embed_window_id); + ASSERT_TRUE(embed_window); + EXPECT_TRUE(wm_tree()->SetWindowVisibility(embed_window_id, true)); + ASSERT_TRUE(FirstRoot(wm_tree())); + const ClientWindowId wm_root_id = FirstRootId(wm_tree()); + EXPECT_TRUE(wm_tree()->AddWindow(wm_root_id, embed_window_id)); + ServerWindow* wm_root = FirstRoot(wm_tree()); + ASSERT_TRUE(wm_root); + wm_root->SetBounds(gfx::Rect(0, 0, 100, 100)); + // This tests expects |wm_root| to be a possible target. + wm_root->set_event_targeting_policy( + mojom::EventTargetingPolicy::TARGET_AND_DESCENDANTS); + display()->root_window()->SetBounds(gfx::Rect(0, 0, 100, 100)); + mojom::WindowTreeClientPtr client; + wm_client()->Bind(mojo::MakeRequest(&client)); + const uint32_t embed_flags = 0; + wm_tree()->Embed(embed_window_id, std::move(client), embed_flags); + WindowTree* tree1 = window_server()->GetTreeWithRoot(embed_window); + ASSERT_TRUE(tree1 != nullptr); + ASSERT_NE(tree1, wm_tree()); + + embed_window->SetBounds(gfx::Rect(20, 20, 20, 20)); + embed_window->SetCursor(ui::CursorData(ui::CursorType::kIBeam)); + + // Because the cursor is still at the origin, changing the cursor shouldn't + // have switched to ibeam. + EXPECT_EQ(ui::CursorType::kPointer, cursor_type()); + + // Have the window manager mvoe the cursor within the embed window. + static_cast<mojom::WindowManagerClient*>(wm_tree()) + ->WmMoveCursorToDisplayLocation(gfx::Point(21, 21), -1); + + EXPECT_EQ(ui::CursorType::kIBeam, cursor_type()); +} + using WindowTreeShutdownTest = testing::Test; // Makes sure WindowTreeClient doesn't get any messages during shutdown.
diff --git a/testing/buildbot/chromium.chromiumos.json b/testing/buildbot/chromium.chromiumos.json index d7bd592..589224b 100644 --- a/testing/buildbot/chromium.chromiumos.json +++ b/testing/buildbot/chromium.chromiumos.json
@@ -47,7 +47,7 @@ "--mash", "--test-launcher-filter-file=../../testing/buildbot/filters/ash_unittests_mash.filter" ], - "name": "ash_unittests --mash", + "name": "ash_unittests-mash", "override_isolate_target": "ash_unittests", "swarming": { "can_use_on_swarming_builders": true @@ -59,7 +59,7 @@ "--mus", "--test-launcher-filter-file=../../testing/buildbot/filters/ash_unittests_mus.filter" ], - "name": "ash_unittests --mus", + "name": "ash_unittests-mus", "override_isolate_target": "ash_unittests", "swarming": { "can_use_on_swarming_builders": true
diff --git a/testing/buildbot/chromium.fyi.json b/testing/buildbot/chromium.fyi.json index 47ce9b82..e8d493e 100644 --- a/testing/buildbot/chromium.fyi.json +++ b/testing/buildbot/chromium.fyi.json
@@ -11655,7 +11655,7 @@ "--mash", "--test-launcher-filter-file=../../testing/buildbot/filters/ash_unittests_mash.filter" ], - "name": "ash_unittests --mash", + "name": "ash_unittests-mash", "override_isolate_target": "ash_unittests", "swarming": { "can_use_on_swarming_builders": true @@ -11667,7 +11667,7 @@ "--mus", "--test-launcher-filter-file=../../testing/buildbot/filters/ash_unittests_mus.filter" ], - "name": "ash_unittests --mus", + "name": "ash_unittests-mus", "override_isolate_target": "ash_unittests", "swarming": { "can_use_on_swarming_builders": true
diff --git a/testing/variations/fieldtrial_testing_config.json b/testing/variations/fieldtrial_testing_config.json index cebbb78..5be5f25 100644 --- a/testing/variations/fieldtrial_testing_config.json +++ b/testing/variations/fieldtrial_testing_config.json
@@ -475,6 +475,22 @@ ] } ], + "ClientSidePreviews": [ + { + "platforms": [ + "android" + ], + "experiments": [ + { + "name": "Enabled_2G_2", + "params": { + "max_allowed_effective_connection_type": "2G", + "show_offline_pages": "true" + } + } + ] + } + ], "ContextualSearch": [ { "platforms": [
diff --git a/third_party/WebKit/LayoutTests/MSANExpectations b/third_party/WebKit/LayoutTests/MSANExpectations index 2c2d910..b85495d 100644 --- a/third_party/WebKit/LayoutTests/MSANExpectations +++ b/third_party/WebKit/LayoutTests/MSANExpectations
@@ -52,3 +52,12 @@ # These tests use OpenGl, which crashes on MSAN builds due to missing instrumentation crbug.com/555703 [ Linux ] virtual/media-gpu-accelerated [ Skip ] + +# These tests are just a tad bit too slow on MSAN bots, give them more time. +crbug.com/729136 [ Linux ] external/wpt/encoding/textdecoder-fatal-single-byte.html [ Slow ] +crbug.com/729136 [ Linux ] fast/css/css-selector-deeply-nested.html [ Slow ] +crbug.com/729136 [ Linux ] http/tests/inspector/forced-layout-in-microtask.html [ Slow ] +crbug.com/729136 [ Linux ] http/tests/inspector/tracing/timeline-xhr-response-type-blob-event.html [ Slow ] +crbug.com/729136 [ Linux ] inspector/components/file-path-scoring.html [ Slow ] +crbug.com/729136 [ Linux ] inspector/elements/styles-4/styles-should-not-force-sync-style-recalc.html [ Slow ] +crbug.com/729136 [ Linux ] webaudio/mixing.html [ Slow ]
diff --git a/third_party/WebKit/LayoutTests/TestExpectations b/third_party/WebKit/LayoutTests/TestExpectations index 3b09686d..3333bad1 100644 --- a/third_party/WebKit/LayoutTests/TestExpectations +++ b/third_party/WebKit/LayoutTests/TestExpectations
@@ -2984,7 +2984,6 @@ crbug.com/725455 [ Linux ] nfc/nfc-block-iframe.html [ Failure Pass Timeout ] crbug.com/725455 [ Linux ] nfc/push.html [ Failure Pass Timeout ] crbug.com/725455 [ Linux ] nfc/watch.html [ Failure Pass Timeout ] -crbug.com/725585 payments/payment-request-interface.html [ Failure Pass ] # Sheriff failures 2017-05-29 crbug.com/727014 [ Linux ] external/wpt/IndexedDB/large-nested-cloning.html [ Pass Timeout ] @@ -2996,3 +2995,5 @@ crbug.com/727505 [ Linux Mac Win ] virtual/threaded/fast/compositorworker/basic-plumbing-main-to-worker.html [ Pass Failure Timeout Crash ] crbug.com/727505 [ Linux Mac Win ] virtual/threaded/fast/compositorworker/basic-plumbing-worker-to-main.html [ Pass Failure Timeout Crash ] crbug.com/727505 [ Linux Mac Win ] virtual/threaded/fast/compositorworker/request-animation-frame.html [ Pass Failure Timeout Crash ] + +crbug.com/729075 [ Mac10.11 Retina ] css3/blending/background-blend-mode-gif-color-2.html [ Failure Pass ]
diff --git a/third_party/WebKit/LayoutTests/css3/fonts/resources/style-matching-test.js b/third_party/WebKit/LayoutTests/css3/fonts/resources/style-matching-test.js index c5f964ba..58a883fd 100644 --- a/third_party/WebKit/LayoutTests/css3/fonts/resources/style-matching-test.js +++ b/third_party/WebKit/LayoutTests/css3/fonts/resources/style-matching-test.js
@@ -183,22 +183,14 @@ } } - function platformFontsForElementWithSelector(selector) + async function platformFontsForElementWithSelector(selector) { - InspectorTest.requestNodeId(documentNodeId, selector, onNodeId); - - function onNodeId(nodeId) - { - InspectorTest.sendCommandOrDie("CSS.getPlatformFontsForNode", - { nodeId: nodeId }, - onGotComputedFonts); - } - - function onGotComputedFonts(response) - { - logResults(response); - nextTest(); - } + var nodeId = await InspectorTest.requestNodeId(documentNodeId, selector); + await InspectorTest.sendCommandOrDie("CSS.enable", {}); + var response = await InspectorTest.sendCommandOrDie("CSS.getPlatformFontsForNode", + { nodeId: nodeId }); + logResults(response); + nextTest(); } function logResults(response)
diff --git a/third_party/WebKit/LayoutTests/external/wpt/fetch/api/headers/header-values-normalize-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/fetch/api/headers/header-values-normalize-expected.txt deleted file mode 100644 index 9f0bc93..0000000 --- a/third_party/WebKit/LayoutTests/external/wpt/fetch/api/headers/header-values-normalize-expected.txt +++ /dev/null
@@ -1,67 +0,0 @@ -This is a testharness.js-based test. -Found 62 tests; 58 PASS, 4 FAIL, 0 TIMEOUT, 0 NOTRUN. -PASS XMLHttpRequest with value %00 -PASS fetch() with value %00 -PASS XMLHttpRequest with value %01 -PASS fetch() with value %01 -PASS XMLHttpRequest with value %02 -PASS fetch() with value %02 -PASS XMLHttpRequest with value %03 -PASS fetch() with value %03 -PASS XMLHttpRequest with value %04 -PASS fetch() with value %04 -PASS XMLHttpRequest with value %05 -PASS fetch() with value %05 -PASS XMLHttpRequest with value %06 -PASS fetch() with value %06 -PASS XMLHttpRequest with value %07 -PASS fetch() with value %07 -PASS XMLHttpRequest with value %08 -PASS fetch() with value %08 -PASS XMLHttpRequest with value %09 -PASS fetch() with value %09 -FAIL XMLHttpRequest with value %0A Failed to execute 'setRequestHeader' on 'XMLHttpRequest': ' -' is not a valid HTTP header field value. -FAIL fetch() with value %0A promise_test: Unhandled rejection with value: object "TypeError: Failed to execute 'fetch' on 'Window': Invalid value" -FAIL XMLHttpRequest with value %0D Failed to execute 'setRequestHeader' on 'XMLHttpRequest': '\r' is not a valid HTTP header field value. -FAIL fetch() with value %0D promise_test: Unhandled rejection with value: object "TypeError: Failed to execute 'fetch' on 'Window': Invalid value" -PASS XMLHttpRequest with value %0E -PASS fetch() with value %0E -PASS XMLHttpRequest with value %0F -PASS fetch() with value %0F -PASS XMLHttpRequest with value %10 -PASS fetch() with value %10 -PASS XMLHttpRequest with value %11 -PASS fetch() with value %11 -PASS XMLHttpRequest with value %12 -PASS fetch() with value %12 -PASS XMLHttpRequest with value %13 -PASS fetch() with value %13 -PASS XMLHttpRequest with value %14 -PASS fetch() with value %14 -PASS XMLHttpRequest with value %15 -PASS fetch() with value %15 -PASS XMLHttpRequest with value %16 -PASS fetch() with value %16 -PASS XMLHttpRequest with value %17 -PASS fetch() with value %17 -PASS XMLHttpRequest with value %18 -PASS fetch() with value %18 -PASS XMLHttpRequest with value %19 -PASS fetch() with value %19 -PASS XMLHttpRequest with value %1A -PASS fetch() with value %1A -PASS XMLHttpRequest with value %1B -PASS fetch() with value %1B -PASS XMLHttpRequest with value %1C -PASS fetch() with value %1C -PASS XMLHttpRequest with value %1D -PASS fetch() with value %1D -PASS XMLHttpRequest with value %1E -PASS fetch() with value %1E -PASS XMLHttpRequest with value %1F -PASS fetch() with value %1F -PASS XMLHttpRequest with value %20 -PASS fetch() with value %20 -Harness: the test ran to completion. -
diff --git a/third_party/WebKit/LayoutTests/external/wpt/fetch/api/headers/headers-normalize-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/fetch/api/headers/headers-normalize-expected.txt deleted file mode 100644 index 5e8dd61..0000000 --- a/third_party/WebKit/LayoutTests/external/wpt/fetch/api/headers/headers-normalize-expected.txt +++ /dev/null
@@ -1,6 +0,0 @@ -This is a testharness.js-based test. -FAIL Create headers with not normalized values Failed to construct 'Headers': Invalid value -FAIL Check append method with not normalized values assert_equals: name: name1 has value: space expected "space" but got " space " -FAIL Check set method with not normalized values assert_equals: name: name1 has value: space expected "space" but got " space " -Harness: the test ran to completion. -
diff --git a/third_party/WebKit/LayoutTests/http/tests/fetch/resources/fetch-test-helpers.js b/third_party/WebKit/LayoutTests/http/tests/fetch/resources/fetch-test-helpers.js index a25c558..a1dc234 100644 --- a/third_party/WebKit/LayoutTests/http/tests/fetch/resources/fetch-test-helpers.js +++ b/third_party/WebKit/LayoutTests/http/tests/fetch/resources/fetch-test-helpers.js
@@ -76,11 +76,18 @@ // A header name must match token in RFC 2616. // Fetch API Spec: https://fetch.spec.whatwg.org/#concept-header-name var INVALID_HEADER_NAMES = INVALID_TOKENS; + +// A header value is a byte sequence that matches the following conditions: +// * Has no leading or trailing HTTP whitespace bytes (0x09, 0x0A, 0x0D and +// 0x20). +// * Contains no 0x00, 0x0A or 0x0D bytes. +// Note that header values are normalized (ie. stripped of leading and trailing +// HTTP whitespace bytes) when a new header/value pair is appended or set. var INVALID_HEADER_VALUES = [ 'test \r data', 'test \n data', 'test \0 data', 'test\r\n data', - 'test\r', 'test\n', 'test\r\n', 'test\0', - '\0'.repeat(100000), '\r\n'.repeat(50000), 'x'.repeat(100000) + '\0']; + 'test\0', + '\0'.repeat(100000), 'x'.repeat(100000) + '\0']; var FORBIDDEN_HEADER_NAMES = ['Accept-Charset', 'Accept-Encoding', 'Access-Control-Request-Headers',
diff --git a/third_party/WebKit/LayoutTests/http/tests/inspector-protocol/dom-protocol-test.js b/third_party/WebKit/LayoutTests/http/tests/inspector-protocol/dom-protocol-test.js index e8ee26a..1be873c 100644 --- a/third_party/WebKit/LayoutTests/http/tests/inspector-protocol/dom-protocol-test.js +++ b/third_party/WebKit/LayoutTests/http/tests/inspector-protocol/dom-protocol-test.js
@@ -3,48 +3,44 @@ InspectorTest.trackGetChildNodesEvents = function(nodeInfo, callback) { - InspectorTest.eventHandler["DOM.setChildNodes"] = setChildNodes; + InspectorTest.eventHandler["DOM.setChildNodes"] = setChildNodes; - function setChildNodes(message) - { - var nodes = message.params.nodes; - for (var i = 0; i < nodes.length; ++i) - InspectorTest.addNode(nodeInfo, nodes[i]); - if (callback) - callback(); - } + function setChildNodes(message) + { + var nodes = message.params.nodes; + for (var i = 0; i < nodes.length; ++i) + InspectorTest.addNode(nodeInfo, nodes[i]); + if (callback) + callback(); + } } InspectorTest.addNode = function(nodeInfo, node) { - nodeInfo[node.nodeId] = node; - delete node.nodeId; - var children = node.children || []; - for (var i = 0; i < children.length; ++i) - InspectorTest.addNode(nodeInfo, children[i]); - var shadowRoots = node.shadowRoots || []; - for (var i = 0; i < shadowRoots.length; ++i) - InspectorTest.addNode(nodeInfo, shadowRoots[i]); + nodeInfo[node.nodeId] = node; + delete node.nodeId; + var children = node.children || []; + for (var i = 0; i < children.length; ++i) + InspectorTest.addNode(nodeInfo, children[i]); + var shadowRoots = node.shadowRoots || []; + for (var i = 0; i < shadowRoots.length; ++i) + InspectorTest.addNode(nodeInfo, shadowRoots[i]); } -InspectorTest.requestDocumentNodeId = function(callback) +InspectorTest.requestDocumentNodeId = async function(callback) { - InspectorTest.sendCommandOrDie("DOM.getDocument", {}, onGotDocument); - - function onGotDocument(result) - { - callback(result.root.nodeId); - } + var result = await InspectorTest.sendCommandOrDie("DOM.getDocument", {}); + if (callback) + callback(result.root.nodeId); + return result.root.nodeId; }; -InspectorTest.requestNodeId = function(documentNodeId, selector, callback) +InspectorTest.requestNodeId = async function(documentNodeId, selector, callback) { - InspectorTest.sendCommandOrDie("DOM.querySelector", { "nodeId": documentNodeId , "selector": selector }, onGotNode); - - function onGotNode(result) - { - callback(result.nodeId); - } + var result = await InspectorTest.sendCommandOrDie("DOM.querySelector", { "nodeId": documentNodeId , "selector": selector }); + if (callback) + callback(result.nodeId); + return result.nodeId; }; }
diff --git a/third_party/WebKit/LayoutTests/http/tests/inspector-protocol/resources/protocol-test.html b/third_party/WebKit/LayoutTests/http/tests/inspector-protocol/resources/protocol-test.html index 510b441..1f3ce3c 100644 --- a/third_party/WebKit/LayoutTests/http/tests/inspector-protocol/resources/protocol-test.html +++ b/third_party/WebKit/LayoutTests/http/tests/inspector-protocol/resources/protocol-test.html
@@ -62,6 +62,9 @@ InspectorTest.sendCommandOrDie = function(command, properties, callback) { + var fulfill; + var result = new Promise(f => fulfill = f); + InspectorTest.sendCommand(command, properties || {}, commandCallback); function commandCallback(msg) { @@ -72,7 +75,9 @@ } if (callback) callback(msg.result); + fulfill(msg.result); } + return result; } InspectorTest.sendCommandPromise = function(method, params)
diff --git a/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/inject-header-expected.txt b/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/inject-header-expected.txt index 6e131698..391ad3c 100644 --- a/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/inject-header-expected.txt +++ b/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/inject-header-expected.txt
@@ -1,10 +1,12 @@ CONSOLE WARNING: line 10: Synchronous XMLHttpRequest on the main thread is deprecated because of its detrimental effects to the end user's experience. For more help, check https://xhr.spec.whatwg.org/. -Test that setRequestHeader properly checks for line feeds in header values. +Test that setRequestHeader properly checks for invalid characters in header values. -%0AEvil%3A%20on -> SUCCESS, setRequestHeader() raised an exception SyntaxError: Failed to execute 'setRequestHeader' on 'XMLHttpRequest': ' Evil: on' is not a valid HTTP header field value. +%0AE%0Avil%3A%20on -> SUCCESS, setRequestHeader() raised an exception SyntaxError: Failed to execute 'setRequestHeader' on 'XMLHttpRequest': 'E vil: on' is not a valid HTTP header field value. -%0DEvil%3A%20on -> SUCCESS, setRequestHeader() raised an exception SyntaxError: Failed to execute 'setRequestHeader' on 'XMLHttpRequest': ' Evil: on' is not a valid HTTP header field value. +%0DE%0Dvil%3A%20on -> SUCCESS, setRequestHeader() raised an exception SyntaxError: Failed to execute 'setRequestHeader' on 'XMLHttpRequest': 'E vil: on' is not a valid HTTP header field value. -%0D%0AEvil%3A%20on -> SUCCESS, setRequestHeader() raised an exception SyntaxError: Failed to execute 'setRequestHeader' on 'XMLHttpRequest': ' Evil: on' is not a valid HTTP header field value. +%0D%0AEvil%0D%0A%3A%20on -> SUCCESS, setRequestHeader() raised an exception SyntaxError: Failed to execute 'setRequestHeader' on 'XMLHttpRequest': 'Evil : on' is not a valid HTTP header field value. -%0A%0DEvil%3A%20on -> SUCCESS, setRequestHeader() raised an exception SyntaxError: Failed to execute 'setRequestHeader' on 'XMLHttpRequest': ' Evil: on' is not a valid HTTP header field value. +%0A%0DEvil%0D%0A%3A%20on -> SUCCESS, setRequestHeader() raised an exception SyntaxError: Failed to execute 'setRequestHeader' on 'XMLHttpRequest': 'Evil : on' is not a valid HTTP header field value. + +%0D%0AEvil%3A%20o%00n%0A%0D -> SUCCESS, setRequestHeader() raised an exception SyntaxError: Failed to execute 'setRequestHeader' on 'XMLHttpRequest': 'Evil: on' is not a valid HTTP header field value.
diff --git a/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/inject-header.html b/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/inject-header.html index a3e3a6aef..f1fe5234 100644 --- a/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/inject-header.html +++ b/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/inject-header.html
@@ -1,6 +1,6 @@ <html> <body> -<p>Test that setRequestHeader properly checks for line feeds in header values.</p> +<p>Test that setRequestHeader properly checks for invalid characters in header values.</p> <script> if (window.testRunner) testRunner.dumpAsText(); @@ -28,10 +28,11 @@ } } -test("\nEvil: on"); -test("\rEvil: on"); -test("\r\nEvil: on"); -test("\n\rEvil: on"); +test("\nE\nvil: on"); +test("\rE\rvil: on"); +test("\r\nEvil\r\n: on"); +test("\n\rEvil\r\n: on"); +test("\r\nEvil: o\0n\n\r"); </script> </body> </html>
diff --git a/third_party/WebKit/LayoutTests/inspector-protocol/css/css-get-platform-fonts.html b/third_party/WebKit/LayoutTests/inspector-protocol/css/css-get-platform-fonts.html index 616c5941..bc8d880 100644 --- a/third_party/WebKit/LayoutTests/inspector-protocol/css/css-get-platform-fonts.html +++ b/third_party/WebKit/LayoutTests/inspector-protocol/css/css-get-platform-fonts.html
@@ -28,20 +28,13 @@ } - function platformFontsForElementWithSelector(selector, callback) + async function platformFontsForElementWithSelector(selector, callback) { - InspectorTest.requestNodeId(documentNodeId, selector, onNodeId); - - function onNodeId(nodeId) - { - InspectorTest.sendCommandOrDie("CSS.getPlatformFontsForNode", { nodeId: nodeId }, onGotComputedFonts); - } - - function onGotComputedFonts(response) - { - dumpComputedFonts(response); - callback(); - } + var nodeId = await InspectorTest.requestNodeId(documentNodeId, selector); + await InspectorTest.sendCommandOrDie("CSS.enable", { }); + var response = await InspectorTest.sendCommandOrDie("CSS.getPlatformFontsForNode", { nodeId: nodeId }); + dumpComputedFonts(response); + callback(); } function dumpComputedFonts(response)
diff --git a/third_party/WebKit/LayoutTests/inspector-protocol/css/css-set-inline-styleSheetText.html b/third_party/WebKit/LayoutTests/inspector-protocol/css/css-set-inline-styleSheetText.html index 44e8920..9667efb 100644 --- a/third_party/WebKit/LayoutTests/inspector-protocol/css/css-set-inline-styleSheetText.html +++ b/third_party/WebKit/LayoutTests/inspector-protocol/css/css-set-inline-styleSheetText.html
@@ -9,47 +9,29 @@ InspectorTest.sendCommand("CSS.enable", {}, cssWasEnabled); - function cssWasEnabled() + async function cssWasEnabled() { - InspectorTest.sendCommandOrDie("DOM.getDocument", {}, onGotDocument); - } - - function onGotDocument(result) - { + var result = await InspectorTest.sendCommandOrDie("DOM.getDocument", {}); var root = result.root; - InspectorTest.sendCommandOrDie("DOM.querySelector", { + var node = await InspectorTest.sendCommandOrDie("DOM.querySelector", { nodeId: root.nodeId, selector: "#inliner" - }, onGotNode); - } + }); - function onGotNode(node) - { - InspectorTest.sendCommandOrDie("CSS.getInlineStylesForNode", { nodeId: node.nodeId }, onGotInlineStyles); - } + await InspectorTest.sendCommandOrDie("CSS.enable", { }); - function onGotInlineStyles(result) - { + result = await InspectorTest.sendCommandOrDie("CSS.getInlineStylesForNode", { nodeId: node.nodeId }); inlineStyleSheetId = result.inlineStyle.styleSheetId; - InspectorTest.sendCommandOrDie("CSS.getStyleSheetText", { styleSheetId: inlineStyleSheetId }, onReceiveStyleSheetText); - } - function onReceiveStyleSheetText(result) - { + result = await InspectorTest.sendCommandOrDie("CSS.getStyleSheetText", { styleSheetId: inlineStyleSheetId }); InspectorTest.log(result.text); - InspectorTest.sendCommandOrDie("CSS.setStyleSheetText", { + + result = await InspectorTest.sendCommandOrDie("CSS.setStyleSheetText", { styleSheetId: inlineStyleSheetId, text: "border: 1px solid black;" - }, onSetStyleSheetBody); - } + }); - function onSetStyleSheetBody(result) - { - InspectorTest.sendCommandOrDie("CSS.getStyleSheetText", { styleSheetId: inlineStyleSheetId }, onCheckStyleSheetBody); - } - - function onCheckStyleSheetBody(result) - { + result = await InspectorTest.sendCommandOrDie("CSS.getStyleSheetText", { styleSheetId: inlineStyleSheetId }); InspectorTest.log(result.text); InspectorTest.completeTest(); }
diff --git a/third_party/WebKit/LayoutTests/inspector-protocol/css/pseudo-element-matching-selectors.html b/third_party/WebKit/LayoutTests/inspector-protocol/css/pseudo-element-matching-selectors.html index 980b0285..b658c98 100644 --- a/third_party/WebKit/LayoutTests/inspector-protocol/css/pseudo-element-matching-selectors.html +++ b/third_party/WebKit/LayoutTests/inspector-protocol/css/pseudo-element-matching-selectors.html
@@ -8,61 +8,37 @@ document.getElementById("style").textContent = "#for-pseudo:before { content: \"BEFORE\" }"; } -function test() +async function test() { var nodeInfo = {}; var childrenCallback; InspectorTest.eventHandler["DOM.setChildNodes"] = setChildNodes; - getDocument(); + await InspectorTest.sendCommandOrDie("DOM.enable", {}); + await InspectorTest.sendCommandOrDie("CSS.enable", {}); - function getDocument() - { - step({ - name: "Get the Document", - command: "DOM.getDocument", - parameters: {}, - callback: getImmediateChildren - }); - }; + InspectorTest.log("\n=== Get the Document ===\n"); + var result = await InspectorTest.sendCommandOrDie("DOM.getDocument", {}); + var bodyId = result.root.children[0].children[1].nodeId; - function getImmediateChildren(result) - { - var bodyId = result.root.children[0].children[1].nodeId; - childrenCallback = onChildrenRequested; - step({ - name: "Get immediate children of the body", - command: "DOM.requestChildNodes", - parameters: {"nodeId": bodyId} - }); - }; + InspectorTest.log("\n=== Get immediate children of the body ===\n"); + result = await InspectorTest.sendCommandOrDie("DOM.requestChildNodes", {"nodeId": bodyId}); + var node = findNodeById("for-pseudo"); + var beforeNode = node.pseudoElements[0]; - function onChildrenRequested() - { - var node = findNodeById("for-pseudo"); - var beforeNode = node.pseudoElements[0]; - step({ - name: "Request matching styles for #for-pseudo::before", - command: "CSS.getMatchedStylesForNode", - parameters: {nodeId: beforeNode.nodeId}, - callback: stylesReceived - }); - } - - function stylesReceived(result) - { - var matchedRules = result.matchedCSSRules; - for (var i = 0; i < matchedRules.length; ++i) { - var match = matchedRules[i]; - if (match.rule.selectorList.text === "#for-pseudo::before") { - InspectorTest.log("#for-pseudo::before matching the :before element: " + (match.matchingSelectors[0] === 0)); - InspectorTest.completeTest(); - return; - } + InspectorTest.log("\n=== Request matching styles for #for-pseudo::before ===\n"); + result = await InspectorTest.sendCommandOrDie("CSS.getMatchedStylesForNode", {nodeId: beforeNode.nodeId}); + var matchedRules = result.matchedCSSRules; + for (var i = 0; i < matchedRules.length; ++i) { + var match = matchedRules[i]; + if (match.rule.selectorList.text === "#for-pseudo::before") { + InspectorTest.log("#for-pseudo::before matching the :before element: " + (match.matchingSelectors[0] === 0)); + InspectorTest.completeTest(); + return; } - InspectorTest.log("#for-pseudo::before rule not received"); - InspectorTest.completeTest(); } + InspectorTest.log("#for-pseudo::before rule not received"); + InspectorTest.completeTest(); function setChildNodes(message) { @@ -75,18 +51,6 @@ callback(); } - function step(test) - { - InspectorTest.log("\n=== " + test.name + " ===\n"); - InspectorTest.sendCommand(test.command, test.parameters, function(messageObject) { - if (messageObject.hasOwnProperty("error")) - InspectorTest.log("Backend error: " + messageObject.error.message + " (" + messageObject.error.code + ")\n"); - - if (test.callback) - test.callback(messageObject.result); - }); - } - function findNodeById(id) { for (var nodeId in nodeInfo) { @@ -105,18 +69,10 @@ return null; } - function addNodesRecursive(root) - { - addNode(root); - if (!root.children) - return; - for (var i = 0; i < root.children.length; ++i) - addNodesRecursive(root.children[i]); - } - - function addNode(node) + function addNodesRecursive(node) { nodeInfo[node.nodeId] = node; + (node.children || []).forEach(addNodesRecursive); } }
diff --git a/third_party/WebKit/LayoutTests/inspector-protocol/layout-fonts/resources/layout-font-test.js b/third_party/WebKit/LayoutTests/inspector-protocol/layout-fonts/resources/layout-font-test.js index f3efc86..996ca6b 100644 --- a/third_party/WebKit/LayoutTests/inspector-protocol/layout-fonts/resources/layout-font-test.js +++ b/third_party/WebKit/LayoutTests/inspector-protocol/layout-fonts/resources/layout-font-test.js
@@ -57,20 +57,13 @@ } - function platformFontsForElementWithSelector(selector) + async function platformFontsForElementWithSelector(selector) { - InspectorTest.requestNodeId(documentNodeId, selector, onNodeId); - - function onNodeId(nodeId) - { - InspectorTest.sendCommandOrDie("CSS.getPlatformFontsForNode", { nodeId: nodeId }, onGotComputedFonts); - } - - function onGotComputedFonts(response) - { - collectResults(response); - testNextPageElement(); - } + var nodeId = await InspectorTest.requestNodeId(documentNodeId, selector); + await InspectorTest.sendCommandOrDie("CSS.enable", {}); + var response = await InspectorTest.sendCommandOrDie("CSS.getPlatformFontsForNode", { nodeId: nodeId }); + collectResults(response); + testNextPageElement(); } function collectResults(response)
diff --git a/third_party/WebKit/LayoutTests/inspector/sources/debugger-breakpoints/breakpoint-manager.js b/third_party/WebKit/LayoutTests/inspector/sources/debugger-breakpoints/breakpoint-manager.js index c33bcd4..704c107 100644 --- a/third_party/WebKit/LayoutTests/inspector/sources/debugger-breakpoints/breakpoint-manager.js +++ b/third_party/WebKit/LayoutTests/inspector/sources/debugger-breakpoints/breakpoint-manager.js
@@ -126,6 +126,12 @@ return new SDK.DebuggerModel.Location(this, script.scriptId, line, column); } + createRawLocationByURL(url, line, column) + { + var script = this._scriptForURL(url); + return new SDK.DebuggerModel.Location(this, script.scriptId, line, column); + } + setBreakpointByURL(url, lineNumber, columnNumber, condition, callback) { InspectorTest.addResult(" debuggerModel.setBreakpoint(" + [url, lineNumber, condition].join(":") + ")");
diff --git a/third_party/WebKit/LayoutTests/payments/payment-request-interface-expected.txt b/third_party/WebKit/LayoutTests/payments/payment-request-interface-expected.txt deleted file mode 100644 index 12e2625..0000000 --- a/third_party/WebKit/LayoutTests/payments/payment-request-interface-expected.txt +++ /dev/null
@@ -1,153 +0,0 @@ -CONSOLE WARNING: line 160: Duplicate shipping option identifier 'express' is treated as an invalid address indicator. -CONSOLE WARNING: line 248: Cannot yet distinguish credit, debit, and prepaid cards. -CONSOLE WARNING: line 252: Cannot yet distinguish credit, debit, and prepaid cards. -This is a testharness.js-based test. -PASS Creating a PaymentRequest with empty parameters should not throw or crash. -PASS Creating a PaymentRequest with extra parameters should not throw or crash. -PASS Creating a PaymentRequest with omitted optional parameters should not throw or crash. -PASS Creating a PaymentRequest with undefined optional parameters should not throw or crash. -PASS Creating a PaymentRequest with null optional parameters should not throw or crash. -PASS PaymentRequest should have readonly shippingAddress and shippingOption properties. -PASS PaymentRequest should have onShippingAddressChange and onShippingOptionChange events. -PASS PaymentRequest should have methods abort() and show(). -PASS PaymentRequest.abort() and PaymentRequest.show() should take no parameters. -PASS Valid data causes no errors. -PASS Shipping option identifier should be null if shipping request is omitted. -PASS Shipping option identifier should be null if shipping is explicitly not requested. -PASS Shipping option identifier should be null if no shipping options are provided. -PASS Shipping option identifier should be null if the single provided option is not selected. -PASS Shipping option identifier should default to the single provided option if it is selected. -PASS Shipping option identifier should be null if multiple unselected shipping options are provided. -PASS Shipping option identifier should default to the selected shipping option. -PASS Shipping option identifier should default to the last selected shipping option, if multiple are selected. -PASS No shipping option selected for duplicate shipping option identifiers. -PASS Shipping type should be null if shipping is explicitly not requested. -PASS Shipping type should be 'shipping' by default if shipping type isn't specified. -PASS Shipping type should be null if shipping type is specified but requestShipping is false. -PASS Shipping type should be 'shipping' if shipping type is specified as 'shipping'. -PASS Shipping type should be 'delivery' if shipping type is specified as 'delivery'. -PASS Shipping type should be 'pickup' if shipping type is specified as 'pickup'. -PASS Shipping type should be 'shipping' if shipping type is specified as undefined. -PASS Undefined display items should not throw. -PASS Empty display items should not throw. -PASS Non-negative total value should not throw. -PASS Negative line item value should not throw. -PASS Undefined modifiers should not throw. -PASS Non-negative total value in PaymentDetailsModifier should not throw. -PASS Duplicate supported payment method identifiers should not throw. -PASS Duplicate supported payment method identifiers in separate methodData objects should not throw. -PASS Duplicate supported payment method identifiers in modifiers should not throw. -PASS Duplicate supported payment method identifiers in separate methoData objects of modifiers should not throw. -PASS Android Pay parameters for test environment with gateway token should not throw. -PASS Android Pay parameters for produciton environment with network token should not throw. -PASS Basic card parameters should not throw. -PASS Empty basic card parameters should not throw. -PASS Invalid basic card parameters should not throw when method name is not "basic-card". -PASS Invalid basic card parameters should not throw even when method name is "basic-card". -PASS Android Pay parameters for network token without environment key should not throw. -PASS Invalid Android Pay parameters should not throw when method name is not "https://android.com/pay". -PASS Invalid Android Pay parameters should not throw even when method name is "https://android.com/pay". -PASS Array value for payment method specific data parameter should not throw -FAIL abort() without show() should reject with error Test bug: need to pass exception to assert_throws() -FAIL PaymentRequest constructor should throw for incorrect parameter types. Test bug: need to pass exception to assert_throws() -FAIL PaymentRequest constructor should throw for undefined required parameters. Test bug: need to pass exception to assert_throws() -FAIL PaymentRequest constructor should throw for null required parameter. Test bug: need to pass exception to assert_throws() -PASS Empty list of supported payment method identifiers should throw TypeError. -FAIL Empty supported payment method identifiers should throw TypeError. Test bug: need to pass exception to assert_throws() -FAIL Absence of total should throw TypeError. Test bug: need to pass exception to assert_throws() -FAIL Negative total value should throw a TypeError. Test bug: need to pass exception to assert_throws() -FAIL Negative total value in PaymentDetailsModifier should throw a TypeError. Test bug: need to pass exception to assert_throws() -FAIL Null supportedMethods in modifiers should throw TypeError. Test bug: need to pass exception to assert_throws() -FAIL Undefined supportedMethods in modifiers should throw TypeError. Test bug: need to pass exception to assert_throws() -FAIL Empty supportedMethods in modifiers should throw TypeError. Test bug: need to pass exception to assert_throws() -FAIL Absence of supportedMethods in modifiers should throw TypeError. Test bug: need to pass exception to assert_throws() -FAIL Empty details should throw Test bug: need to pass exception to assert_throws() -PASS Null items should throw -PASS Null shipping options should throw -PASS Undefined PaymentShippingType value for shppingType should throw a TypeError -PASS Null for shppingType should throw a TypeError -PASS Array value for shppingType should throw a TypeError -PASS Object value for shppingType should throw a TypeError -PASS Numeric value for shppingType should throw a TypeError -FAIL String value for payment method specific data parameter should throw Test bug: need to pass exception to assert_throws() -FAIL Numeric value for payment method specific data parameter should throw Test bug: need to pass exception to assert_throws() -FAIL Infinite JSON value for one of the payment method specific data pieces should throw Test bug: need to pass exception to assert_throws() -FAIL Null for payment method specific data parameter should throw Test bug: need to pass exception to assert_throws() -FAIL Empty string for payment method specific data parameter should throw Test bug: need to pass exception to assert_throws() -FAIL Undefined currency code in total should throw Test bug: need to pass exception to assert_throws() -FAIL Invalid amount "-" in total should throw Test bug: need to pass exception to assert_throws() -FAIL Invalid amount "notdigits" in total should throw Test bug: need to pass exception to assert_throws() -FAIL Invalid amount "ALSONOTDIGITS" in total should throw Test bug: need to pass exception to assert_throws() -FAIL Invalid amount "10." in total should throw Test bug: need to pass exception to assert_throws() -FAIL Invalid amount ".99" in total should throw Test bug: need to pass exception to assert_throws() -FAIL Invalid amount "-10." in total should throw Test bug: need to pass exception to assert_throws() -FAIL Invalid amount "-.99" in total should throw Test bug: need to pass exception to assert_throws() -FAIL Invalid amount "10-" in total should throw Test bug: need to pass exception to assert_throws() -FAIL Invalid amount "1-0" in total should throw Test bug: need to pass exception to assert_throws() -FAIL Invalid amount "1.0.0" in total should throw Test bug: need to pass exception to assert_throws() -FAIL Invalid amount "1/3" in total should throw Test bug: need to pass exception to assert_throws() -FAIL Empty amount in total should throw Test bug: need to pass exception to assert_throws() -FAIL Null amount in total should throw Test bug: need to pass exception to assert_throws() -FAIL Undefined amount in total should throw Test bug: need to pass exception to assert_throws() -FAIL Undefined currency code in displayItems.0 should throw Test bug: need to pass exception to assert_throws() -FAIL Invalid amount "-" in displayItems.0 should throw Test bug: need to pass exception to assert_throws() -FAIL Invalid amount "notdigits" in displayItems.0 should throw Test bug: need to pass exception to assert_throws() -FAIL Invalid amount "ALSONOTDIGITS" in displayItems.0 should throw Test bug: need to pass exception to assert_throws() -FAIL Invalid amount "10." in displayItems.0 should throw Test bug: need to pass exception to assert_throws() -FAIL Invalid amount ".99" in displayItems.0 should throw Test bug: need to pass exception to assert_throws() -FAIL Invalid amount "-10." in displayItems.0 should throw Test bug: need to pass exception to assert_throws() -FAIL Invalid amount "-.99" in displayItems.0 should throw Test bug: need to pass exception to assert_throws() -FAIL Invalid amount "10-" in displayItems.0 should throw Test bug: need to pass exception to assert_throws() -FAIL Invalid amount "1-0" in displayItems.0 should throw Test bug: need to pass exception to assert_throws() -FAIL Invalid amount "1.0.0" in displayItems.0 should throw Test bug: need to pass exception to assert_throws() -FAIL Invalid amount "1/3" in displayItems.0 should throw Test bug: need to pass exception to assert_throws() -FAIL Empty amount in displayItems.0 should throw Test bug: need to pass exception to assert_throws() -FAIL Null amount in displayItems.0 should throw Test bug: need to pass exception to assert_throws() -FAIL Undefined amount in displayItems.0 should throw Test bug: need to pass exception to assert_throws() -FAIL Undefined currency code in shippingOptions.0 should throw Test bug: need to pass exception to assert_throws() -FAIL Invalid amount "-" in shippingOptions.0 should throw Test bug: need to pass exception to assert_throws() -FAIL Invalid amount "notdigits" in shippingOptions.0 should throw Test bug: need to pass exception to assert_throws() -FAIL Invalid amount "ALSONOTDIGITS" in shippingOptions.0 should throw Test bug: need to pass exception to assert_throws() -FAIL Invalid amount "10." in shippingOptions.0 should throw Test bug: need to pass exception to assert_throws() -FAIL Invalid amount ".99" in shippingOptions.0 should throw Test bug: need to pass exception to assert_throws() -FAIL Invalid amount "-10." in shippingOptions.0 should throw Test bug: need to pass exception to assert_throws() -FAIL Invalid amount "-.99" in shippingOptions.0 should throw Test bug: need to pass exception to assert_throws() -FAIL Invalid amount "10-" in shippingOptions.0 should throw Test bug: need to pass exception to assert_throws() -FAIL Invalid amount "1-0" in shippingOptions.0 should throw Test bug: need to pass exception to assert_throws() -FAIL Invalid amount "1.0.0" in shippingOptions.0 should throw Test bug: need to pass exception to assert_throws() -FAIL Invalid amount "1/3" in shippingOptions.0 should throw Test bug: need to pass exception to assert_throws() -FAIL Empty amount in shippingOptions.0 should throw Test bug: need to pass exception to assert_throws() -FAIL Null amount in shippingOptions.0 should throw Test bug: need to pass exception to assert_throws() -FAIL Undefined amount in shippingOptions.0 should throw Test bug: need to pass exception to assert_throws() -FAIL Undefined currency code in modifiers.0.total should throw Test bug: need to pass exception to assert_throws() -FAIL Invalid amount "-" in modifiers.0.total should throw Test bug: need to pass exception to assert_throws() -FAIL Invalid amount "notdigits" in modifiers.0.total should throw Test bug: need to pass exception to assert_throws() -FAIL Invalid amount "ALSONOTDIGITS" in modifiers.0.total should throw Test bug: need to pass exception to assert_throws() -FAIL Invalid amount "10." in modifiers.0.total should throw Test bug: need to pass exception to assert_throws() -FAIL Invalid amount ".99" in modifiers.0.total should throw Test bug: need to pass exception to assert_throws() -FAIL Invalid amount "-10." in modifiers.0.total should throw Test bug: need to pass exception to assert_throws() -FAIL Invalid amount "-.99" in modifiers.0.total should throw Test bug: need to pass exception to assert_throws() -FAIL Invalid amount "10-" in modifiers.0.total should throw Test bug: need to pass exception to assert_throws() -FAIL Invalid amount "1-0" in modifiers.0.total should throw Test bug: need to pass exception to assert_throws() -FAIL Invalid amount "1.0.0" in modifiers.0.total should throw Test bug: need to pass exception to assert_throws() -FAIL Invalid amount "1/3" in modifiers.0.total should throw Test bug: need to pass exception to assert_throws() -FAIL Empty amount in modifiers.0.total should throw Test bug: need to pass exception to assert_throws() -FAIL Null amount in modifiers.0.total should throw Test bug: need to pass exception to assert_throws() -FAIL Undefined amount in modifiers.0.total should throw Test bug: need to pass exception to assert_throws() -FAIL Undefined currency code in modifiers.0.additionalDisplayItems.0 should throw Test bug: need to pass exception to assert_throws() -FAIL Invalid amount "-" in modifiers.0.additionalDisplayItems.0 should throw Test bug: need to pass exception to assert_throws() -FAIL Invalid amount "notdigits" in modifiers.0.additionalDisplayItems.0 should throw Test bug: need to pass exception to assert_throws() -FAIL Invalid amount "ALSONOTDIGITS" in modifiers.0.additionalDisplayItems.0 should throw Test bug: need to pass exception to assert_throws() -FAIL Invalid amount "10." in modifiers.0.additionalDisplayItems.0 should throw Test bug: need to pass exception to assert_throws() -FAIL Invalid amount ".99" in modifiers.0.additionalDisplayItems.0 should throw Test bug: need to pass exception to assert_throws() -FAIL Invalid amount "-10." in modifiers.0.additionalDisplayItems.0 should throw Test bug: need to pass exception to assert_throws() -FAIL Invalid amount "-.99" in modifiers.0.additionalDisplayItems.0 should throw Test bug: need to pass exception to assert_throws() -FAIL Invalid amount "10-" in modifiers.0.additionalDisplayItems.0 should throw Test bug: need to pass exception to assert_throws() -FAIL Invalid amount "1-0" in modifiers.0.additionalDisplayItems.0 should throw Test bug: need to pass exception to assert_throws() -FAIL Invalid amount "1.0.0" in modifiers.0.additionalDisplayItems.0 should throw Test bug: need to pass exception to assert_throws() -FAIL Invalid amount "1/3" in modifiers.0.additionalDisplayItems.0 should throw Test bug: need to pass exception to assert_throws() -FAIL Empty amount in modifiers.0.additionalDisplayItems.0 should throw Test bug: need to pass exception to assert_throws() -FAIL Null amount in modifiers.0.additionalDisplayItems.0 should throw Test bug: need to pass exception to assert_throws() -FAIL Undefined amount in modifiers.0.additionalDisplayItems.0 should throw Test bug: need to pass exception to assert_throws() -Harness: the test ran to completion. -
diff --git a/third_party/WebKit/LayoutTests/payments/payment-request-interface.html b/third_party/WebKit/LayoutTests/payments/payment-request-interface.html index 8ebb2c2..b57aa85 100644 --- a/third_party/WebKit/LayoutTests/payments/payment-request-interface.html +++ b/third_party/WebKit/LayoutTests/payments/payment-request-interface.html
@@ -277,47 +277,47 @@ }, 'Array value for payment method specific data parameter should not throw'); promise_test(function(t) { - return promise_rejects(t, null, new PaymentRequest([{'supportedMethods': ['foo']}], buildDetails()).abort()); + return promise_rejects(t, 'InvalidStateError', new PaymentRequest([{'supportedMethods': ['foo']}], buildDetails()).abort()); }, 'abort() without show() should reject with error'); generate_tests(assert_throws, [ - ['PaymentRequest constructor should throw for incorrect parameter types.', null, function() { + ['PaymentRequest constructor should throw for incorrect parameter types.', new TypeError(), function() { new PaymentRequest('', '', '') }], - ['PaymentRequest constructor should throw for undefined required parameters.', null, function() { + ['PaymentRequest constructor should throw for undefined required parameters.', new TypeError(), function() { new PaymentRequest(undefined, undefined) }], - ['PaymentRequest constructor should throw for null required parameter.', null, function() { + ['PaymentRequest constructor should throw for null required parameter.', new TypeError(), function() { new PaymentRequest(null, null) }], ['Empty list of supported payment method identifiers should throw TypeError.', new TypeError(), function() { new PaymentRequest([], buildDetails()) }], - ['Empty supported payment method identifiers should throw TypeError.', null, function() { + ['Empty supported payment method identifiers should throw TypeError.', new TypeError(), function() { new PaymentRequest([{'supportedMethods': []}], buildDetails()) }], - ['Absence of total should throw TypeError.', null, function() { + ['Absence of total should throw TypeError.', new TypeError(), function() { new PaymentRequest([{'supportedMethods': ['foo']}], {'displayItems': [buildItem()]}) }], - ['Negative total value should throw a TypeError.', null, function() { + ['Negative total value should throw a TypeError.', new TypeError(), function() { new PaymentRequest([{'supportedMethods': ['foo']}], buildDetails('total', {'value': '-0.01'})) }], - ['Negative total value in PaymentDetailsModifier should throw a TypeError.', null, function() { + ['Negative total value in PaymentDetailsModifier should throw a TypeError.', new TypeError(), function() { new PaymentRequest([{'supportedMethods': ['foo']}], {'total': buildItem(), 'modifiers': [{'supportedMethods': ['foo'], 'total': buildItem({'value': '-0.01'})}]}) }], - ['Null supportedMethods in modifiers should throw TypeError.', null, function() { + ['Null supportedMethods in modifiers should throw TypeError.', new TypeError(), function() { new PaymentRequest([{'supportedMethods': ['foo']}], {'total': buildItem(), 'modifiers': [{'supportedMethods': null}]}) }], - ['Undefined supportedMethods in modifiers should throw TypeError.', null, function() { + ['Undefined supportedMethods in modifiers should throw TypeError.', new TypeError(), function() { new PaymentRequest([{'supportedMethods': ['foo']}], {'total': buildItem(), 'modifiers': [{'supportedMethods': undefined}]}) }], - ['Empty supportedMethods in modifiers should throw TypeError.', null, function() { + ['Empty supportedMethods in modifiers should throw TypeError.', new TypeError(), function() { new PaymentRequest([{'supportedMethods': ['foo']}], {'total': buildItem(), 'modifiers': [{'supportedMethods': []}]}) }], - ['Absence of supportedMethods in modifiers should throw TypeError.', null, function() { + ['Absence of supportedMethods in modifiers should throw TypeError.', new TypeError(), function() { new PaymentRequest([{'supportedMethods': ['foo']}], {'total': buildItem(), 'modifiers': [{'total': buildItem()}]}) }], - ['Empty details should throw', null, function() { + ['Empty details should throw', new TypeError(), function() { new PaymentRequest([{'supportedMethods': ['foo']}], {}) }], ['Null items should throw', new TypeError(), function() { @@ -343,21 +343,21 @@ }], // Payment method specific data should be a JSON-serializable object. - ['String value for payment method specific data parameter should throw', null, function() { + ['String value for payment method specific data parameter should throw', new TypeError(), function() { new PaymentRequest([{'supportedMethods': ['foo'], 'data': 'foo'}], buildDetails(), {}) }], - ['Numeric value for payment method specific data parameter should throw', null, function() { + ['Numeric value for payment method specific data parameter should throw', new TypeError(), function() { new PaymentRequest([{'supportedMethods': ['foo'], 'data': 42}], buildDetails(), {}) }], - ['Infinite JSON value for one of the payment method specific data pieces should throw', null, function() { + ['Infinite JSON value for one of the payment method specific data pieces should throw', new TypeError(), function() { var infiniteData = {'foo': {}}; infiniteData.foo = infiniteData; new PaymentRequest([{'supportedMethods': ['foo'], 'data': infiniteData}], buildDetails()) }], - ['Null for payment method specific data parameter should throw', null, function() { + ['Null for payment method specific data parameter should throw', new TypeError(), function() { new PaymentRequest([{'supportedMethods': ['foo'], 'data': null}], buildDetails()) }], - ['Empty string for payment method specific data parameter should throw', null, function() { + ['Empty string for payment method specific data parameter should throw', new TypeError(), function() { new PaymentRequest([{'supportedMethods': ['foo'], 'data': ''}], buildDetails()) }] ]); @@ -366,51 +366,51 @@ for (var i in detailNames) { generate_tests(assert_throws, [ // Invalid currency code formats. - ['Undefined currency code in ' + detailNames[i] + ' should throw', null, function() { + ['Undefined currency code in ' + detailNames[i] + ' should throw', new TypeError(), function() { new PaymentRequest([{'supportedMethods': ['foo']}], buildDetails(detailNames[i], {'currency': undefined}), {requestShipping: true}) }], // Invalid amount formats. - ['Invalid amount "-" in ' + detailNames[i] + ' should throw', null, function() { + ['Invalid amount "-" in ' + detailNames[i] + ' should throw', new TypeError(), function() { new PaymentRequest([{'supportedMethods': ['foo']}], buildDetails(detailNames[i], {'value': '-'}), {requestShipping: true}) }], - ['Invalid amount "notdigits" in ' + detailNames[i] + ' should throw', null, function() { + ['Invalid amount "notdigits" in ' + detailNames[i] + ' should throw', new TypeError(), function() { new PaymentRequest([{'supportedMethods': ['foo']}], buildDetails(detailNames[i], {'value': 'notdigits'}), {requestShipping: true}) }], - ['Invalid amount "ALSONOTDIGITS" in ' + detailNames[i] + ' should throw', null, function() { + ['Invalid amount "ALSONOTDIGITS" in ' + detailNames[i] + ' should throw', new TypeError(), function() { new PaymentRequest([{'supportedMethods': ['foo']}], buildDetails(detailNames[i], {'value': 'ALSONOTDIGITS'}), {requestShipping: true}) }], - ['Invalid amount "10." in ' + detailNames[i] + ' should throw', null, function() { + ['Invalid amount "10." in ' + detailNames[i] + ' should throw', new TypeError(), function() { new PaymentRequest([{'supportedMethods': ['foo']}], buildDetails(detailNames[i], {'value': '10.'}), {requestShipping: true}) }], - ['Invalid amount ".99" in ' + detailNames[i] + ' should throw', null, function() { + ['Invalid amount ".99" in ' + detailNames[i] + ' should throw', new TypeError(), function() { new PaymentRequest([{'supportedMethods': ['foo']}], buildDetails(detailNames[i], {'value': '.99'}), {requestShipping: true}) }], - ['Invalid amount "-10." in ' + detailNames[i] + ' should throw', null, function() { + ['Invalid amount "-10." in ' + detailNames[i] + ' should throw', new TypeError(), function() { new PaymentRequest([{'supportedMethods': ['foo']}], buildDetails(detailNames[i], {'value': '-10.'}), {requestShipping: true}) }], - ['Invalid amount "-.99" in ' + detailNames[i] + ' should throw', null, function() { + ['Invalid amount "-.99" in ' + detailNames[i] + ' should throw', new TypeError(), function() { new PaymentRequest([{'supportedMethods': ['foo']}], buildDetails(detailNames[i], {'value': '-.99'}), {requestShipping: true}) }], - ['Invalid amount "10-" in ' + detailNames[i] + ' should throw', null, function() { + ['Invalid amount "10-" in ' + detailNames[i] + ' should throw', new TypeError(), function() { new PaymentRequest([{'supportedMethods': ['foo']}], buildDetails(detailNames[i], {'value': '10-'}), {requestShipping: true}) }], - ['Invalid amount "1-0" in ' + detailNames[i] + ' should throw', null, function() { + ['Invalid amount "1-0" in ' + detailNames[i] + ' should throw', new TypeError(), function() { new PaymentRequest([{'supportedMethods': ['foo']}], buildDetails(detailNames[i], {'value': '1-0'}), {requestShipping: true}) }], - ['Invalid amount "1.0.0" in ' + detailNames[i] + ' should throw', null, function() { + ['Invalid amount "1.0.0" in ' + detailNames[i] + ' should throw', new TypeError(), function() { new PaymentRequest([{'supportedMethods': ['foo']}], buildDetails(detailNames[i], {'value': '1.0.0'}), {requestShipping: true}) }], - ['Invalid amount "1/3" in ' + detailNames[i] + ' should throw', null, function() { + ['Invalid amount "1/3" in ' + detailNames[i] + ' should throw', new TypeError(), function() { new PaymentRequest([{'supportedMethods': ['foo']}], buildDetails(detailNames[i], {'value': '1/3'}), {requestShipping: true}) }], - ['Empty amount in ' + detailNames[i] + ' should throw', null, function() { + ['Empty amount in ' + detailNames[i] + ' should throw', new TypeError(), function() { new PaymentRequest([{'supportedMethods': ['foo']}], buildDetails(detailNames[i], {'value': ''}), {requestShipping: true}) }], - ['Null amount in ' + detailNames[i] + ' should throw', null, function() { + ['Null amount in ' + detailNames[i] + ' should throw', new TypeError(), function() { new PaymentRequest([{'supportedMethods': ['foo']}], buildDetails(detailNames[i], {'value': null}), {requestShipping: true}) }], - ['Undefined amount in ' + detailNames[i] + ' should throw', null, function() { + ['Undefined amount in ' + detailNames[i] + ' should throw', new TypeError(), function() { new PaymentRequest([{'supportedMethods': ['foo']}], buildDetails(detailNames[i], {'value': undefined}), {requestShipping: true}) }], ]);
diff --git a/third_party/WebKit/Source/core/editing/iterators/TextIterator.cpp b/third_party/WebKit/Source/core/editing/iterators/TextIterator.cpp index 2a1c2e8..6784200 100644 --- a/third_party/WebKit/Source/core/editing/iterators/TextIterator.cpp +++ b/third_party/WebKit/Source/core/editing/iterators/TextIterator.cpp
@@ -875,7 +875,7 @@ int TextIteratorAlgorithm<Strategy>::StartOffsetInCurrentContainer() const { if (text_state_->PositionNode()) { text_state_->FlushPositionOffsets(); - return text_state_->PositionStartOffset() + text_state_->TextStartOffset(); + return text_state_->PositionStartOffset(); } DCHECK(end_container_); return end_offset_; @@ -885,7 +885,7 @@ int TextIteratorAlgorithm<Strategy>::EndOffsetInCurrentContainer() const { if (text_state_->PositionNode()) { text_state_->FlushPositionOffsets(); - return text_state_->PositionEndOffset() + text_state_->TextStartOffset(); + return text_state_->PositionEndOffset(); } DCHECK(end_container_); return end_offset_;
diff --git a/third_party/WebKit/Source/core/editing/iterators/TextIteratorTextNodeHandler.cpp b/third_party/WebKit/Source/core/editing/iterators/TextIteratorTextNodeHandler.cpp index d96e3c70..1fd0e41d 100644 --- a/third_party/WebKit/Source/core/editing/iterators/TextIteratorTextNodeHandler.cpp +++ b/third_party/WebKit/Source/core/editing/iterators/TextIteratorTextNodeHandler.cpp
@@ -330,7 +330,7 @@ // come back again to finish handling this text box; don't advance to // the next one. if (static_cast<unsigned>(text_state_->PositionEndOffset()) < - text_box_end) + text_box_end + text_start_offset) return; if (behavior_.DoesNotEmitSpaceBeyondRangeEnd()) {
diff --git a/third_party/WebKit/Source/core/editing/iterators/TextIteratorTextState.cpp b/third_party/WebKit/Source/core/editing/iterators/TextIteratorTextState.cpp index e6cc3b1..6971b1f 100644 --- a/third_party/WebKit/Source/core/editing/iterators/TextIteratorTextState.cpp +++ b/third_party/WebKit/Source/core/editing/iterators/TextIteratorTextState.cpp
@@ -52,7 +52,7 @@ return single_character_buffer_; } - return text_[PositionStartOffset() + index]; + return text_[text_start_offset_ + index]; } String TextIteratorTextState::Substring(unsigned position, @@ -66,7 +66,7 @@ DCHECK_EQ(length, 1u); return String(&single_character_buffer_, 1); } - return text_.Substring(PositionStartOffset() + position, length); + return text_.Substring(text_start_offset_ + position, length); } void TextIteratorTextState::AppendTextToStringBuilder( @@ -81,7 +81,7 @@ DCHECK_EQ(position, 0u); builder.Append(single_character_buffer_); } else { - builder.Append(text_, PositionStartOffset() + position, length_to_append); + builder.Append(text_, text_start_offset_ + position, length_to_append); } } @@ -94,15 +94,15 @@ single_character_buffer_ = 0; text_length_ = 0; - last_character_ = 0; text_start_offset_ = 0; + last_character_ = 0; } void TextIteratorTextState::EmitAltText(Node* node) { text_ = ToHTMLElement(node)->AltText(); + text_start_offset_ = 0; text_length_ = text_.length(); last_character_ = text_length_ ? text_[text_length_ - 1] : 0; - text_start_offset_ = 0; } void TextIteratorTextState::FlushPositionOffsets() const { @@ -135,12 +135,14 @@ single_character_buffer_ = c; DCHECK(single_character_buffer_); text_length_ = 1; + text_start_offset_ = 0; // remember some iteration state last_character_ = c; - text_start_offset_ = 0; } +// TODO(xiaochengh): Remove the dependency on LayoutText, so that the class can +// also be used by Layout NG. void TextIteratorTextState::EmitText(Node* text_node, LayoutText* layout_object, int text_start_offset, @@ -160,14 +162,14 @@ position_node_ = text_node; position_offset_base_node_ = nullptr; - position_start_offset_ = text_start_offset; - position_end_offset_ = text_end_offset; + position_start_offset_ = text_start_offset + layout_object->TextStartOffset(); + position_end_offset_ = text_end_offset + layout_object->TextStartOffset(); single_character_buffer_ = 0; + text_start_offset_ = text_start_offset; text_length_ = text_end_offset - text_start_offset; last_character_ = text_[text_end_offset - 1]; has_emitted_ = true; - text_start_offset_ = layout_object->TextStartOffset(); } void TextIteratorTextState::AppendTextTo(ForwardsTextBuffer* output, @@ -186,17 +188,11 @@ output->PushCharacters(single_character_buffer_, 1); return; } - if (PositionNode()) { - FlushPositionOffsets(); - unsigned offset = PositionStartOffset() + position; - if (text_.Is8Bit()) - output->PushRange(text_.Characters8() + offset, length_to_append); - else - output->PushRange(text_.Characters16() + offset, length_to_append); - return; - } - // We shouldn't be attempting to append text that doesn't exist. - NOTREACHED(); + unsigned offset = text_start_offset_ + position; + if (text_.Is8Bit()) + output->PushRange(text_.Characters8() + offset, length_to_append); + else + output->PushRange(text_.Characters16() + offset, length_to_append); } } // namespace blink
diff --git a/third_party/WebKit/Source/core/editing/iterators/TextIteratorTextState.h b/third_party/WebKit/Source/core/editing/iterators/TextIteratorTextState.h index f81bb8fe..64dbf2f 100644 --- a/third_party/WebKit/Source/core/editing/iterators/TextIteratorTextState.h +++ b/third_party/WebKit/Source/core/editing/iterators/TextIteratorTextState.h
@@ -44,12 +44,16 @@ explicit TextIteratorTextState(const TextIteratorBehavior&); ~TextIteratorTextState() {} + // Return properties of the current text. int length() const { return text_length_; } UChar CharacterAt(unsigned index) const; String Substring(unsigned position, unsigned length) const; void AppendTextToStringBuilder(StringBuilder&, unsigned position = 0, unsigned max_length = UINT_MAX) const; + void AppendTextTo(ForwardsTextBuffer* output, + unsigned position, + unsigned length_to_append) const; void SpliceBuffer(UChar, Node* text_node, @@ -62,35 +66,36 @@ int text_end_offset); void EmitAltText(Node*); void UpdateForReplacedElement(Node* base_node); + + // Return position of the current text. void FlushPositionOffsets() const; int PositionStartOffset() const { return position_start_offset_; } int PositionEndOffset() const { return position_end_offset_; } Node* PositionNode() const { return position_node_; } + bool HasEmitted() const { return has_emitted_; } UChar LastCharacter() const { return last_character_; } - int TextStartOffset() const { return text_start_offset_; } void ResetRunInformation() { position_node_ = nullptr; text_length_ = 0; } - void AppendTextTo(ForwardsTextBuffer* output, - unsigned position, - unsigned length_to_append) const; - DECLARE_TRACE(); private: int text_length_ = 0; - String text_; // Used for whitespace characters that aren't in the DOM, so we can point at // them. - // If non-zero, overrides m_text. + // If non-zero, overrides |text_|. UChar single_character_buffer_ = 0; - // The current text and its position, in the form to be returned from the - // iterator. + // The current text when |single_character_buffer_| is zero, in which case it + // is |text_.Substring(text_start_offset_, text_length_)|. + String text_; + int text_start_offset_ = 0; + + // Position of the current text, in the form to be returned from the iterator. Member<Node> position_node_; mutable Member<Node> position_offset_base_node_; mutable int position_start_offset_ = 0; @@ -103,10 +108,6 @@ const TextIteratorBehavior behavior_; - // Stores the length of :first-letter when we are at the remaining text. - // Equals to 0 in all other cases. - int text_start_offset_ = 0; - DISALLOW_COPY_AND_ASSIGN(TextIteratorTextState); };
diff --git a/third_party/WebKit/Source/core/inspector/InspectorCSSAgent.cpp b/third_party/WebKit/Source/core/inspector/InspectorCSSAgent.cpp index 77463d4..eddcc1c 100644 --- a/third_party/WebKit/Source/core/inspector/InspectorCSSAgent.cpp +++ b/third_party/WebKit/Source/core/inspector/InspectorCSSAgent.cpp
@@ -757,6 +757,7 @@ HeapVector<Member<Document>> documents = dom_agent_->Documents(); for (Document* document : documents) UpdateActiveStyleSheets(document); + was_enabled_ = true; } Response InspectorCSSAgent::disable() { @@ -764,6 +765,7 @@ dom_agent_->SetDOMListener(nullptr); instrumenting_agents_->removeInspectorCSSAgent(this); state_->setBoolean(CSSAgentState::kCssAgentEnabled, false); + was_enabled_ = false; resource_content_loader_->Cancel(resource_content_loader_client_id_); state_->setBoolean(CSSAgentState::kRuleRecordingEnabled, false); SetCoverageEnabled(false); @@ -915,8 +917,12 @@ inherited_entries, Maybe<protocol::Array<protocol::CSS::CSSKeyframesRule>>* css_keyframes_rules) { + Response response = AssertEnabled(); + if (!response.isSuccess()) + return response; + Element* element = nullptr; - Response response = dom_agent_->AssertElement(node_id, element); + response = dom_agent_->AssertElement(node_id, element); if (!response.isSuccess()) return response; @@ -1092,8 +1098,11 @@ int node_id, Maybe<protocol::CSS::CSSStyle>* inline_style, Maybe<protocol::CSS::CSSStyle>* attributes_style) { + Response response = AssertEnabled(); + if (!response.isSuccess()) + return response; Element* element = nullptr; - Response response = dom_agent_->AssertElement(node_id, element); + response = dom_agent_->AssertElement(node_id, element); if (!response.isSuccess()) return response; @@ -1111,8 +1120,11 @@ int node_id, std::unique_ptr<protocol::Array<protocol::CSS::CSSComputedStyleProperty>>* style) { + Response response = AssertEnabled(); + if (!response.isSuccess()) + return response; Node* node = nullptr; - Response response = dom_agent_->AssertNode(node_id, node); + response = dom_agent_->AssertNode(node_id, node); if (!response.isSuccess()) return response; @@ -1178,8 +1190,11 @@ int node_id, std::unique_ptr<protocol::Array<protocol::CSS::PlatformFontUsage>>* platform_fonts) { + Response response = AssertEnabled(); + if (!response.isSuccess()) + return response; Node* node = nullptr; - Response response = dom_agent_->AssertNode(node_id, node); + response = dom_agent_->AssertNode(node_id, node); if (!response.isSuccess()) return response; @@ -1565,8 +1580,11 @@ Response InspectorCSSAgent::forcePseudoState( int node_id, std::unique_ptr<protocol::Array<String>> forced_pseudo_classes) { + Response response = AssertEnabled(); + if (!response.isSuccess()) + return response; Element* element = nullptr; - Response response = dom_agent_->AssertElement(node_id, element); + response = dom_agent_->AssertElement(node_id, element); if (!response.isSuccess()) return response; @@ -1891,9 +1909,17 @@ return css_style_sheet_to_inspector_style_sheet_.at(&inspector_sheet); } +Response InspectorCSSAgent::AssertEnabled() { + return was_enabled_ ? Response::OK() + : Response::Error("CSS agent was not enabled"); +} + Response InspectorCSSAgent::AssertInspectorStyleSheetForId( const String& style_sheet_id, InspectorStyleSheet*& result) { + Response response = AssertEnabled(); + if (!response.isSuccess()) + return response; IdToInspectorStyleSheet::iterator it = id_to_inspector_style_sheet_.find(style_sheet_id); if (it == id_to_inspector_style_sheet_.end())
diff --git a/third_party/WebKit/Source/core/inspector/InspectorCSSAgent.h b/third_party/WebKit/Source/core/inspector/InspectorCSSAgent.h index 6b381b2..81f8b8b5 100644 --- a/third_party/WebKit/Source/core/inspector/InspectorCSSAgent.h +++ b/third_party/WebKit/Source/core/inspector/InspectorCSSAgent.h
@@ -280,6 +280,8 @@ InspectorStyleSheet* InspectorStyleSheetForRule(CSSStyleRule*); InspectorStyleSheet* ViaInspectorStyleSheet(Document*); + + protocol::Response AssertEnabled(); protocol::Response AssertInspectorStyleSheetForId(const String&, InspectorStyleSheet*&); protocol::Response AssertStyleSheetForId(const String&, @@ -352,6 +354,7 @@ Member<CSSStyleSheet> inspector_user_agent_style_sheet_; int resource_content_loader_client_id_; + bool was_enabled_ = false; friend class InspectorResourceContentLoaderCallback; friend class StyleSheetBinder;
diff --git a/third_party/WebKit/Source/core/layout/LayoutBox.h b/third_party/WebKit/Source/core/layout/LayoutBox.h index 2af18c4..0e4c826a 100644 --- a/third_party/WebKit/Source/core/layout/LayoutBox.h +++ b/third_party/WebKit/Source/core/layout/LayoutBox.h
@@ -1280,8 +1280,8 @@ VisualRectFlags, TransformState&) const; - virtual bool HasRelativeLogicalWidth() const; - virtual bool HasRelativeLogicalHeight() const; + bool HasRelativeLogicalWidth() const; + bool HasRelativeLogicalHeight() const; bool HasHorizontalLayoutOverflow() const { if (!overflow_)
diff --git a/third_party/WebKit/Source/core/xmlhttprequest/XMLHttpRequest.cpp b/third_party/WebKit/Source/core/xmlhttprequest/XMLHttpRequest.cpp index 2cb0204..1a2ec91 100644 --- a/third_party/WebKit/Source/core/xmlhttprequest/XMLHttpRequest.cpp +++ b/third_party/WebKit/Source/core/xmlhttprequest/XMLHttpRequest.cpp
@@ -798,7 +798,7 @@ if (AreMethodAndURLValidForSend()) { if (GetRequestHeader(HTTPNames::Content_Type).IsEmpty()) { - const String& blob_type = body->type(); + const String& blob_type = FetchUtils::NormalizeHeaderValue(body->type()); if (!blob_type.IsEmpty() && ParsedContentType(blob_type).IsValid()) { SetRequestHeaderInternal(HTTPNames::Content_Type, AtomicString(blob_type)); @@ -839,7 +839,7 @@ if (GetRequestHeader(HTTPNames::Content_Type).IsEmpty()) { AtomicString content_type = AtomicString("multipart/form-data; boundary=") + - http_body->Boundary().data(); + FetchUtils::NormalizeHeaderValue(http_body->Boundary().data()); SetRequestHeaderInternal(HTTPNames::Content_Type, content_type); } } @@ -1297,28 +1297,36 @@ mime_type_override_ = mime_type; } +// https://xhr.spec.whatwg.org/#the-setrequestheader()-method void XMLHttpRequest::setRequestHeader(const AtomicString& name, const AtomicString& value, ExceptionState& exception_state) { + // "1. If |state| is not "opened", throw an InvalidStateError exception. + // 2. If the send() flag is set, throw an InvalidStateError exception." if (state_ != kOpened || send_flag_) { exception_state.ThrowDOMException(kInvalidStateError, "The object's state must be OPENED."); return; } + // "3. Normalize |value|." + const String normalized_value = FetchUtils::NormalizeHeaderValue(value); + + // "4. If |name| is not a name or |value| is not a value, throw a SyntaxError + // exception." if (!IsValidHTTPToken(name)) { exception_state.ThrowDOMException( kSyntaxError, "'" + name + "' is not a valid HTTP header field name."); return; } - - if (!IsValidHTTPHeaderValue(value)) { + if (!IsValidHTTPHeaderValue(normalized_value)) { exception_state.ThrowDOMException( kSyntaxError, - "'" + value + "' is not a valid HTTP header field value."); + "'" + normalized_value + "' is not a valid HTTP header field value."); return; } + // "5. Terminate these steps if |name| is a forbidden header name." // No script (privileged or not) can set unsafe headers. if (FetchUtils::IsForbiddenHeaderName(name)) { LogConsoleError(GetExecutionContext(), @@ -1326,11 +1334,14 @@ return; } - SetRequestHeaderInternal(name, value); + // "6. Combine |name|/|value| in author request headers." + SetRequestHeaderInternal(name, AtomicString(normalized_value)); } void XMLHttpRequest::SetRequestHeaderInternal(const AtomicString& name, const AtomicString& value) { + DCHECK_EQ(value, FetchUtils::NormalizeHeaderValue(value)) + << "Header values must be normalized"; HTTPHeaderMap::AddResult result = request_headers_.Add(name, value); if (!result.is_new_entry) { AtomicString new_value = result.stored_value->value + ", " + value;
diff --git a/third_party/WebKit/Source/devtools/front_end/bindings/ResourceScriptMapping.js b/third_party/WebKit/Source/devtools/front_end/bindings/ResourceScriptMapping.js index 1c9adac..fead041 100644 --- a/third_party/WebKit/Source/devtools/front_end/bindings/ResourceScriptMapping.js +++ b/third_party/WebKit/Source/devtools/front_end/bindings/ResourceScriptMapping.js
@@ -90,10 +90,11 @@ console.assert(scripts.length); var script = scripts[scripts.length - 1]; if (script.isInlineScriptWithSourceURL()) { - return this._debuggerModel.createRawLocation( - script, lineNumber + script.lineOffset, lineNumber ? columnNumber : columnNumber + script.columnOffset); + return this._debuggerModel.createRawLocationByURL( + script.sourceURL, lineNumber + script.lineOffset, + lineNumber ? columnNumber : columnNumber + script.columnOffset); } - return this._debuggerModel.createRawLocation(script, lineNumber, columnNumber); + return this._debuggerModel.createRawLocationByURL(script.sourceURL, lineNumber, columnNumber); } /**
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 082c942..91d2371 100644 --- a/third_party/WebKit/Source/devtools/front_end/devices/DevicesView.js +++ b/third_party/WebKit/Source/devtools/front_end/devices/DevicesView.js
@@ -791,8 +791,7 @@ var titleRow = element.createChild('div', 'device-page-title-row'); var title = titleRow.createChild('div', 'device-page-title'); - var inspect = - UI.createTextButton(Common.UIString('Inspect'), doAction.bind(null, 'inspect'), 'device-inspect-button'); + var inspect = UI.createTextButton(Common.UIString('Inspect'), doAction.bind(null, 'inspect')); titleRow.appendChild(inspect); var toolbar = new UI.Toolbar('');
diff --git a/third_party/WebKit/Source/devtools/front_end/help/ReleaseNoteView.js b/third_party/WebKit/Source/devtools/front_end/help/ReleaseNoteView.js index a8ab848..ddd24aaa 100644 --- a/third_party/WebKit/Source/devtools/front_end/help/ReleaseNoteView.js +++ b/third_party/WebKit/Source/devtools/front_end/help/ReleaseNoteView.js
@@ -31,19 +31,14 @@ } var actionContainer = container.createChild('div', 'release-note-action-container'); - var viewMoreButton = actionContainer.createChild('button'); - viewMoreButton.textContent = Common.UIString('Learn more'); - viewMoreButton.addEventListener('click', event => { + actionContainer.appendChild(UI.createTextButton(Common.UIString('Learn more'), event => { event.consume(true); InspectorFrontendHost.openInNewTab(releaseNote.link); - }); - - var closeButton = actionContainer.createChild('button', 'close-release-note'); - closeButton.textContent = Common.UIString('Close'); - closeButton.addEventListener('click', event => { + })); + actionContainer.appendChild(UI.createTextButton(Common.UIString('Close'), event => { event.consume(true); UI.inspectorView.closeDrawerTab(Help._releaseNoteViewId, true); - }); + }, 'close-release-note')); var imageLink = UI.createExternalLink(releaseNote.link, ' '); imageLink.classList.add('release-note-image');
diff --git a/third_party/WebKit/Source/devtools/front_end/help/releaseNote.css b/third_party/WebKit/Source/devtools/front_end/help/releaseNote.css index e09c204..b49054e 100644 --- a/third_party/WebKit/Source/devtools/front_end/help/releaseNote.css +++ b/third_party/WebKit/Source/devtools/front_end/help/releaseNote.css
@@ -75,6 +75,7 @@ text-transform: uppercase; color: #757575; font-size: 13px; + box-shadow: none; } .release-note-action-container > button:hover {
diff --git a/third_party/WebKit/Source/devtools/front_end/perf_ui/FilmStripView.js b/third_party/WebKit/Source/devtools/front_end/perf_ui/FilmStripView.js index ee0774c..049bf3e 100644 --- a/third_party/WebKit/Source/devtools/front_end/perf_ui/FilmStripView.js +++ b/third_party/WebKit/Source/devtools/front_end/perf_ui/FilmStripView.js
@@ -223,12 +223,12 @@ this._imageElement = this.contentElement.createChild('img'); var footerElement = this.contentElement.createChild('div', 'filmstrip-dialog-footer'); footerElement.createChild('div', 'flex-auto'); - var prevButton = - UI.createTextButton('\u25C0', this._onPrevFrame.bind(this), undefined, Common.UIString('Previous frame')); + var prevButton = UI.createTextButton('\u25C0', this._onPrevFrame.bind(this)); + prevButton.title = Common.UIString('Previous frame'); footerElement.appendChild(prevButton); this._timeLabel = footerElement.createChild('div', 'filmstrip-dialog-label'); - var nextButton = - UI.createTextButton('\u25B6', this._onNextFrame.bind(this), undefined, Common.UIString('Next frame')); + var nextButton = UI.createTextButton('\u25B6', this._onNextFrame.bind(this)); + nextButton.title = Common.UIString('Next frame'); footerElement.appendChild(nextButton); footerElement.createChild('div', 'flex-auto');
diff --git a/third_party/WebKit/Source/devtools/front_end/profiler/ProfileLauncherView.js b/third_party/WebKit/Source/devtools/front_end/profiler/ProfileLauncherView.js index 0fc88a5..7cc895c 100644 --- a/third_party/WebKit/Source/devtools/front_end/profiler/ProfileLauncherView.js +++ b/third_party/WebKit/Source/devtools/front_end/profiler/ProfileLauncherView.js
@@ -47,10 +47,11 @@ targetDiv.createChild('div').textContent = Common.UIString('Target:'); var targetsSelect = targetDiv.createChild('select', 'chrome-select'); new Profiler.TargetsComboBoxController(targetsSelect, targetDiv); - this._controlButton = UI.createTextButton('', this._controlButtonClicked.bind(this)); - controlDiv.appendChild(this._controlButton); + this._controlButton = UI.createTextButton('', this._controlButtonClicked.bind(this), 'profile-launcher-button'); + this._contentElement.appendChild(this._controlButton); this._recordButtonEnabled = true; - this._loadButton = UI.createTextButton(Common.UIString('Load'), this._loadButtonClicked.bind(this), 'load-profile'); + this._loadButton = + UI.createTextButton(Common.UIString('Load'), this._loadButtonClicked.bind(this), 'profile-launcher-button'); this._contentElement.appendChild(this._loadButton); this._selectedProfileTypeSetting = Common.settings.createSetting('selectedProfileType', 'CPU');
diff --git a/third_party/WebKit/Source/devtools/front_end/profiler/profilesPanel.css b/third_party/WebKit/Source/devtools/front_end/profiler/profilesPanel.css index eb70b40..407370e8 100644 --- a/third_party/WebKit/Source/devtools/front_end/profiler/profilesPanel.css +++ b/third_party/WebKit/Source/devtools/front_end/profiler/profilesPanel.css
@@ -200,12 +200,12 @@ width: 150px; } -button.load-profile { +.profile-launcher-button { margin-top: 10px; + margin-right: 8px; min-width: 110px; } - .cpu-profile-flame-chart-overview-container { overflow: hidden; position: absolute;
diff --git a/third_party/WebKit/Source/devtools/front_end/sdk/DebuggerModel.js b/third_party/WebKit/Source/devtools/front_end/sdk/DebuggerModel.js index 6ed168c4..38989116 100644 --- a/third_party/WebKit/Source/devtools/front_end/sdk/DebuggerModel.js +++ b/third_party/WebKit/Source/devtools/front_end/sdk/DebuggerModel.js
@@ -592,8 +592,6 @@ * @return {?SDK.DebuggerModel.Location} */ createRawLocation(script, lineNumber, columnNumber) { - if (script.sourceURL) - return this.createRawLocationByURL(script.sourceURL, lineNumber, columnNumber); return new SDK.DebuggerModel.Location(this, script.scriptId, lineNumber, columnNumber); }
diff --git a/third_party/WebKit/Source/devtools/front_end/ui/SearchableView.js b/third_party/WebKit/Source/devtools/front_end/ui/SearchableView.js index 3d33e23..8c8e917ac3 100644 --- a/third_party/WebKit/Source/devtools/front_end/ui/SearchableView.js +++ b/third_party/WebKit/Source/devtools/front_end/ui/SearchableView.js
@@ -103,43 +103,40 @@ // Build the buttons (Find, Previous, Replace, Replace All). this._buttonsContainer = this._footerElement.createChild('div', 'toolbar-search-buttons hidden'); - var findButtonElement = this._buttonsContainer.createChild('button', 'search-action-button'); - findButtonElement.textContent = Common.UIString('Find'); + var findButtonElement = + UI.createTextButton(Common.UIString('Find'), this._onFindClick.bind(this), 'search-action-button'); findButtonElement.tabIndex = -1; - findButtonElement.addEventListener('click', this._onFindClick.bind(this), false); + this._buttonsContainer.appendChild(findButtonElement); - var prevButtonElement = this._buttonsContainer.createChild('button', 'search-action-button'); - prevButtonElement.textContent = Common.UIString('Previous'); + var prevButtonElement = + UI.createTextButton(Common.UIString('Previous'), this._onPreviousClick.bind(this), 'search-action-button'); prevButtonElement.tabIndex = -1; - prevButtonElement.addEventListener('click', this._onPreviousClick.bind(this), false); + this._buttonsContainer.appendChild(prevButtonElement); - this._replaceButtonElement = this._buttonsContainer.createChild('button', 'search-action-button'); - this._replaceButtonElement.textContent = Common.UIString('Replace'); + this._replaceButtonElement = + UI.createTextButton(Common.UIString('Replace'), this._replace.bind(this), 'search-action-button'); this._replaceButtonElement.disabled = true; this._replaceButtonElement.tabIndex = -1; - this._replaceButtonElement.addEventListener('click', this._replace.bind(this), false); + this._buttonsContainer.appendChild(this._replaceButtonElement); - var replaceAllButtonElement = this._buttonsContainer.createChild('button', 'search-action-button'); - replaceAllButtonElement.textContent = Common.UIString('Replace All'); - replaceAllButtonElement.addEventListener('click', this._replaceAll.bind(this), false); + var replaceAllButtonElement = + UI.createTextButton(Common.UIString('Replace All'), this._replaceAll.bind(this), 'search-action-button'); + this._buttonsContainer.appendChild(replaceAllButtonElement); // Build the replace checkbox and cancel button. this._replaceElement = this._footerElement.createChild('div').createChild('span', 'toolbar-replace-checkbox'); var replaceLabelElement = UI.CheckboxLabel.create(Common.UIString('Replace')); this._replaceCheckboxElement = replaceLabelElement.checkboxElement; - var uniqueId = ++UI.SearchableView._lastUniqueId; - var replaceCheckboxId = 'search-replace-trigger' + uniqueId; - this._replaceCheckboxElement.id = replaceCheckboxId; this._replaceCheckboxElement.addEventListener('change', this._updateSecondRowVisibility.bind(this), false); this._replaceElement.appendChild(replaceLabelElement); - var cancelButtonElement = this._footerElement.createChild('div').createChild('button', 'search-action-button'); - cancelButtonElement.textContent = Common.UIString('Cancel'); + var cancelButtonElement = + UI.createTextButton(Common.UIString('Cancel'), this.closeSearch.bind(this), 'search-action-button'); cancelButtonElement.tabIndex = -1; - cancelButtonElement.addEventListener('click', this.closeSearch.bind(this), false); this._minimalSearchQuerySize = 3; + this._footerElement.createChild('div').appendChild(cancelButtonElement); this._loadSetting(); } @@ -510,7 +507,6 @@ } }; -UI.SearchableView._lastUniqueId = 0; UI.SearchableView._symbol = Symbol('searchableView');
diff --git a/third_party/WebKit/Source/devtools/front_end/ui/UIUtils.js b/third_party/WebKit/Source/devtools/front_end/ui/UIUtils.js index ea0a021..13125efc 100644 --- a/third_party/WebKit/Source/devtools/front_end/ui/UIUtils.js +++ b/third_party/WebKit/Source/devtools/front_end/ui/UIUtils.js
@@ -1170,16 +1170,13 @@ * @param {string} text * @param {function(!Event)=} clickHandler * @param {string=} className - * @param {string=} title * @return {!Element} */ -UI.createTextButton = function(text, clickHandler, className, title) { +UI.createTextButton = function(text, clickHandler, className) { var element = createElementWithClass('button', className || '', 'text-button'); element.textContent = text; if (clickHandler) element.addEventListener('click', clickHandler, false); - if (title) - element.title = title; return element; };
diff --git a/third_party/WebKit/Source/devtools/front_end/ui/searchableView.css b/third_party/WebKit/Source/devtools/front_end/ui/searchableView.css index b5c4f1e..b5b74fa 100644 --- a/third_party/WebKit/Source/devtools/front_end/ui/searchableView.css +++ b/third_party/WebKit/Source/devtools/front_end/ui/searchableView.css
@@ -77,7 +77,7 @@ border-radius: 8px; margin: 1px 3px 0 3px; background-image: linear-gradient(rgb(241, 241, 241), rgb(220, 220, 220)); - width: 75px; + width: 82px; height: 20px; white-space: nowrap; } @@ -93,7 +93,7 @@ } .toolbar-search-buttons { - flex-basis: 165px; + flex-basis: 179px; } .toolbar-replace-control,
diff --git a/third_party/WebKit/Source/devtools/front_end/ui/textButton.css b/third_party/WebKit/Source/devtools/front_end/ui/textButton.css index d4a718b..be3ce161 100644 --- a/third_party/WebKit/Source/devtools/front_end/ui/textButton.css +++ b/third_party/WebKit/Source/devtools/front_end/ui/textButton.css
@@ -13,7 +13,7 @@ font-size: 12px; margin: 0 1px 0 0; text-shadow: 0 1px 0 hsl(0, 0%, 94%); - min-height: 2em !important; + height: 24px; padding-left: 10px; padding-right: 10px; -webkit-user-select: none;
diff --git a/third_party/WebKit/Source/modules/budget/BudgetService.idl b/third_party/WebKit/Source/modules/budget/BudgetService.idl index 3f89319..e0235e2b 100644 --- a/third_party/WebKit/Source/modules/budget/BudgetService.idl +++ b/third_party/WebKit/Source/modules/budget/BudgetService.idl
@@ -12,7 +12,7 @@ RuntimeEnabled=Budget, Exposed=(Window,Worker) ] interface BudgetService { - [OriginTrialEnabled=BudgetQuery, CallWith=ScriptState] Promise<double> getCost(OperationType operation); - [OriginTrialEnabled=BudgetQuery, CallWith=ScriptState] Promise<sequence<BudgetState>> getBudget(); + [OriginTrialEnabled=BudgetQuery, CallWith=ScriptState, MeasureAs=BudgetAPIGetCost] Promise<double> getCost(OperationType operation); + [OriginTrialEnabled=BudgetQuery, CallWith=ScriptState, MeasureAs=BudgetAPIGetBudget] Promise<sequence<BudgetState>> getBudget(); [CallWith=ScriptState] Promise<boolean> reserve(OperationType operation); };
diff --git a/third_party/WebKit/Source/modules/fetch/Headers.cpp b/third_party/WebKit/Source/modules/fetch/Headers.cpp index 7e6ea5f..985c6fb 100644 --- a/third_party/WebKit/Source/modules/fetch/Headers.cpp +++ b/third_party/WebKit/Source/modules/fetch/Headers.cpp
@@ -79,37 +79,40 @@ ExceptionState& exception_state) { // "To append a name/value (|name|/|value|) pair to a Headers object // (|headers|), run these steps:" - // "1. If |name| is not a name or |value| is not a value, throw a + // "1. Normalize |value|." + const String normalized_value = FetchUtils::NormalizeHeaderValue(value); + // "2. If |name| is not a name or |value| is not a value, throw a // TypeError." if (!FetchHeaderList::IsValidHeaderName(name)) { exception_state.ThrowTypeError("Invalid name"); return; } - if (!FetchHeaderList::IsValidHeaderValue(value)) { + if (!FetchHeaderList::IsValidHeaderValue(normalized_value)) { exception_state.ThrowTypeError("Invalid value"); return; } - // "2. If guard is |request|, throw a TypeError." + // "3. If guard is |request|, throw a TypeError." if (guard_ == kImmutableGuard) { exception_state.ThrowTypeError("Headers are immutable"); return; } - // "3. Otherwise, if guard is |request| and |name| is a forbidden header + // "4. Otherwise, if guard is |request| and |name| is a forbidden header // name, return." if (guard_ == kRequestGuard && FetchUtils::IsForbiddenHeaderName(name)) return; - // "4. Otherwise, if guard is |request-no-CORS| and |name|/|value| is not a + // "5. Otherwise, if guard is |request-no-CORS| and |name|/|value| is not a // simple header, return." if (guard_ == kRequestNoCORSGuard && - !FetchUtils::IsSimpleHeader(AtomicString(name), AtomicString(value))) + !FetchUtils::IsSimpleHeader(AtomicString(name), + AtomicString(normalized_value))) return; - // "5. Otherwise, if guard is |response| and |name| is a forbidden response + // "6. Otherwise, if guard is |response| and |name| is a forbidden response // header name, return." if (guard_ == kResponseGuard && FetchUtils::IsForbiddenResponseHeaderName(name)) return; - // "6. Append |name|/|value| to header list." - header_list_->Append(name, value); + // "7. Append |name|/|value| to header list." + header_list_->Append(name, normalized_value); } void Headers::remove(const String& name, ExceptionState& exception_state) { @@ -173,37 +176,40 @@ const String& value, ExceptionState& exception_state) { // "The set(|name|, |value|) method, when invoked, must run these steps:" - // "1. If |name| is not a name or |value| is not a value, throw a + // "1. Normalize |value|." + const String normalized_value = FetchUtils::NormalizeHeaderValue(value); + // "2. If |name| is not a name or |value| is not a value, throw a // TypeError." if (!FetchHeaderList::IsValidHeaderName(name)) { exception_state.ThrowTypeError("Invalid name"); return; } - if (!FetchHeaderList::IsValidHeaderValue(value)) { + if (!FetchHeaderList::IsValidHeaderValue(normalized_value)) { exception_state.ThrowTypeError("Invalid value"); return; } - // "2. If guard is |immutable|, throw a TypeError." + // "3. If guard is |immutable|, throw a TypeError." if (guard_ == kImmutableGuard) { exception_state.ThrowTypeError("Headers are immutable"); return; } - // "3. Otherwise, if guard is |request| and |name| is a forbidden header + // "4. Otherwise, if guard is |request| and |name| is a forbidden header // name, return." if (guard_ == kRequestGuard && FetchUtils::IsForbiddenHeaderName(name)) return; - // "4. Otherwise, if guard is |request-no-CORS| and |name|/|value| is not a + // "5. Otherwise, if guard is |request-no-CORS| and |name|/|value| is not a // simple header, return." if (guard_ == kRequestNoCORSGuard && - !FetchUtils::IsSimpleHeader(AtomicString(name), AtomicString(value))) + !FetchUtils::IsSimpleHeader(AtomicString(name), + AtomicString(normalized_value))) return; - // "5. Otherwise, if guard is |response| and |name| is a forbidden response + // "6. Otherwise, if guard is |response| and |name| is a forbidden response // header name, return." if (guard_ == kResponseGuard && FetchUtils::IsForbiddenResponseHeaderName(name)) return; - // "6. Set |name|/|value| in header list." - header_list_->Set(name, value); + // "7. Set |name|/|value| in header list." + header_list_->Set(name, normalized_value); } // This overload is not called directly by Web APIs, but rather by other C++
diff --git a/third_party/WebKit/Source/platform/fonts/shaping/ShapeResult.cpp b/third_party/WebKit/Source/platform/fonts/shaping/ShapeResult.cpp index 9e1d3f5..1e91b421 100644 --- a/third_party/WebKit/Source/platform/fonts/shaping/ShapeResult.cpp +++ b/third_party/WebKit/Source/platform/fonts/shaping/ShapeResult.cpp
@@ -170,7 +170,7 @@ has_vertical_offsets_(other.has_vertical_offsets_) { runs_.ReserveCapacity(other.runs_.size()); for (const auto& run : other.runs_) - runs_.push_back(WTF::WrapUnique(new ShapeResult::RunInfo(*run))); + runs_.push_back(base::MakeUnique<RunInfo>(*run)); } ShapeResult::~ShapeResult() {} @@ -447,11 +447,11 @@ unsigned end = std::min(end_offset - run_start, run_end); DCHECK(end > start); - ShapeResult::RunInfo* sub_run = (*run).CreateSubRun(start, end); + auto sub_run = (*run).CreateSubRun(start, end); sub_run->start_index_ = index; - target->runs_.push_back(WTF::WrapUnique(sub_run)); target->width_ += sub_run->width_; index += sub_run->num_characters_; + target->runs_.push_back(std::move(sub_run)); } } @@ -466,10 +466,9 @@ const SimpleFontData* font_data = font->PrimaryFont(); // Tab characters are always LTR or RTL, not TTB, even when // isVerticalAnyUpright(). - std::unique_ptr<ShapeResult::RunInfo> run = - WTF::WrapUnique(new ShapeResult::RunInfo( - font_data, text_run.Rtl() ? HB_DIRECTION_RTL : HB_DIRECTION_LTR, - HB_SCRIPT_COMMON, 0, count, count)); + std::unique_ptr<ShapeResult::RunInfo> run = base::MakeUnique<RunInfo>( + font_data, text_run.Rtl() ? HB_DIRECTION_RTL : HB_DIRECTION_LTR, + HB_SCRIPT_COMMON, 0, count, count); float position = text_run.XPos() + position_offset; float start_position = position; for (unsigned i = 0; i < count; i++) {
diff --git a/third_party/WebKit/Source/platform/fonts/shaping/ShapeResultInlineHeaders.h b/third_party/WebKit/Source/platform/fonts/shaping/ShapeResultInlineHeaders.h index 6fa7635..8337bb8 100644 --- a/third_party/WebKit/Source/platform/fonts/shaping/ShapeResultInlineHeaders.h +++ b/third_party/WebKit/Source/platform/fonts/shaping/ShapeResultInlineHeaders.h
@@ -99,7 +99,7 @@ } // Creates a new RunInfo instance representing a subset of the current run. - RunInfo* CreateSubRun(unsigned start, unsigned end) { + std::unique_ptr<RunInfo> CreateSubRun(unsigned start, unsigned end) { DCHECK(end > start); unsigned number_of_characters = std::min(end - start, num_characters_); @@ -121,9 +121,9 @@ }); } - RunInfo* run = - new RunInfo(font_data_.Get(), direction_, script_, start_index_ + start, - number_of_glyphs, number_of_characters); + auto run = base::MakeUnique<RunInfo>(font_data_.Get(), direction_, script_, + start_index_ + start, number_of_glyphs, + number_of_characters); unsigned sub_glyph_index = 0; float total_advance = 0;
diff --git a/third_party/WebKit/Source/platform/graphics/gpu/DrawingBuffer.cpp b/third_party/WebKit/Source/platform/graphics/gpu/DrawingBuffer.cpp index acc92e2..944abccd 100644 --- a/third_party/WebKit/Source/platform/graphics/gpu/DrawingBuffer.cpp +++ b/third_party/WebKit/Source/platform/graphics/gpu/DrawingBuffer.cpp
@@ -296,6 +296,7 @@ bool DrawingBuffer::FinishPrepareTextureMailboxSoftware( cc::TextureMailbox* out_mailbox, std::unique_ptr<cc::SingleReleaseCallback>* out_release_callback) { + DCHECK(state_restorer_); std::unique_ptr<cc::SharedBitmap> bitmap = CreateOrRecycleBitmap(); if (!bitmap) return false; @@ -308,6 +309,8 @@ WebGLImageConversion::AlphaOp op = need_premultiply ? WebGLImageConversion::kAlphaDoPremultiply : WebGLImageConversion::kAlphaDoNothing; + state_restorer_->SetFramebufferBindingDirty(); + gl_->BindFramebuffer(GL_FRAMEBUFFER, fbo_); ReadBackFramebuffer(pixels, Size().Width(), Size().Height(), kReadbackSkia, op); }
diff --git a/third_party/WebKit/Source/platform/graphics/gpu/DrawingBufferSoftwareRenderingTest.cpp b/third_party/WebKit/Source/platform/graphics/gpu/DrawingBufferSoftwareRenderingTest.cpp index edcd8be5..ade6f6f 100644 --- a/third_party/WebKit/Source/platform/graphics/gpu/DrawingBufferSoftwareRenderingTest.cpp +++ b/third_party/WebKit/Source/platform/graphics/gpu/DrawingBufferSoftwareRenderingTest.cpp
@@ -53,8 +53,10 @@ provider = WTF::WrapUnique( new WebGraphicsContext3DProviderSoftwareRenderingForTests( std::move(gl))); + GLES2InterfaceForTests* gl_ = + static_cast<GLES2InterfaceForTests*>(provider->ContextGL()); drawing_buffer_ = DrawingBufferForTests::Create( - std::move(provider), nullptr, initial_size, DrawingBuffer::kPreserve, + std::move(provider), gl_, initial_size, DrawingBuffer::kPreserve, kDisableMultisampling); CHECK(drawing_buffer_); } @@ -63,7 +65,7 @@ bool is_software_rendering_ = false; }; -TEST_F(DrawingBufferSoftwareRenderingTest, bitmapRecycling) { +TEST_F(DrawingBufferSoftwareRenderingTest, BitmapRecycling) { cc::TextureMailbox texture_mailbox; std::unique_ptr<cc::SingleReleaseCallback> release_callback1; std::unique_ptr<cc::SingleReleaseCallback> release_callback2; @@ -101,5 +103,29 @@ drawing_buffer_->BeginDestruction(); } +TEST_F(DrawingBufferSoftwareRenderingTest, FramebufferBinding) { + GLES2InterfaceForTests* gl_ = drawing_buffer_->ContextGLForTests(); + cc::TextureMailbox texture_mailbox; + std::unique_ptr<cc::SingleReleaseCallback> release_callback; + IntSize initial_size(kInitialWidth, kInitialHeight); + GLint drawBinding = 0, readBinding = 0; + + GLuint draw_framebuffer_binding = 0xbeef3; + GLuint read_framebuffer_binding = 0xbeef4; + gl_->BindFramebuffer(GL_DRAW_FRAMEBUFFER, draw_framebuffer_binding); + gl_->BindFramebuffer(GL_READ_FRAMEBUFFER, read_framebuffer_binding); + gl_->SaveState(); + drawing_buffer_->Resize(initial_size); + drawing_buffer_->MarkContentsChanged(); + drawing_buffer_->PrepareTextureMailbox(&texture_mailbox, &release_callback); + gl_->GetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, &drawBinding); + gl_->GetIntegerv(GL_READ_FRAMEBUFFER_BINDING, &readBinding); + EXPECT_EQ(static_cast<GLint>(draw_framebuffer_binding), drawBinding); + EXPECT_EQ(static_cast<GLint>(read_framebuffer_binding), readBinding); + release_callback->Run(gpu::SyncToken(), false /* lostResource */); + + drawing_buffer_->BeginDestruction(); +} + } // unnamed namespace } // blink
diff --git a/third_party/WebKit/Source/platform/graphics/gpu/DrawingBufferTest.cpp b/third_party/WebKit/Source/platform/graphics/gpu/DrawingBufferTest.cpp index 6cd8201..9cbaccf 100644 --- a/third_party/WebKit/Source/platform/graphics/gpu/DrawingBufferTest.cpp +++ b/third_party/WebKit/Source/platform/graphics/gpu/DrawingBufferTest.cpp
@@ -73,21 +73,23 @@ IntSize initial_size(kInitialWidth, kInitialHeight); std::unique_ptr<GLES2InterfaceForTests> gl = WTF::WrapUnique(new GLES2InterfaceForTests); - gl_ = gl.get(); - SetAndSaveRestoreState(false); std::unique_ptr<WebGraphicsContext3DProviderForTests> provider = WTF::WrapUnique( new WebGraphicsContext3DProviderForTests(std::move(gl))); + GLES2InterfaceForTests* gl_ = + static_cast<GLES2InterfaceForTests*>(provider->ContextGL()); drawing_buffer_ = DrawingBufferForTests::Create( std::move(provider), gl_, initial_size, DrawingBuffer::kPreserve, use_multisampling); CHECK(drawing_buffer_); + SetAndSaveRestoreState(false); } // Initialize GL state with unusual values, to verify that they are restored. // The |invert| parameter will reverse all boolean parameters, so that all // values are tested. void SetAndSaveRestoreState(bool invert) { + GLES2InterfaceForTests* gl_ = drawing_buffer_->ContextGLForTests(); GLboolean scissor_enabled = !invert; GLfloat clear_color[4] = {0.1, 0.2, 0.3, 0.4}; GLfloat clear_depth = 0.8; @@ -124,9 +126,11 @@ gl_->SaveState(); } - void VerifyStateWasRestored() { gl_->VerifyStateHasNotChangedSinceSave(); } + void VerifyStateWasRestored() { + GLES2InterfaceForTests* gl_ = drawing_buffer_->ContextGLForTests(); + gl_->VerifyStateHasNotChangedSinceSave(); + } - GLES2InterfaceForTests* gl_; RefPtr<DrawingBufferForTests> drawing_buffer_; }; @@ -152,6 +156,7 @@ } TEST_F(DrawingBufferTest, verifyResizingProperlyAffectsMailboxes) { + GLES2InterfaceForTests* gl_ = drawing_buffer_->ContextGLForTests(); VerifyStateWasRestored(); cc::TextureMailbox texture_mailbox; std::unique_ptr<cc::SingleReleaseCallback> release_callback; @@ -349,6 +354,7 @@ } TEST_F(DrawingBufferTest, verifyInsertAndWaitSyncTokenCorrectly) { + GLES2InterfaceForTests* gl_ = drawing_buffer_->ContextGLForTests(); cc::TextureMailbox texture_mailbox; std::unique_ptr<cc::SingleReleaseCallback> release_callback; @@ -391,18 +397,19 @@ IntSize initial_size(kInitialWidth, kInitialHeight); std::unique_ptr<GLES2InterfaceForTests> gl = WTF::WrapUnique(new GLES2InterfaceForTests); - gl_ = gl.get(); - SetAndSaveRestoreState(true); std::unique_ptr<WebGraphicsContext3DProviderForTests> provider = WTF::WrapUnique( new WebGraphicsContext3DProviderForTests(std::move(gl))); RuntimeEnabledFeatures::setWebGLImageChromiumEnabled(true); + GLES2InterfaceForTests* gl_ = + static_cast<GLES2InterfaceForTests*>(provider->ContextGL()); image_id0_ = gl_->NextImageIdToBeCreated(); EXPECT_CALL(*gl_, BindTexImage2DMock(image_id0_)).Times(1); drawing_buffer_ = DrawingBufferForTests::Create( std::move(provider), gl_, initial_size, DrawingBuffer::kPreserve, kDisableMultisampling); CHECK(drawing_buffer_); + SetAndSaveRestoreState(true); testing::Mock::VerifyAndClearExpectations(gl_); } @@ -416,6 +423,7 @@ }; TEST_F(DrawingBufferImageChromiumTest, verifyResizingReallocatesImages) { + GLES2InterfaceForTests* gl_ = drawing_buffer_->ContextGLForTests(); cc::TextureMailbox texture_mailbox; std::unique_ptr<cc::SingleReleaseCallback> release_callback; @@ -497,6 +505,7 @@ } TEST_F(DrawingBufferImageChromiumTest, allocationFailure) { + GLES2InterfaceForTests* gl_ = drawing_buffer_->ContextGLForTests(); cc::TextureMailbox texture_mailbox1; std::unique_ptr<cc::SingleReleaseCallback> release_callback1; cc::TextureMailbox texture_mailbox2; @@ -695,6 +704,7 @@ } TEST_F(DrawingBufferTest, verifySetIsHiddenProperlyAffectsMailboxes) { + GLES2InterfaceForTests* gl_ = drawing_buffer_->ContextGLForTests(); cc::TextureMailbox texture_mailbox; std::unique_ptr<cc::SingleReleaseCallback> release_callback;
diff --git a/third_party/WebKit/Source/platform/graphics/gpu/DrawingBufferTestHelpers.h b/third_party/WebKit/Source/platform/graphics/gpu/DrawingBufferTestHelpers.h index c231f09..b98717b 100644 --- a/third_party/WebKit/Source/platform/graphics/gpu/DrawingBufferTestHelpers.h +++ b/third_party/WebKit/Source/platform/graphics/gpu/DrawingBufferTestHelpers.h
@@ -24,58 +24,6 @@ kEnableMultisampling, }; -class DrawingBufferForTests : public DrawingBuffer { - public: - static PassRefPtr<DrawingBufferForTests> Create( - std::unique_ptr<WebGraphicsContext3DProvider> context_provider, - DrawingBuffer::Client* client, - const IntSize& size, - PreserveDrawingBuffer preserve, - UseMultisampling use_multisampling) { - std::unique_ptr<Extensions3DUtil> extensions_util = - Extensions3DUtil::Create(context_provider->ContextGL()); - RefPtr<DrawingBufferForTests> drawing_buffer = - AdoptRef(new DrawingBufferForTests(std::move(context_provider), - std::move(extensions_util), client, - preserve)); - if (!drawing_buffer->Initialize( - size, use_multisampling != kDisableMultisampling)) { - drawing_buffer->BeginDestruction(); - return nullptr; - } - return drawing_buffer.Release(); - } - - DrawingBufferForTests( - std::unique_ptr<WebGraphicsContext3DProvider> context_provider, - std::unique_ptr<Extensions3DUtil> extensions_util, - DrawingBuffer::Client* client, - PreserveDrawingBuffer preserve) - : DrawingBuffer( - std::move(context_provider), - std::move(extensions_util), - client, - false /* discardFramebufferSupported */, - true /* wantAlphaChannel */, - false /* premultipliedAlpha */, - preserve, - kWebGL1, - false /* wantDepth */, - false /* wantStencil */, - DrawingBuffer::kAllowChromiumImage /* ChromiumImageUsage */, - CanvasColorParams()), - live_(0) {} - - ~DrawingBufferForTests() override { - if (live_) - *live_ = false; - } - - bool* live_; - - int RecycledBitmapCount() { return recycled_bitmaps_.size(); } -}; - class WebGraphicsContext3DProviderForTests : public WebGraphicsContext3DProvider { public: @@ -214,8 +162,18 @@ } void GetIntegerv(GLenum pname, GLint* value) override { - if (pname == GL_MAX_TEXTURE_SIZE) - *value = 1024; + switch (pname) { + case GL_DRAW_FRAMEBUFFER_BINDING: + *value = state_.draw_framebuffer_binding; + break; + case GL_READ_FRAMEBUFFER_BINDING: + *value = state_.read_framebuffer_binding; + break; + case GL_MAX_TEXTURE_SIZE: + *value = 1024; + default: + break; + } } void GenMailboxCHROMIUM(GLbyte* mailbox) override { @@ -408,4 +366,60 @@ HashMap<GLuint, GLuint> image_to_texture_map_; }; +class DrawingBufferForTests : public DrawingBuffer { + public: + static PassRefPtr<DrawingBufferForTests> Create( + std::unique_ptr<WebGraphicsContext3DProvider> context_provider, + DrawingBuffer::Client* client, + const IntSize& size, + PreserveDrawingBuffer preserve, + UseMultisampling use_multisampling) { + std::unique_ptr<Extensions3DUtil> extensions_util = + Extensions3DUtil::Create(context_provider->ContextGL()); + RefPtr<DrawingBufferForTests> drawing_buffer = + AdoptRef(new DrawingBufferForTests(std::move(context_provider), + std::move(extensions_util), client, + preserve)); + if (!drawing_buffer->Initialize( + size, use_multisampling != kDisableMultisampling)) { + drawing_buffer->BeginDestruction(); + return nullptr; + } + return drawing_buffer.Release(); + } + + DrawingBufferForTests( + std::unique_ptr<WebGraphicsContext3DProvider> context_provider, + std::unique_ptr<Extensions3DUtil> extensions_util, + DrawingBuffer::Client* client, + PreserveDrawingBuffer preserve) + : DrawingBuffer( + std::move(context_provider), + std::move(extensions_util), + client, + false /* discardFramebufferSupported */, + true /* wantAlphaChannel */, + false /* premultipliedAlpha */, + preserve, + kWebGL1, + false /* wantDepth */, + false /* wantStencil */, + DrawingBuffer::kAllowChromiumImage /* ChromiumImageUsage */, + CanvasColorParams()), + live_(0) {} + + ~DrawingBufferForTests() override { + if (live_) + *live_ = false; + } + + GLES2InterfaceForTests* ContextGLForTests() { + return static_cast<GLES2InterfaceForTests*>(ContextGL()); + } + + bool* live_; + + int RecycledBitmapCount() { return recycled_bitmaps_.size(); } +}; + } // blink
diff --git a/third_party/WebKit/Source/web/WebRemoteFrameImpl.cpp b/third_party/WebKit/Source/web/WebRemoteFrameImpl.cpp index 6023efa..a72b4e1 100644 --- a/third_party/WebKit/Source/web/WebRemoteFrameImpl.cpp +++ b/third_party/WebKit/Source/web/WebRemoteFrameImpl.cpp
@@ -92,10 +92,6 @@ return WebVector<WebIconURL>(); } -void WebRemoteFrameImpl::SetCanHaveScrollbars(bool) { - NOTREACHED(); -} - WebSize WebRemoteFrameImpl::GetScrollOffset() const { NOTREACHED(); return WebSize();
diff --git a/third_party/WebKit/Source/web/WebRemoteFrameImpl.h b/third_party/WebKit/Source/web/WebRemoteFrameImpl.h index 5544cee..b8dbf1d 100644 --- a/third_party/WebKit/Source/web/WebRemoteFrameImpl.h +++ b/third_party/WebKit/Source/web/WebRemoteFrameImpl.h
@@ -35,7 +35,6 @@ WebString AssignedName() const override; void SetName(const WebString&) override; WebVector<WebIconURL> IconURLs(int icon_types_mask) const override; - void SetCanHaveScrollbars(bool) override; WebSize GetScrollOffset() const override; void SetScrollOffset(const WebSize&) override; WebSize ContentsSize() const override;
diff --git a/third_party/WebKit/public/platform/UseCounterFeature.def b/third_party/WebKit/public/platform/UseCounterFeature.def index 1fac9d4..2d9b84e 100644 --- a/third_party/WebKit/public/platform/UseCounterFeature.def +++ b/third_party/WebKit/public/platform/UseCounterFeature.def
@@ -1552,7 +1552,8 @@ kCSSRegisterProperty = 2018, kRelativeOrientationSensorConstructor = 2019, kSmoothScrollJSInterventionActivated = 2020, - +kBudgetAPIGetCost = 2021, +kBudgetAPIGetBudget = 2022, // Add new features immediately above this line. Don't change assigned // numbers of any item, and don't reuse removed slots. // Also, run update_use_counter_feature_enum.py in
diff --git a/third_party/WebKit/public/web/WebFrame.h b/third_party/WebKit/public/web/WebFrame.h index 7f244d8..434a862214 100644 --- a/third_party/WebKit/public/web/WebFrame.h +++ b/third_party/WebKit/public/web/WebFrame.h
@@ -160,9 +160,6 @@ // NOTE: These routines do not force page layout so their results may // not be accurate if the page layout is out-of-date. - // If set to false, do not draw scrollbars on this frame's view. - virtual void SetCanHaveScrollbars(bool) = 0; - // The scroll offset from the top-left corner of the frame in pixels. virtual WebSize GetScrollOffset() const = 0; virtual void SetScrollOffset(const WebSize&) = 0;
diff --git a/third_party/WebKit/public/web/WebLocalFrame.h b/third_party/WebKit/public/web/WebLocalFrame.h index 2d01d5b..ead2f68 100644 --- a/third_party/WebKit/public/web/WebLocalFrame.h +++ b/third_party/WebKit/public/web/WebLocalFrame.h
@@ -572,6 +572,11 @@ // frame is attached to a document. virtual std::unique_ptr<WebURLLoader> CreateURLLoader() = 0; + // Geometry ----------------------------------------------------------------- + + // If set to false, do not draw scrollbars on this frame's view. + virtual void SetCanHaveScrollbars(bool) = 0; + protected: explicit WebLocalFrame(WebTreeScopeType scope) : WebFrame(scope) {}
diff --git a/third_party/closure_compiler/externs/accessibility_private.js b/third_party/closure_compiler/externs/accessibility_private.js index 43fd60d8..9efc7c60 100644 --- a/third_party/closure_compiler/externs/accessibility_private.js +++ b/third_party/closure_compiler/externs/accessibility_private.js
@@ -102,6 +102,14 @@ chrome.accessibilityPrivate.darkenScreen = function(enabled) {}; /** + * Change the keyboard keys captured by Switch Access. + * @param {!Array<number>} key_codes The key codes for the keys that will be + * captured. + * @see https://developer.chrome.com/extensions/accessibilityPrivate#method-setSwitchAccessKeys + */ +chrome.accessibilityPrivate.setSwitchAccessKeys = function(key_codes) {}; + +/** * Fired whenever ChromeVox should output introduction. * @type {!ChromeEvent} * @see https://developer.chrome.com/extensions/accessibilityPrivate#event-onIntroduceChromeVox
diff --git a/tools/chrome_proxy/webdriver/lite_page.py b/tools/chrome_proxy/webdriver/lite_page.py index 59b7c40..39b6d43e 100644 --- a/tools/chrome_proxy/webdriver/lite_page.py +++ b/tools/chrome_proxy/webdriver/lite_page.py
@@ -14,26 +14,36 @@ # directive is provided when always-on. def testLitePageForcedExperiment(self): # If it was attempted to run with another experiment, skip this test. + if common.ParseFlags().browser_args and ('--data-reduction-proxy-experiment' + in common.ParseFlags().browser_args): + self.skipTest('This test cannot be run with other experiments.') with TestDriver() as test_driver: test_driver.AddChromeArg('--enable-spdy-proxy-auth') test_driver.AddChromeArg('--data-reduction-proxy-lo-fi=always-on') test_driver.AddChromeArg('--enable-data-reduction-proxy-lite-page') + # Force ECT to be 4G to confirm that we get Lite Page even for fast + # conneciton. + test_driver.AddChromeArg('--force-fieldtrial-params=' + 'NetworkQualityEstimator.Enabled:' + 'force_effective_connection_type/4G') + test_driver.AddChromeArg('--force-fieldtrials=' + 'NetworkQualityEstimator/Enabled/') + test_driver.LoadURL('http://check.googlezip.net/test.html') lite_page_responses = 0 for response in test_driver.GetHTTPResponses(): + # Verify client sends force directive on every request for session. + self.assertIn('exp=force_lite_page', + response.request_headers['chrome-proxy']) + self.assertEqual('4G', response.request_headers['chrome-proxy-ect']) # Skip CSI requests when validating Lite Page headers. CSI requests # aren't expected to have LoFi headers. if '/csi?' in response.url: continue if response.url.startswith('data:'): continue - if not common.ParseFlags().browser_args or ( - '--data-reduction-proxy-experiment' not in - common.ParseFlags().browser_args): - self.assertIn('exp=force_lite_page', - response.request_headers['chrome-proxy']) if (self.checkLitePageResponse(response)): lite_page_responses = lite_page_responses + 1 @@ -44,8 +54,12 @@ # of the page and is able to load all resources. def testLitePageBTF(self): # If it was attempted to run with another experiment, skip this test. + if common.ParseFlags().browser_args and ('--data-reduction-proxy-experiment' + in common.ParseFlags().browser_args): + self.skipTest('This test cannot be run with other experiments.') with TestDriver() as test_driver: test_driver.AddChromeArg('--enable-spdy-proxy-auth') + # Need to force lite page so target page doesn't fallback to Lo-Fi test_driver.AddChromeArg('--data-reduction-proxy-lo-fi=always-on') test_driver.AddChromeArg('--enable-data-reduction-proxy-lite-page') @@ -61,11 +75,6 @@ continue if response.url.startswith('data:'): continue - if not common.ParseFlags().browser_args or ( - '--data-reduction-proxy-experiment' not in - common.ParseFlags().browser_args): - self.assertIn('exp=force_lite_page', - response.request_headers['chrome-proxy']) if (self.checkLitePageResponse(response)): lite_page_responses = lite_page_responses + 1 self.assertEqual(1, lite_page_responses)
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml index 0fcf89a..715c4c6 100644 --- a/tools/metrics/histograms/enums.xml +++ b/tools/metrics/histograms/enums.xml
@@ -1749,6 +1749,232 @@ <int value="17" label="fp05cc03e1"/> </enum> +<enum name="AutofillFieldPredictionQuality" type="int"> + <int value="0" label="True Positive"/> + <int value="1" label="True Negative (Ambiguous)"/> + <int value="2" label="True Negative (Unknown)"/> + <int value="3" label="True Negative (Empty)"/> + <int value="4" label="False Positive (Mismatch)"/> + <int value="5" label="False Positive (Ambiguous)"/> + <int value="6" label="False Positive (Unknown)"/> + <int value="7" label="False Positive (Empty)"/> + <int value="8" label="False Negative (Mismatch)"/> + <int value="9" label="False Negative (Unknown)"/> +</enum> + +<enum name="AutofillFieldPredictionQualityByFieldType" type="int"> + <int value="0" label="Ambiguous: True Positive"/> + <int value="1" label="Ambiguous: True Negative (Ambiguous)"/> + <int value="2" label="Ambiguous: True Negative (Unknown)"/> + <int value="3" label="Ambiguous: True Negative (Empty)"/> + <int value="4" label="Ambiguous: False Positive (Mismatch)"/> + <int value="5" label="Ambiguous: False Positive (Ambiguous)"/> + <int value="6" label="Ambiguous: False Positive (Unknown)"/> + <int value="7" label="Ambiguous: False Positive (Empty)"/> + <int value="8" label="Ambiguous: False Negative (Mismatch)"/> + <int value="9" label="Ambiguous: False Negative (Unknown)"/> + <int value="256" label="Name: True Positive"/> + <int value="257" label="Name: True Negative (Ambiguous)"/> + <int value="258" label="Name: True Negative (Unknown)"/> + <int value="259" label="Name: True Negative (Empty)"/> + <int value="260" label="Name: False Positive (Mismatch)"/> + <int value="261" label="Name: False Positive (Ambiguous)"/> + <int value="262" label="Name: False Positive (Unknown)"/> + <int value="263" label="Name: False Positive (Empty)"/> + <int value="264" label="Name: False Negative (Mismatch)"/> + <int value="265" label="Name: False Negative (Unknown)"/> + <int value="512" label="Company: True Positive"/> + <int value="513" label="Company: True Negative (Ambiguous)"/> + <int value="514" label="Company: True Negative (Unknown)"/> + <int value="515" label="Company: True Negative (Empty)"/> + <int value="516" label="Company: False Positive (Mismatch)"/> + <int value="517" label="Company: False Positive (Ambiguous)"/> + <int value="518" label="Company: False Positive (Unknown)"/> + <int value="519" label="Company: False Positive (Empty)"/> + <int value="520" label="Company: False Negative (Mismatch)"/> + <int value="521" label="Company: False Negative (Unknown)"/> + <int value="768" label="Address Line 1: True Positive"/> + <int value="769" label="Address Line 1: True Negative (Ambiguous)"/> + <int value="770" label="Address Line 1: True Negative (Unknown)"/> + <int value="771" label="Address Line 1: True Negative (Empty)"/> + <int value="772" label="Address Line 1: False Positive (Mismatch)"/> + <int value="773" label="Address Line 1: False Positive (Ambiguous)"/> + <int value="774" label="Address Line 1: False Positive (Unknown)"/> + <int value="775" label="Address Line 1: False Positive (Empty)"/> + <int value="776" label="Address Line 1: False Negative (Mismatch)"/> + <int value="777" label="Address Line 1: False Negative (Unknown)"/> + <int value="1024" label="Address Line 2: True Positive"/> + <int value="1025" label="Address Line 2: True Negative (Ambiguous)"/> + <int value="1026" label="Address Line 2: True Negative (Unknown)"/> + <int value="1027" label="Address Line 2: True Negative (Empty)"/> + <int value="1028" label="Address Line 2: False Positive (Mismatch)"/> + <int value="1029" label="Address Line 2: False Positive (Ambiguous)"/> + <int value="1030" label="Address Line 2: False Positive (Unknown)"/> + <int value="1031" label="Address Line 2: False Positive (Empty)"/> + <int value="1032" label="Address Line 2: False Negative (Mismatch)"/> + <int value="1033" label="Address Line 2: False Negative (Unknown)"/> + <int value="1280" label="City: True Positive"/> + <int value="1281" label="City: True Negative (Ambiguous)"/> + <int value="1282" label="City: True Negative (Unknown)"/> + <int value="1283" label="City: True Negative (Empty)"/> + <int value="1284" label="City: False Positive (Mismatch)"/> + <int value="1285" label="City: False Positive (Ambiguous)"/> + <int value="1286" label="City: False Positive (Unknown)"/> + <int value="1287" label="City: False Positive (Empty)"/> + <int value="1288" label="City: False Negative (Mismatch)"/> + <int value="1289" label="City: False Negative (Unknown)"/> + <int value="1536" label="State: True Positive"/> + <int value="1537" label="State: True Negative (Ambiguous)"/> + <int value="1538" label="State: True Negative (Unknown)"/> + <int value="1539" label="State: True Negative (Empty)"/> + <int value="1540" label="State: False Positive (Mismatch)"/> + <int value="1541" label="State: False Positive (Ambiguous)"/> + <int value="1542" label="State: False Positive (Unknown)"/> + <int value="1543" label="State: False Positive (Empty)"/> + <int value="1544" label="State: False Negative (Mismatch)"/> + <int value="1545" label="State: False Negative (Unknown)"/> + <int value="1792" label="ZIP: True Positive"/> + <int value="1793" label="ZIP: True Negative (Ambiguous)"/> + <int value="1794" label="ZIP: True Negative (Unknown)"/> + <int value="1795" label="ZIP: True Negative (Empty)"/> + <int value="1796" label="ZIP: False Positive (Mismatch)"/> + <int value="1797" label="ZIP: False Positive (Ambiguous)"/> + <int value="1798" label="ZIP: False Positive (Unknown)"/> + <int value="1799" label="ZIP: False Positive (Empty)"/> + <int value="1800" label="ZIP: False Negative (Mismatch)"/> + <int value="1801" label="ZIP: False Negative (Unknown)"/> + <int value="2048" label="Country: True Positive"/> + <int value="2049" label="Country: True Negative (Ambiguous)"/> + <int value="2050" label="Country: True Negative (Unknown)"/> + <int value="2051" label="Country: True Negative (Empty)"/> + <int value="2052" label="Country: False Positive (Mismatch)"/> + <int value="2053" label="Country: False Positive (Ambiguous)"/> + <int value="2054" label="Country: False Positive (Unknown)"/> + <int value="2055" label="Country: False Positive (Empty)"/> + <int value="2056" label="Country: False Negative (Mismatch)"/> + <int value="2057" label="Country: False Negative (Unknown)"/> + <int value="2304" label="Phone: True Positive"/> + <int value="2305" label="Phone: True Negative (Ambiguous)"/> + <int value="2306" label="Phone: True Negative (Unknown)"/> + <int value="2307" label="Phone: True Negative (Empty)"/> + <int value="2308" label="Phone: False Positive (Mismatch)"/> + <int value="2309" label="Phone: False Positive (Ambiguous)"/> + <int value="2310" label="Phone: False Positive (Unknown)"/> + <int value="2311" label="Phone: False Positive (Empty)"/> + <int value="2312" label="Phone: False Negative (Mismatch)"/> + <int value="2313" label="Phone: False Negative (Unknown)"/> + <int value="2560" label="Fax: True Positive"/> + <int value="2561" label="Fax: True Negative (Ambiguous)"/> + <int value="2562" label="Fax: True Negative (Unknown)"/> + <int value="2563" label="Fax: True Negative (Empty)"/> + <int value="2564" label="Fax: False Positive (Mismatch)"/> + <int value="2565" label="Fax: False Positive (Ambiguous)"/> + <int value="2566" label="Fax: False Positive (Unknown)"/> + <int value="2567" label="Fax: False Positive (Empty)"/> + <int value="2568" label="Fax: False Negative (Mismatch)"/> + <int value="2569" label="Fax: False Negative (Unknown)"/> + <int value="2816" label="Email: True Positive"/> + <int value="2817" label="Email: True Negative (Ambiguous)"/> + <int value="2818" label="Email: True Negative (Unknown)"/> + <int value="2819" label="Email: True Negative (Empty)"/> + <int value="2820" label="Email: False Positive (Mismatch)"/> + <int value="2821" label="Email: False Positive (Ambiguous)"/> + <int value="2822" label="Email: False Positive (Unknown)"/> + <int value="2823" label="Email: False Positive (Empty)"/> + <int value="2824" label="Email: False Negative (Mismatch)"/> + <int value="2825" label="Email: False Negative (Unknown)"/> + <int value="3072" label="CC Name: True Positive"/> + <int value="3073" label="CC Name: True Negative (Ambiguous)"/> + <int value="3074" label="CC Name: True Negative (Unknown)"/> + <int value="3075" label="CC Name: True Negative (Empty)"/> + <int value="3076" label="CC Name: False Positive (Mismatch)"/> + <int value="3077" label="CC Name: False Positive (Ambiguous)"/> + <int value="3078" label="CC Name: False Positive (Unknown)"/> + <int value="3079" label="CC Name: False Positive (Empty)"/> + <int value="3080" label="CC Name: False Negative (Mismatch)"/> + <int value="3081" label="CC Name: False Negative (Unknown)"/> + <int value="3328" label="CC Number: True Positive"/> + <int value="3329" label="CC Number: True Negative (Ambiguous)"/> + <int value="3330" label="CC Number: True Negative (Unknown)"/> + <int value="3331" label="CC Number: True Negative (Empty)"/> + <int value="3332" label="CC Number: False Positive (Mismatch)"/> + <int value="3333" label="CC Number: False Positive (Ambiguous)"/> + <int value="3334" label="CC Number: False Positive (Unknown)"/> + <int value="3335" label="CC Number: False Positive (Empty)"/> + <int value="3336" label="CC Number: False Negative (Mismatch)"/> + <int value="3337" label="CC Number: False Negative (Unknown)"/> + <int value="3584" label="CC Expiry: True Positive"/> + <int value="3585" label="CC Expiry: True Negative (Ambiguous)"/> + <int value="3586" label="CC Expiry: True Negative (Unknown)"/> + <int value="3587" label="CC Expiry: True Negative (Empty)"/> + <int value="3588" label="CC Expiry: False Positive (Mismatch)"/> + <int value="3589" label="CC Expiry: False Positive (Ambiguous)"/> + <int value="3590" label="CC Expiry: False Positive (Unknown)"/> + <int value="3591" label="CC Expiry: False Positive (Empty)"/> + <int value="3592" label="CC Expiry: False Negative (Mismatch)"/> + <int value="3593" label="CC Expiry: False Negative (Unknown)"/> + <int value="3840" label="CC Type: True Positive"/> + <int value="3841" label="CC Type: True Negative (Ambiguous)"/> + <int value="3842" label="CC Type: True Negative (Unknown)"/> + <int value="3843" label="CC Type: True Negative (Empty)"/> + <int value="3844" label="CC Type: False Positive (Mismatch)"/> + <int value="3845" label="CC Type: False Positive (Ambiguous)"/> + <int value="3846" label="CC Type: False Positive (Unknown)"/> + <int value="3847" label="CC Type: False Positive (Empty)"/> + <int value="3848" label="CC Type: False Negative (Mismatch)"/> + <int value="3849" label="CC Type: False Negative (Unknown)"/> + <int value="4096" label="Password: True Positive"/> + <int value="4097" label="Password: True Negative (Ambiguous)"/> + <int value="4098" label="Password: True Negative (Unknown)"/> + <int value="4099" label="Password: True Negative (Empty)"/> + <int value="4100" label="Password: False Positive (Mismatch)"/> + <int value="4101" label="Password: False Positive (Ambiguous)"/> + <int value="4102" label="Password: False Positive (Unknown)"/> + <int value="4103" label="Password: False Positive (Empty)"/> + <int value="4104" label="Password: False Negative (Mismatch)"/> + <int value="4105" label="Password: False Negative (Unknown)"/> + <int value="4352" label="Address Line 3: True Positive"/> + <int value="4353" label="Address Line 3: True Negative (Ambiguous)"/> + <int value="4354" label="Address Line 3: True Negative (Unknown)"/> + <int value="4355" label="Address Line 3: True Negative (Empty)"/> + <int value="4356" label="Address Line 3: False Positive (Mismatch)"/> + <int value="4357" label="Address Line 3: False Positive (Ambiguous)"/> + <int value="4358" label="Address Line 3: False Positive (Unknown)"/> + <int value="4359" label="Address Line 3: False Positive (Empty)"/> + <int value="4360" label="Address Line 3: False Negative (Mismatch)"/> + <int value="4361" label="Address Line 3: False Negative (Unknown)"/> + <int value="4608" label="Username: True Positive"/> + <int value="4609" label="Username: True Negative (Ambiguous)"/> + <int value="4610" label="Username: True Negative (Unknown)"/> + <int value="4611" label="Username: True Negative (Empty)"/> + <int value="4612" label="Username: False Positive (Mismatch)"/> + <int value="4613" label="Username: False Positive (Ambiguous)"/> + <int value="4614" label="Username: False Positive (Unknown)"/> + <int value="4615" label="Username: False Positive (Empty)"/> + <int value="4616" label="Username: False Negative (Mismatch)"/> + <int value="4617" label="Username: False Negative (Unknown)"/> + <int value="4864" label="Street Address: True Positive"/> + <int value="4865" label="Street Address: True Negative (Ambiguous)"/> + <int value="4866" label="Street Address: True Negative (Unknown)"/> + <int value="4867" label="Street Address: True Negative (Empty)"/> + <int value="4868" label="Street Address: False Positive (Mismatch)"/> + <int value="4869" label="Street Address: False Positive (Ambiguous)"/> + <int value="4870" label="Street Address: False Positive (Unknown)"/> + <int value="4871" label="Street Address: False Positive (Empty)"/> + <int value="4872" label="Street Address: False Negative (Mismatch)"/> + <int value="4873" label="Street Address: False Negative (Unknown)"/> + <int value="5120" label="CVC: True Positive"/> + <int value="5121" label="CVC: True Negative (Ambiguous)"/> + <int value="5122" label="CVC: True Negative (Unknown)"/> + <int value="5123" label="CVC: True Negative (Empty)"/> + <int value="5124" label="CVC: False Positive (Mismatch)"/> + <int value="5125" label="CVC: False Positive (Ambiguous)"/> + <int value="5126" label="CVC: False Positive (Unknown)"/> + <int value="5127" label="CVC: False Positive (Empty)"/> + <int value="5128" label="CVC: False Negative (Mismatch)"/> + <int value="5129" label="CVC: False Negative (Unknown)"/> +</enum> + <enum name="AutofillFormEvent" type="int"> <int value="0" label="Interacted (once)"/> <int value="1" label="Suggestions shown"/> @@ -12422,6 +12648,7 @@ <int value="1175" label="MEDIAPERCEPTIONPRIVATE_SETSTATE"/> <int value="1176" label="MEDIAPERCEPTIONPRIVATE_GETDIAGNOSTICS"/> <int value="1177" label="NETWORKINGPRIVATE_GETCERTIFICATELISTS"/> + <int value="1178" label="ACCESSIBILITY_PRIVATE_SETSWITCHACCESSKEYS"/> </enum> <enum name="ExtensionIconState" type="int"> @@ -15135,6 +15362,8 @@ <int value="2018" label="CSSRegisterProperty"/> <int value="2019" label="RelativeOrientationSensorConstructor"/> <int value="2020" label="SmoothScrollJSInterventionActivated"/> + <int value="2021" label="BudgetAPIGetCost"/> + <int value="2022" label="BudgetAPIGetBudget"/> </enum> <enum name="FeedbackSource" type="int">
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml index 2970b8f..9bbb211 100644 --- a/tools/metrics/histograms/histograms.xml +++ b/tools/metrics/histograms/histograms.xml
@@ -3880,6 +3880,44 @@ </summary> </histogram> +<histogram name="Autofill.FieldPrediction"> +<!-- Name completed by histogram_suffixes + name="AutofillFieldPredictionSource" --> + + <owner>rogerm@chromium.org</owner> + <summary> + Predicted and actual form field type. This is a computed sparse histogram + where the value is ((predicted << 16)| actual). Predicted and actual + are taken from the autofill::ServerFieldType enumeration. + </summary> +</histogram> + +<histogram name="Autofill.FieldPredictionQuality.Aggregate" + enum="AutofillFieldPredictionQuality"> +<!-- Name completed by histogram_suffixes + name="AutofillFieldPredictionSource" --> + + <owner>rogerm@chromium.org</owner> + <summary> + Aggregate Autofill field-type prediction outcomes. See + https://en.wikipedia.org/wiki/Confusion_matrix for an explanation of the + values. + </summary> +</histogram> + +<histogram name="Autofill.FieldPredictionQuality.ByFieldType" + enum="AutofillFieldPredictionQualityByFieldType"> +<!-- Name completed by histogram_suffixes + name="AutofillFieldPredictionSource" --> + + <owner>rogerm@chromium.org</owner> + <summary> + Autofill field-type prediction outcomes, broken down by field type. See + https://en.wikipedia.org/wiki/Confusion_matrix for an explanation of the + values. + </summary> +</histogram> + <histogram name="Autofill.FillDuration.FromInteraction.WithAutofill"> <owner>isherman@chromium.org</owner> <summary> @@ -4206,12 +4244,20 @@ </histogram> <histogram name="Autofill.Quality.HeuristicType" enum="AutofillTypeQuality"> + <obsolete> + Deprecated as of 6/2017, replaced by + Autofill.FieldPredictionQuality.Aggregate.Heuristic. + </obsolete> <owner>isherman@chromium.org</owner> <summary>The quality of Autofill's heuristic field type detection.</summary> </histogram> <histogram name="Autofill.Quality.HeuristicType.ByFieldType" enum="AutofillTypeQualityByFieldType"> + <obsolete> + Deprecated as of 6/2017, replaced by + Autofill.FieldPredictionQuality.ByFieldType.Heuristic. + </obsolete> <owner>isherman@chromium.org</owner> <summary> The quality of Autofill's heuristic field type detection, broken down by the @@ -4221,12 +4267,20 @@ </histogram> <histogram name="Autofill.Quality.PredictedType" enum="AutofillTypeQuality"> + <obsolete> + Deprecated as of 6/2017, replaced by + Autofill.FieldPredictionQuality.Aggregate.Overall. + </obsolete> <owner>isherman@chromium.org</owner> <summary>The overall quality of the Autofill field type predictions.</summary> </histogram> <histogram name="Autofill.Quality.PredictedType.ByFieldType" enum="AutofillTypeQualityByFieldType"> + <obsolete> + Deprecated as of 6/2017, replaced by + Autofill.FieldPredictionQuality.ByFieldType.Overall. + </obsolete> <owner>isherman@chromium.org</owner> <summary> The overall quality of the Autofill field type predictions, broken down by @@ -4236,12 +4290,20 @@ </histogram> <histogram name="Autofill.Quality.ServerType" enum="AutofillTypeQuality"> + <obsolete> + Deprecated as of 6/2017, replaced by + Autofill.FieldPredictionQuality.Aggregate.Server. + </obsolete> <owner>isherman@chromium.org</owner> <summary>The quality of the Autofill server's field type detection.</summary> </histogram> <histogram name="Autofill.Quality.ServerType.ByFieldType" enum="AutofillTypeQualityByFieldType"> + <obsolete> + Deprecated as of 6/2017, replaced by + Autofill.FieldPredictionQuality.ByFieldType.Server. + </obsolete> <owner>isherman@chromium.org</owner> <summary> The quality of the Autofill server's field type detection, broken down by @@ -85771,6 +85833,20 @@ <affected-histogram name="Autofill.FormEvents.CreditCard"/> </histogram_suffixes> +<histogram_suffixes name="AutofillFieldPredictionSource" separator="."> + <suffix name="Heuristic" + label="Field type predictions using local heuristics."/> + <suffix name="Server" + label="Field types based on crowd-sourced prediction fetched from the + Autofill Server"/> + <suffix name="Overall" + label="Field type prediction as seen by the user after combining the + heuristic and crowd sourced predictions."/> + <affected-histogram name="Autofill.FieldPrediction"/> + <affected-histogram name="Autofill.FieldPredictionQuality.Aggregate"/> + <affected-histogram name="Autofill.FieldPredictionQuality.ByFieldType"/> +</histogram_suffixes> + <histogram_suffixes name="AutofillPayloadCompressionType" separator="."> <suffix name="Query" label="Query request compression"/> <suffix name="Upload" label="Upload request compression"/> @@ -87803,6 +87879,19 @@ <suffix name="NoSubmission" label="No observed submission."/> <suffix name="BasedOnAutocomplete" label="Quality metrics based on autocomplete attributes."/> + <affected-histogram name="Autofill.FieldPrediction.Heuristic"/> + <affected-histogram name="Autofill.FieldPrediction.Overall"/> + <affected-histogram name="Autofill.FieldPrediction.Server"/> + <affected-histogram + name="Autofill.FieldPredictionQuality.Aggregate.Heuristic"/> + <affected-histogram name="Autofill.FieldPredictionQuality.Aggregate.Overall"/> + <affected-histogram name="Autofill.FieldPredictionQuality.Aggregate.Server"/> + <affected-histogram + name="Autofill.FieldPredictionQuality.ByFieldType.Heuristic"/> + <affected-histogram + name="Autofill.FieldPredictionQuality.ByFieldType.Overall"/> + <affected-histogram + name="Autofill.FieldPredictionQuality.ByFieldType.Server"/> <affected-histogram name="Autofill.NumberOfEditedAutofilledFieldsAtSubmission"/> <affected-histogram name="Autofill.Quality.HeuristicType"/>
diff --git a/tools/perf/benchmarks/kraken.py b/tools/perf/benchmarks/kraken.py index 1715f62..df0fcda3 100644 --- a/tools/perf/benchmarks/kraken.py +++ b/tools/perf/benchmarks/kraken.py
@@ -132,10 +132,12 @@ ps = story.StorySet( archive_data_file='../page_sets/data/kraken.json', base_dir=os.path.dirname(os.path.abspath(__file__)), - cloud_storage_bucket=story.PARTNER_BUCKET) + cloud_storage_bucket=story.PARTNER_BUCKET, + verify_names=True) ps.AddStory(page_module.Page( 'http://krakenbenchmark.mozilla.org/kraken-1.1/driver.html', - ps, ps.base_dir)) + ps, ps.base_dir, + name='http://krakenbenchmark.mozilla.org/kraken-1.1/driver.html')) return ps @classmethod
diff --git a/ui/app_list/app_list_model.cc b/ui/app_list/app_list_model.cc index 6ee9d525..f7653e1 100644 --- a/ui/app_list/app_list_model.cc +++ b/ui/app_list/app_list_model.cc
@@ -364,11 +364,6 @@ observer.OnSearchEngineIsGoogleChanged(is_google); } -void AppListModel::SetSearchAnswerAvailable(bool has_answer) { - for (auto& observer : observers_) - observer.OnSearchAnswerAvailableChanged(has_answer); -} - // Private methods void AppListModel::OnListItemMoved(size_t from_index,
diff --git a/ui/app_list/app_list_model.h b/ui/app_list/app_list_model.h index 2a413e7..1d0644a7 100644 --- a/ui/app_list/app_list_model.h +++ b/ui/app_list/app_list_model.h
@@ -166,8 +166,6 @@ void SetSearchEngineIsGoogle(bool is_google); bool search_engine_is_google() const { return search_engine_is_google_; } - void SetSearchAnswerAvailable(bool has_answer); - // Filters the given |results| by |display_type|. The returned list is // truncated to |max_results|. static std::vector<SearchResult*> FilterSearchResultsByDisplayType(
diff --git a/ui/app_list/app_list_model_observer.h b/ui/app_list/app_list_model_observer.h index fafa2c3..09cccc0 100644 --- a/ui/app_list/app_list_model_observer.h +++ b/ui/app_list/app_list_model_observer.h
@@ -39,9 +39,6 @@ // Triggered when the search engine is changed to and from Google. virtual void OnSearchEngineIsGoogleChanged(bool is_google) {} - // Triggered when the availability of the search answer is changed. - virtual void OnSearchAnswerAvailableChanged(bool has_answer) {} - protected: virtual ~AppListModelObserver() {} };
diff --git a/ui/app_list/app_list_view_delegate.h b/ui/app_list/app_list_view_delegate.h index 9bdf665..3d61cb1 100644 --- a/ui/app_list/app_list_view_delegate.h +++ b/ui/app_list/app_list_view_delegate.h
@@ -83,10 +83,6 @@ virtual std::vector<views::View*> CreateCustomPageWebViews( const gfx::Size& size) = 0; - // Gets the web view for the search answer. The caller doesn't take the - // ownership of the returned view. - virtual views::View* GetSearchAnswerWebView() = 0; - // Invoked when the custom launcher page's animation changes. virtual void CustomLauncherPageAnimationChanged(double progress) = 0;
diff --git a/ui/app_list/search_result.cc b/ui/app_list/search_result.cc index 63862ef..e9f1756 100644 --- a/ui/app_list/search_result.cc +++ b/ui/app_list/search_result.cc
@@ -89,6 +89,7 @@ case DISPLAY_LIST: return kListIconSize; case DISPLAY_NONE: + case DISPLAY_CARD: return 0; case DISPLAY_TYPE_LAST: break;
diff --git a/ui/app_list/search_result.h b/ui/app_list/search_result.h index a3b8fec..d721c7e 100644 --- a/ui/app_list/search_result.h +++ b/ui/app_list/search_result.h
@@ -21,6 +21,10 @@ class MenuModel; } +namespace views { +class View; +} + namespace app_list { class SearchResultObserver; @@ -39,6 +43,7 @@ DISPLAY_LIST, DISPLAY_TILE, DISPLAY_RECOMMENDATION, + DISPLAY_CARD, // Add new values here. DISPLAY_TYPE_LAST, @@ -108,6 +113,9 @@ const Tags& details_tags() const { return details_tags_; } void set_details_tags(const Tags& tags) { details_tags_ = tags; } + views::View* view() const { return view_; } + void set_view(views::View* view) { view_ = view; } + const std::string& id() const { return id_; } double relevance() const { return relevance_; } @@ -187,6 +195,12 @@ base::string16 details_; Tags details_tags_; + // Unowned pointer to a view containing a rendered result, or nullptr if there + // is no such view for the result. + // The view has set_owned_by_client() property set. It's a responsibility of + // SearchProvider to set this property and own this view. + views::View* view_ = nullptr; + std::string id_; double relevance_; DisplayType display_type_;
diff --git a/ui/app_list/test/app_list_test_view_delegate.cc b/ui/app_list/test/app_list_test_view_delegate.cc index efef3e22..9202127b 100644 --- a/ui/app_list/test/app_list_test_view_delegate.cc +++ b/ui/app_list/test/app_list_test_view_delegate.cc
@@ -80,10 +80,6 @@ return std::vector<views::View*>(); } -views::View* AppListTestViewDelegate::GetSearchAnswerWebView() { - return nullptr; -} - bool AppListTestViewDelegate::IsSpeechRecognitionEnabled() { return false; }
diff --git a/ui/app_list/test/app_list_test_view_delegate.h b/ui/app_list/test/app_list_test_view_delegate.h index 1d4c242..5cafa04f 100644 --- a/ui/app_list/test/app_list_test_view_delegate.h +++ b/ui/app_list/test/app_list_test_view_delegate.h
@@ -68,7 +68,6 @@ views::View* CreateStartPageWebView(const gfx::Size& size) override; std::vector<views::View*> CreateCustomPageWebViews( const gfx::Size& size) override; - views::View* GetSearchAnswerWebView() override; void CustomLauncherPageAnimationChanged(double progress) override {} void CustomLauncherPagePopSubpage() override {} bool IsSpeechRecognitionEnabled() override;
diff --git a/ui/app_list/views/contents_view.cc b/ui/app_list/views/contents_view.cc index bb8218b..9a3a73b7 100644 --- a/ui/app_list/views/contents_view.cc +++ b/ui/app_list/views/contents_view.cc
@@ -9,6 +9,7 @@ #include "base/logging.h" #include "ui/app_list/app_list_constants.h" +#include "ui/app_list/app_list_features.h" #include "ui/app_list/app_list_switches.h" #include "ui/app_list/app_list_view_delegate.h" #include "ui/app_list/views/app_list_folder_view.h" @@ -70,15 +71,13 @@ search_results_page_view_ = new SearchResultPageView(); // Search result containers. - views::View* const search_answer_view = - view_delegate->GetSearchAnswerWebView(); - if (search_answer_view) { + AppListModel::SearchResults* results = view_delegate->GetModel()->results(); + + if (features::IsAnswerCardEnabled()) { search_results_page_view_->AddSearchResultContainerView( - nullptr, new SearchResultAnswerCardView( - model_, search_results_page_view_, search_answer_view)); + results, new SearchResultAnswerCardView(view_delegate)); } - AppListModel::SearchResults* results = view_delegate->GetModel()->results(); search_results_page_view_->AddSearchResultContainerView( results, new SearchResultListView(app_list_main_view_, view_delegate));
diff --git a/ui/app_list/views/search_result_answer_card_view.cc b/ui/app_list/views/search_result_answer_card_view.cc index 43ac790..3e36ba06 100644 --- a/ui/app_list/views/search_result_answer_card_view.cc +++ b/ui/app_list/views/search_result_answer_card_view.cc
@@ -6,7 +6,7 @@ #include "ui/app_list/app_list_constants.h" #include "ui/app_list/app_list_features.h" -#include "ui/app_list/views/search_result_page_view.h" +#include "ui/app_list/app_list_view_delegate.h" #include "ui/views/background.h" #include "ui/views/controls/button/custom_button.h" #include "ui/views/layout/box_layout.h" @@ -14,26 +14,20 @@ namespace app_list { -namespace { - -// Answer card relevance is high to always have it first. -constexpr double kSearchAnswerCardRelevance = 100; - -} // namespace - // Container of the search answer view. class SearchResultAnswerCardView::SearchAnswerContainerView - : public views::CustomButton { + : public views::CustomButton, + public views::ButtonListener { public: - explicit SearchAnswerContainerView(views::View* search_results_page_view) - : CustomButton(nullptr), - search_results_page_view_(search_results_page_view) { + explicit SearchAnswerContainerView(AppListViewDelegate* view_delegate) + : CustomButton(this), view_delegate_(view_delegate) { // Center the card horizontally in the container. views::BoxLayout* answer_container_layout = new views::BoxLayout(views::BoxLayout::kHorizontal, 0, 0, 0); answer_container_layout->set_main_axis_alignment( views::BoxLayout::MAIN_AXIS_ALIGNMENT_CENTER); SetLayoutManager(answer_container_layout); + SetVisible(false); } void SetSelected(bool selected) { @@ -43,23 +37,38 @@ UpdateBackgroundColor(); } + void SetSearchResult(SearchResult* search_result) { + views::View* const old_result_view = child_count() ? child_at(0) : nullptr; + views::View* const new_result_view = + search_result ? search_result->view() : nullptr; + + if (old_result_view != new_result_view) { + if (old_result_view != nullptr) + RemoveChildView(old_result_view); + if (new_result_view != nullptr) + AddChildView(new_result_view); + } + + search_result_ = search_result ? search_result->Duplicate() : nullptr; + + SetVisible(new_result_view != nullptr); + } + // views::CustomButton overrides: - void ChildPreferredSizeChanged(View* child) override { - // Card size changed. - if (visible()) - search_results_page_view_->Layout(); - } - - int GetHeightForWidth(int w) const override { - return visible() ? CustomButton::GetHeightForWidth(w) : 0; - } - const char* GetClassName() const override { return "SearchAnswerContainerView"; } void StateChanged(ButtonState old_state) override { UpdateBackgroundColor(); } + // views::ButtonListener overrides: + void ButtonPressed(views::Button* sender, const ui::Event& event) override { + DCHECK(sender == this); + DCHECK(search_result_); + view_delegate_->OpenSearchResult(search_result_.get(), false, + event.flags()); + } + private: void UpdateBackgroundColor() { if (selected_) @@ -70,29 +79,22 @@ SchedulePaint(); } - views::View* const search_results_page_view_; + AppListViewDelegate* const view_delegate_; // Not owned. bool selected_ = false; + std::unique_ptr<SearchResult> search_result_; DISALLOW_COPY_AND_ASSIGN(SearchAnswerContainerView); }; SearchResultAnswerCardView::SearchResultAnswerCardView( - AppListModel* model, - SearchResultPageView* search_results_page_view, - views::View* search_answer_view) - : model_(model), - search_answer_container_view_( - new SearchAnswerContainerView(search_results_page_view)) { - search_answer_container_view_->SetVisible(false); - search_answer_container_view_->AddChildView(search_answer_view); + AppListViewDelegate* view_delegate) + : search_answer_container_view_( + new SearchAnswerContainerView(view_delegate)) { AddChildView(search_answer_container_view_); - model->AddObserver(this); SetLayoutManager(new views::FillLayout); } -SearchResultAnswerCardView::~SearchResultAnswerCardView() { - model_->RemoveObserver(this); -} +SearchResultAnswerCardView::~SearchResultAnswerCardView() {} const char* SearchResultAnswerCardView::GetClassName() const { return "SearchResultAnswerCardView"; @@ -112,8 +114,17 @@ } int SearchResultAnswerCardView::DoUpdate() { - const bool have_result = search_answer_container_view_->visible(); - set_container_score(have_result ? kSearchAnswerCardRelevance : 0); + std::vector<SearchResult*> display_results = + AppListModel::FilterSearchResultsByDisplayType( + results(), SearchResult::DISPLAY_CARD, 1); + + const bool have_result = + !display_results.empty() && !features::IsAnswerCardDarkRunEnabled(); + + search_answer_container_view_->SetSearchResult( + have_result ? display_results[0] : nullptr); + + set_container_score(have_result ? display_results.front()->relevance() : 0); return have_result ? 1 : 0; } @@ -128,14 +139,13 @@ NotifyAccessibilityEvent(ui::AX_EVENT_SELECTION, true); } -void SearchResultAnswerCardView::OnSearchAnswerAvailableChanged( - bool has_answer) { - const bool visible = has_answer && !features::IsAnswerCardDarkRunEnabled(); - if (visible == search_answer_container_view_->visible()) - return; +bool SearchResultAnswerCardView::OnKeyPressed(const ui::KeyEvent& event) { + if (selected_index() == 0 && + search_answer_container_view_->OnKeyPressed(event)) { + return true; + } - search_answer_container_view_->SetVisible(visible); - ScheduleUpdate(); + return SearchResultContainerView::OnKeyPressed(event); } } // namespace app_list
diff --git a/ui/app_list/views/search_result_answer_card_view.h b/ui/app_list/views/search_result_answer_card_view.h index 745b5fad..80ad1c8 100644 --- a/ui/app_list/views/search_result_answer_card_view.h +++ b/ui/app_list/views/search_result_answer_card_view.h
@@ -5,22 +5,17 @@ #ifndef UI_APP_LIST_VIEWS_SEARCH_RESULT_ANSWER_CARD_VIEW_H_ #define UI_APP_LIST_VIEWS_SEARCH_RESULT_ANSWER_CARD_VIEW_H_ -#include "ui/app_list/app_list_model_observer.h" #include "ui/app_list/views/search_result_container_view.h" namespace app_list { -class AppListModel; -class SearchResultPageView; +class AppListViewDelegate; // Result container for the search answer card. class APP_LIST_EXPORT SearchResultAnswerCardView - : public SearchResultContainerView, - public AppListModelObserver { + : public SearchResultContainerView { public: - SearchResultAnswerCardView(AppListModel* model, - SearchResultPageView* search_results_page_view, - views::View* search_answer_view); + explicit SearchResultAnswerCardView(AppListViewDelegate* view_delegate); ~SearchResultAnswerCardView() override; private: @@ -36,12 +31,7 @@ int GetYSize() override; int DoUpdate() override; void UpdateSelectedIndex(int old_selected, int new_selected) override; - - // Overridden from AppListModelObserver - void OnSearchAnswerAvailableChanged(bool has_answer) override; - - // Unowned pointer to application list model. - AppListModel* const model_; + bool OnKeyPressed(const ui::KeyEvent& event) override; // Pointer to the container of the search answer; owned by the view hierarchy. // It's visible iff we have a search answer result.
diff --git a/ui/app_list/views/search_result_container_view.h b/ui/app_list/views/search_result_container_view.h index 19c02c13..b5f8496 100644 --- a/ui/app_list/views/search_result_container_view.h +++ b/ui/app_list/views/search_result_container_view.h
@@ -84,12 +84,11 @@ virtual void OnContainerSelected(bool from_bottom, bool directional_movement) = 0; - protected: + private: // Schedules an Update call using |update_factory_|. Do nothing if there is a // pending call. void ScheduleUpdate(); - private: // Updates UI with model. Returns the number of visible results. virtual int DoUpdate() = 0;
diff --git a/ui/aura/mus/window_tree_client.cc b/ui/aura/mus/window_tree_client.cc index 89481a1..7987464 100644 --- a/ui/aura/mus/window_tree_client.cc +++ b/ui/aura/mus/window_tree_client.cc
@@ -2000,6 +2000,16 @@ WindowMus::Get(window_tree_host->window())->server_id()); } +void WindowTreeClient::OnWindowTreeHostMoveCursorToDisplayLocation( + const gfx::Point& location_in_pixels, + int64_t display_id) { + DCHECK(window_manager_client_); + if (window_manager_client_) { + window_manager_client_->WmMoveCursorToDisplayLocation(location_in_pixels, + display_id); + } +} + std::unique_ptr<WindowPortMus> WindowTreeClient::CreateWindowPortForTopLevel( const std::map<std::string, std::vector<uint8_t>>* properties) { std::unique_ptr<WindowPortMus> window_port =
diff --git a/ui/aura/mus/window_tree_client.h b/ui/aura/mus/window_tree_client.h index a297e32..44f3f3a 100644 --- a/ui/aura/mus/window_tree_client.h +++ b/ui/aura/mus/window_tree_client.h
@@ -515,6 +515,9 @@ const base::Callback<void(bool)>& callback) override; void OnWindowTreeHostCancelWindowMove( WindowTreeHostMus* window_tree_host) override; + void OnWindowTreeHostMoveCursorToDisplayLocation( + const gfx::Point& location_in_pixels, + int64_t display_id) override; std::unique_ptr<WindowPortMus> CreateWindowPortForTopLevel( const std::map<std::string, std::vector<uint8_t>>* properties) override; void OnWindowTreeHostCreated(WindowTreeHostMus* window_tree_host) override;
diff --git a/ui/aura/mus/window_tree_host_mus.cc b/ui/aura/mus/window_tree_host_mus.cc index 85cdf6a4d..5e60905 100644 --- a/ui/aura/mus/window_tree_host_mus.cc +++ b/ui/aura/mus/window_tree_host_mus.cc
@@ -200,10 +200,12 @@ void WindowTreeHostMus::MoveCursorToScreenLocationInPixels( const gfx::Point& location_in_pixels) { - // TODO: this needs to message the server http://crbug.com/693340. Setting - // the location is really only appropriate in tests, outside of tests this - // value is ignored. - NOTIMPLEMENTED(); + gfx::Point screen_location_in_pixels = location_in_pixels; + gfx::Point location = GetLocationOnScreenInPixels(); + screen_location_in_pixels.Offset(-location.x(), -location.y()); + delegate_->OnWindowTreeHostMoveCursorToDisplayLocation( + screen_location_in_pixels, display_id_); + Env::GetInstance()->set_last_mouse_location(location_in_pixels); }
diff --git a/ui/aura/mus/window_tree_host_mus_delegate.h b/ui/aura/mus/window_tree_host_mus_delegate.h index b93c6598..4ea7c2bf 100644 --- a/ui/aura/mus/window_tree_host_mus_delegate.h +++ b/ui/aura/mus/window_tree_host_mus_delegate.h
@@ -71,6 +71,11 @@ virtual void OnWindowTreeHostCancelWindowMove( WindowTreeHostMus* window_tree_host) = 0; + // Called to move the location of the cursor. + virtual void OnWindowTreeHostMoveCursorToDisplayLocation( + const gfx::Point& location_in_pixels, + int64_t display_id) = 0; + // Called when a WindowTreeHostMus is created without a WindowPort. // TODO: this should take an unordered_map, see http://crbug.com/670515. virtual std::unique_ptr<WindowPortMus> CreateWindowPortForTopLevel(
diff --git a/ui/aura/test/mus/test_window_manager_client.cc b/ui/aura/test/mus/test_window_manager_client.cc index 0131e12..8ecb9dea 100644 --- a/ui/aura/test/mus/test_window_manager_client.cc +++ b/ui/aura/test/mus/test_window_manager_client.cc
@@ -72,6 +72,10 @@ void TestWindowManagerClient::WmSetGlobalOverrideCursor( base::Optional<ui::CursorData> cursor) {} +void TestWindowManagerClient::WmMoveCursorToDisplayLocation( + const gfx::Point& display_pixels, + int64_t display_id) {} + void TestWindowManagerClient::OnWmCreatedTopLevelWindow( uint32_t change_id, Id transport_window_id) {}
diff --git a/ui/aura/test/mus/test_window_manager_client.h b/ui/aura/test/mus/test_window_manager_client.h index 87373d231..0d56414 100644 --- a/ui/aura/test/mus/test_window_manager_client.h +++ b/ui/aura/test/mus/test_window_manager_client.h
@@ -58,6 +58,8 @@ void WmSetCursorVisible(bool visible) override; void WmSetGlobalOverrideCursor( base::Optional<ui::CursorData> cursor) override; + void WmMoveCursorToDisplayLocation(const gfx::Point& display_pixels, + int64_t display_id) override; void OnWmCreatedTopLevelWindow(uint32_t change_id, Id transport_window_id) override; void OnAcceleratorAck(
diff --git a/ui/message_center/views/message_center_view.cc b/ui/message_center/views/message_center_view.cc index 5a183bf..8e3e8a86 100644 --- a/ui/message_center/views/message_center_view.cc +++ b/ui/message_center/views/message_center_view.cc
@@ -92,15 +92,10 @@ const int button_height = button_bar_->GetPreferredSize().height(); scroller_ = new views::ScrollView(); + scroller_->SetBackgroundColor(kMessageCenterBackgroundColor); scroller_->ClipHeightTo(kMinScrollViewHeight, max_height - button_height); scroller_->SetVerticalScrollBar(new views::OverlayScrollBar(false)); scroller_->SetHorizontalScrollBar(new views::OverlayScrollBar(true)); - scroller_->SetBackground( - views::CreateSolidBackground(kMessageCenterBackgroundColor)); - - scroller_->SetPaintToLayer(); - scroller_->layer()->SetFillsBoundsOpaquely(false); - scroller_->layer()->SetMasksToBounds(true); message_list_view_.reset(new MessageListView()); message_list_view_->set_scroller(scroller_);
diff --git a/ui/views/controls/scroll_view.cc b/ui/views/controls/scroll_view.cc index 6d97969..539d23e 100644 --- a/ui/views/controls/scroll_view.cc +++ b/ui/views/controls/scroll_view.cc
@@ -49,6 +49,17 @@ DISALLOW_COPY_AND_ASSIGN(ScrollCornerView); }; +// Returns true if any descendants of |view| have a layer (not including +// |view|). +bool DoesDescendantHaveLayer(View* view) { + for (int i = 0; i < view->child_count(); ++i) { + View* child = view->child_at(i); + if (child->layer() || DoesDescendantHaveLayer(child)) + return true; + } + return false; +} + // Returns the position for the view so that it isn't scrolled off the visible // region. int CheckScrollBounds(int viewport_size, int content_size, int current_pos) { @@ -110,7 +121,7 @@ // Viewport contains the contents View of the ScrollView. class ScrollView::Viewport : public View { public: - Viewport() {} + explicit Viewport(ScrollView* scroll_view) : scroll_view_(scroll_view) {} ~Viewport() override {} const char* GetClassName() const override { return "ScrollView::Viewport"; } @@ -122,8 +133,7 @@ View* contents = child_at(0); gfx::Rect scroll_rect(rect); - ScrollView* scroll_view = static_cast<ScrollView*>(parent()); - if (scroll_view->ScrollsWithLayers()) { + if (scroll_view_->ScrollsWithLayers()) { // With layer scrolling, there's no need to "undo" the offset done in the // child's View::ScrollRectToVisible() before it calls this. DCHECK_EQ(0, contents->x()); @@ -132,7 +142,7 @@ scroll_rect.Offset(-contents->x(), -contents->y()); } - scroll_view->ScrollContentsRegionToBeVisible(scroll_rect); + scroll_view_->ScrollContentsRegionToBeVisible(scroll_rect); } void ChildPreferredSizeChanged(View* child) override { @@ -140,21 +150,37 @@ parent()->Layout(); } + void ViewHierarchyChanged( + const ViewHierarchyChangedDetails& details) override { + if (details.is_add && IsContentsViewport() && Contains(details.parent)) + scroll_view_->UpdateViewportLayerForClipping(); + } + + void OnChildLayerChanged(View* child) override { + if (IsContentsViewport()) + scroll_view_->UpdateViewportLayerForClipping(); + } + private: + bool IsContentsViewport() const { + return parent() && scroll_view_->contents_viewport_ == this; + } + + ScrollView* scroll_view_; + DISALLOW_COPY_AND_ASSIGN(Viewport); }; ScrollView::ScrollView() - : contents_(NULL), - contents_viewport_(new Viewport()), - header_(NULL), - header_viewport_(new Viewport()), + : contents_(nullptr), + contents_viewport_(new Viewport(this)), + header_(nullptr), + header_viewport_(new Viewport(this)), horiz_sb_(PlatformStyle::CreateScrollBar(true).release()), vert_sb_(PlatformStyle::CreateScrollBar(false).release()), corner_view_(new ScrollCornerView()), min_height_(-1), max_height_(-1), - background_color_(SK_ColorTRANSPARENT), hide_horizontal_scrollbar_(false), scroll_with_layers_enabled_( base::FeatureList::IsEnabled(kToolkitViewsScrollWithLayers)) { @@ -171,10 +197,9 @@ vert_sb_->set_controller(this); corner_view_->SetVisible(false); - if (!scroll_with_layers_enabled_) - return; - - EnableViewPortLayer(); + if (scroll_with_layers_enabled_) + EnableViewPortLayer(); + UpdateBackground(); } ScrollView::~ScrollView() { @@ -208,8 +233,8 @@ // Protect against clients passing a contents view that has its own Layer. DCHECK(!a_view->layer()); if (ScrollsWithLayers()) { - if (!a_view->background() && background_color_ != SK_ColorTRANSPARENT) { - a_view->SetBackground(CreateSolidBackground(background_color_)); + if (!a_view->background() && GetBackgroundColor() != SK_ColorTRANSPARENT) { + a_view->SetBackground(CreateSolidBackground(GetBackgroundColor())); } a_view->SetPaintToLayer(); a_view->layer()->SetScrollable( @@ -224,12 +249,15 @@ } void ScrollView::SetBackgroundColor(SkColor color) { - background_color_ = color; - contents_viewport_->SetBackground(CreateSolidBackground(background_color_)); - if (contents_ && ScrollsWithLayers() && - background_color_ != SK_ColorTRANSPARENT) { - contents_->SetBackground(CreateSolidBackground(background_color_)); - } + background_color_data_.color = color; + use_color_id_ = false; + UpdateBackground(); +} + +void ScrollView::SetBackgroundThemeColorId(ui::NativeTheme::ColorId color_id) { + background_color_data_.color_id = color_id; + use_color_id_ = true; + UpdateBackground(); } gfx::Rect ScrollView::GetVisibleRect() const { @@ -530,16 +558,8 @@ void ScrollView::OnNativeThemeChanged(const ui::NativeTheme* theme) { UpdateBorder(); -} - -void ScrollView::ViewHierarchyChanged( - const ViewHierarchyChangedDetails& details) { - if (details.is_add && !viewport_layer_enabled_ && Contains(details.parent)) - EnableLayeringRecursivelyForChild(details.child); -} - -void ScrollView::OnChildLayerChanged(View* child) { - EnableViewPortLayer(); + if (use_color_id_) + UpdateBackground(); } void ScrollView::ScrollToPosition(ScrollBar* source, int position) { @@ -590,6 +610,24 @@ contents_viewport_->height() / 5; } +bool ScrollView::DoesViewportOrScrollViewHaveLayer() const { + return layer() || contents_viewport_->layer(); +} + +void ScrollView::UpdateViewportLayerForClipping() { + if (scroll_with_layers_enabled_) + return; + + const bool has_layer = DoesViewportOrScrollViewHaveLayer(); + const bool needs_layer = DoesDescendantHaveLayer(contents_viewport_); + if (has_layer == needs_layer) + return; + if (needs_layer) + EnableViewPortLayer(); + else + contents_viewport_->DestroyLayer(); +} + void ScrollView::SetHeaderOrContents(View* parent, View* new_view, View** member) { @@ -740,22 +778,12 @@ } void ScrollView::EnableViewPortLayer() { - if (viewport_layer_enabled_) + if (DoesViewportOrScrollViewHaveLayer()) return; - viewport_layer_enabled_ = true; - contents_viewport_->SetPaintToLayer(); - - if (scroll_with_layers_enabled_) { - background_color_ = SK_ColorWHITE; - contents_viewport_->SetBackground(CreateSolidBackground(background_color_)); - } else { - // We may have transparent children who want to blend into the default - // background. - contents_viewport_->layer()->SetFillsBoundsOpaquely(false); - } contents_viewport_->layer()->SetMasksToBounds(true); + UpdateBackground(); } void ScrollView::OnLayerScrolled(const gfx::ScrollOffset&) { @@ -791,20 +819,27 @@ : ui::NativeTheme::kColorId_UnfocusedBorderColor))); } -bool ScrollView::EnableLayeringRecursivelyForChild(View* view) { - if (viewport_layer_enabled_ || scroll_with_layers_enabled_) - return true; +void ScrollView::UpdateBackground() { + const SkColor background_color = GetBackgroundColor(); - if (view->layer()) { - EnableViewPortLayer(); - return true; + SetBackground(CreateSolidBackground(background_color)); + // In addition to setting the background of |this|, set the background on + // the viewport as well. This way if the viewport has a layer + // SetFillsBoundsOpaquely() is honored. + contents_viewport_->SetBackground(CreateSolidBackground(background_color)); + if (contents_ && ScrollsWithLayers()) + contents_->SetBackground(CreateSolidBackground(background_color)); + if (contents_viewport_->layer()) { + contents_viewport_->layer()->SetFillsBoundsOpaquely(background_color != + SK_ColorTRANSPARENT); } + SchedulePaint(); +} - for (int i = 0; i < view->child_count(); ++i) { - if (EnableLayeringRecursivelyForChild(view->child_at(i))) - return true; - } - return false; +SkColor ScrollView::GetBackgroundColor() const { + return use_color_id_ + ? GetNativeTheme()->GetSystemColor(background_color_data_.color_id) + : background_color_data_.color; } // VariableRowHeightScrollHelper ----------------------------------------------
diff --git a/ui/views/controls/scroll_view.h b/ui/views/controls/scroll_view.h index 8fe732f..a39fbbd 100644 --- a/ui/views/controls/scroll_view.h +++ b/ui/views/controls/scroll_view.h
@@ -10,6 +10,7 @@ #include "base/compiler_specific.h" #include "base/gtest_prod_util.h" #include "base/macros.h" +#include "ui/native_theme/native_theme.h" #include "ui/views/controls/scrollbar/scroll_bar.h" namespace gfx { @@ -17,8 +18,6 @@ } namespace views { -class ViewObserverTest; - namespace test { class ScrollViewTestApi; } @@ -61,10 +60,15 @@ // Sets the header, deleting the previous header. void SetHeader(View* header); - // Sets the background color. The default is white when scrolling with layers, - // otherwise transparent. An opaque color when scrolling with layers ensures - // fonts can be drawn with subpixel antialiasing. + // The background color can be configured in two distinct ways: + // . By way of SetBackgroundThemeColorId(). This is the default and when + // called the background color comes from the theme (and changes if the + // theme changes). + // . By way of setting an explicit color, i.e. SetBackgroundColor(). Use + // SK_ColorTRANSPARENT if you don't want any color, but be warned this + // produces awful results when layers are used with subpixel rendering. void SetBackgroundColor(SkColor color); + void SetBackgroundThemeColorId(ui::NativeTheme::ColorId color_id); // Returns the visible region of the content View. gfx::Rect GetVisibleRect() const; @@ -107,9 +111,6 @@ void OnGestureEvent(ui::GestureEvent* event) override; const char* GetClassName() const override; void OnNativeThemeChanged(const ui::NativeTheme* theme) override; - void ViewHierarchyChanged( - const ViewHierarchyChangedDetails& details) override; - void OnChildLayerChanged(View* child) override; // ScrollBarController overrides: void ScrollToPosition(ScrollBar* source, int position) override; @@ -117,16 +118,27 @@ bool is_page, bool is_positive) override; - // TODO(djacobo): Remove this method when http://crbug.com/656198 is closed. - // Force |contents_viewport_| to enable a Layer(). - void EnableViewPortLayer(); - private: friend class test::ScrollViewTestApi; - FRIEND_TEST_ALL_PREFIXES(ViewObserverTest, ScrollViewChildAddLayerTest); class Viewport; + union BackgroundColorData { + SkColor color; + ui::NativeTheme::ColorId color_id; + }; + + // Forces |contents_viewport_| to have a Layer (assuming it doesn't already). + void EnableViewPortLayer(); + + // Returns true if this or the viewport has a layer. + bool DoesViewportOrScrollViewHaveLayer() const; + + // Updates or destroys the viewport layer as necessary. If any descendants + // of the viewport have a layer, then the viewport needs to have a layer, + // otherwise it doesn't. + void UpdateViewportLayerForClipping(); + // Used internally by SetHeader() and SetContents() to reset the view. Sets // |member| to |new_view|. If |new_view| is non-null it is added to |parent|. void SetHeaderOrContents(View* parent, View* new_view, View** member); @@ -168,10 +180,8 @@ void AddBorder(); void UpdateBorder(); - // Enables view port layering if |child| or any of its descendants has a - // layer. Returns true if yes. We short circuit the recursion if we enabled - // layering. - bool EnableLayeringRecursivelyForChild(View* child); + void UpdateBackground(); + SkColor GetBackgroundColor() const; // The current contents and its viewport. |contents_| is contained in // |contents_viewport_|. @@ -197,9 +207,10 @@ int min_height_; int max_height_; - // The background color given to the viewport (for overscroll), and to the - // contents when scrolling with layers. - SkColor background_color_; + // See description of SetBackgroundColor() for details. + BackgroundColorData background_color_data_ = { + ui::NativeTheme::kColorId_DialogBackground}; + bool use_color_id_ = true; // If true, never show the horizontal scrollbar (even if the contents is wider // than the viewport). @@ -215,9 +226,6 @@ // Focus ring, if one is installed. View* focus_ring_ = nullptr; - // Set to true if we enabled layering for the viewport. - bool viewport_layer_enabled_ = false; - // Set to true if the scroll with layers feature is enabled. const bool scroll_with_layers_enabled_;
diff --git a/ui/views/controls/scroll_view_unittest.cc b/ui/views/controls/scroll_view_unittest.cc index 574893ba..cc0a318 100644 --- a/ui/views/controls/scroll_view_unittest.cc +++ b/ui/views/controls/scroll_view_unittest.cc
@@ -707,6 +707,54 @@ EXPECT_TRUE(corner_view->visible()); } +TEST_F(ScrollViewTest, ChildWithLayerTest) { + View* contents = InstallContents(); + ScrollViewTestApi test_api(&scroll_view_); + + if (test_api.contents_viewport()->layer()) + return; + + View* child = new View(); + contents->AddChildView(child); + child->SetPaintToLayer(ui::LAYER_TEXTURED); + + ASSERT_TRUE(test_api.contents_viewport()->layer()); + // The default ScrollView color is opaque, so that fills bounds opaquely + // should be true. + EXPECT_TRUE(test_api.contents_viewport()->layer()->fills_bounds_opaquely()); + + // Setting a transparent color should make fills opaquely false. + scroll_view_.SetBackgroundColor(SK_ColorTRANSPARENT); + EXPECT_FALSE(test_api.contents_viewport()->layer()->fills_bounds_opaquely()); + + child->DestroyLayer(); + EXPECT_FALSE(test_api.contents_viewport()->layer()); + + View* child_child = new View(); + child->AddChildView(child_child); + EXPECT_FALSE(test_api.contents_viewport()->layer()); + child->SetPaintToLayer(ui::LAYER_TEXTURED); + EXPECT_TRUE(test_api.contents_viewport()->layer()); +} + +// Validates that if a child of a ScrollView adds a layer, then a layer +// is added to the ScrollView's viewport. +TEST_F(ScrollViewTest, DontCreateLayerOnViewportIfLayerOnScrollViewCreated) { + View* contents = InstallContents(); + ScrollViewTestApi test_api(&scroll_view_); + + if (test_api.contents_viewport()->layer()) + return; + + scroll_view_.SetPaintToLayer(); + + View* child = new View(); + contents->AddChildView(child); + child->SetPaintToLayer(ui::LAYER_TEXTURED); + + EXPECT_FALSE(test_api.contents_viewport()->layer()); +} + #if defined(OS_MACOSX) // Tests the overlay scrollbars on Mac. Ensure that they show up properly and // do not overlap each other.
diff --git a/ui/views/view_unittest.cc b/ui/views/view_unittest.cc index d71f0f6..e45cbb7 100644 --- a/ui/views/view_unittest.cc +++ b/ui/views/view_unittest.cc
@@ -5023,31 +5023,6 @@ EXPECT_EQ(child_view2.get(), view_reordered()); } -// Validates that if a child of a ScrollView adds a layer, then a layer -// is added to the ScrollView's viewport. -TEST_F(ViewObserverTest, ScrollViewChildAddLayerTest) { - std::unique_ptr<ScrollView> scroll_view(new ScrollView()); - scroll_view->SetContents(new View()); - // Bail if the scroll view already has a layer. - if (scroll_view->contents_viewport_->layer()) - return; - - EXPECT_FALSE(scroll_view->contents_viewport_->layer()); - - std::unique_ptr<View> child_view = NewView(); - scroll_view->AddChildView(child_view.get()); - child_view->SetPaintToLayer(ui::LAYER_TEXTURED); - - EXPECT_TRUE(scroll_view->contents_viewport_->layer()); - // We don't want the viewport's layer to have the fill_bounds_opaquely() bit - // set, as we may have transparent children who want to blend into the - // default background. - EXPECT_FALSE( - scroll_view->contents_viewport_->layer()->fills_bounds_opaquely()); - - scroll_view->RemoveChildView(child_view.get()); -} - // Provides a simple parent view implementation which tracks layer change // notifications from child views. class TestParentView : public View {