diff --git a/DEPS b/DEPS index 514891f..3a94d35 100644 --- a/DEPS +++ b/DEPS
@@ -115,11 +115,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': 'a72e8d3f40539f0c13329fced7eba8edf926df9f', + 'skia_revision': '15640698497a9d9175828091922d7c57f38093e2', # 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': '9062ade59ce8de42c395674707bbad68f8f7779a', + 'v8_revision': 'c2ee93406a001b80556c39f66f1a8d00bfcc9517', # 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. @@ -127,7 +127,7 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling ANGLE # and whatever else without interference from each other. - 'angle_revision': '153e0224da45beaaee596e434b0c81e349b2ab21', + 'angle_revision': '149eb33bb49faed65a7edb3f5c1d58641fe981c0', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling build tools # and whatever else without interference from each other. @@ -139,7 +139,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': '32660f54f79530f36cfd78ca88dae996d4fa9c88', + 'pdfium_revision': '1ccf890a09a33b8e49d92f8f8f565645be82fb6b', # 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. @@ -223,7 +223,7 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling feed # and whatever else without interference from each other. - 'spv_tools_revision': 'e07dabc25f1f3d966988dbd455bd05582ccfe170', + 'spv_tools_revision': '248debf55ad6de4a80f6d4a128ef195b6ed05a30', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling feed # and whatever else without interference from each other. @@ -239,7 +239,7 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling feed # and whatever else without interference from each other. - 'dawn_revision': '07df605a2bfb4f27f96968ac36bf94636af17fb3', + 'dawn_revision': 'a49242766a107c411d744d828a733317ef92dc83', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling feed # and whatever else without interference from each other. @@ -687,7 +687,7 @@ }, 'src/third_party/depot_tools': - Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + 'ec40d02c8a16c9bc03a8eddddb71979244f5f1fd', + Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + '762a25693faf4d7e82a70d1021aebd7d981297ff', 'src/third_party/devtools-node-modules': Var('chromium_git') + '/external/github.com/ChromeDevTools/devtools-node-modules' + '@' + Var('devtools_node_modules_revision'), @@ -1019,7 +1019,7 @@ }, 'src/third_party/perfetto': - Var('android_git') + '/platform/external/perfetto.git' + '@' + '2efdf1d56ab23366f091b4d93d814981b2a4df79', + Var('android_git') + '/platform/external/perfetto.git' + '@' + 'faae590fff1a333b4c7b3d16c93dd6d01c539e02', 'src/third_party/perl': { 'url': Var('chromium_git') + '/chromium/deps/perl.git' + '@' + 'ac0d98b5cee6c024b0cffeb4f8f45b6fc5ccdb78', @@ -1086,7 +1086,7 @@ }, 'src/third_party/re2/src': - Var('chromium_git') + '/external/github.com/google/re2.git' + '@' + '749d64c35e09849045303c3de4e9955597b75b53', + Var('chromium_git') + '/external/github.com/google/re2.git' + '@' + 'f620af75bd693f917c684106d26de1b99ffe0e0d', 'src/third_party/r8': { 'packages': [ @@ -1213,7 +1213,7 @@ Var('chromium_git') + '/v8/v8.git' + '@' + Var('v8_revision'), 'src-internal': { - 'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@b12d02f6627fd976f6b0e9cf99177989ae65948c', + 'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@ddee6ce9c58a72fc2bd4e2da086178c5b468b578', 'condition': 'checkout_src_internal', }, @@ -1736,6 +1736,17 @@ 'dep_type': 'cipd', }, + 'src/third_party/android_deps/libs/com_google_ar_core': { + 'packages': [ + { + 'package': 'chromium/third_party/android_deps/libs/com_google_ar_core', + 'version': 'version:1.5.0-cr0', + }, + ], + 'condition': 'checkout_android', + 'dep_type': 'cipd', + }, + 'src/third_party/android_deps/libs/com_google_code_findbugs_jsr305': { 'packages': [ { @@ -2270,6 +2281,44 @@ '-d', 'src/chrome/build', ], }, + # Pull luci-go binaries (isolate, swarming) using checked-in hashes. + # TODO(maruel): Remove, https://crbug.com/851596 + { + 'name': 'luci-go_win', + 'pattern': '.', + 'condition': 'host_os == "win"', + 'action': [ 'python', + 'src/third_party/depot_tools/download_from_google_storage.py', + '--no_resume', + '--no_auth', + '--bucket', 'chromium-luci', + '-d', 'src/tools/luci-go/win64', + ], + }, + { + 'name': 'luci-go_mac', + 'pattern': '.', + 'condition': 'host_os == "mac"', + 'action': [ 'python', + 'src/third_party/depot_tools/download_from_google_storage.py', + '--no_resume', + '--no_auth', + '--bucket', 'chromium-luci', + '-d', 'src/tools/luci-go/mac64', + ], + }, + { + 'name': 'luci-go_linux', + 'pattern': '.', + 'condition': 'host_os == "linux"', + 'action': [ 'python', + 'src/third_party/depot_tools/download_from_google_storage.py', + '--no_resume', + '--no_auth', + '--bucket', 'chromium-luci', + '-d', 'src/tools/luci-go/linux64', + ], + }, { 'name': 'apache_win32', 'pattern': '\\.sha1',
diff --git a/WATCHLISTS b/WATCHLISTS index 03f0ac9..d7ca3f0 100644 --- a/WATCHLISTS +++ b/WATCHLISTS
@@ -1085,11 +1085,6 @@ 'mash_buildbot_filters': { 'filepath': 'testing/buildbot/filters/mash.*filter', }, - 'md_settings': { - 'filepath': 'chrome/browser/resources/settings/'\ - '|chrome/browser/ui/webui/settings/'\ - '|chrome/test/data/webui/settings/', - }, 'media': { 'filepath': 'media|third_party/(ffmpeg|opus|libvpx)' }, @@ -1460,6 +1455,11 @@ 'services_public': { 'filepath': 'services/([^/]*/)*public/', }, + 'settings': { + 'filepath': 'chrome/browser/resources/settings/'\ + '|chrome/browser/ui/webui/settings/'\ + '|chrome/test/data/webui/settings/', + }, 'settings_reset_prompt': { 'filepath': 'chrome/browser/safe_browsing/settings_reset_prompt/'\ '|chrome/browser/ui/views/settings_reset_prompt', @@ -1692,6 +1692,10 @@ 'wake_lock': { 'filepath': 'wake_lock', }, + 'web_dev_style': { + 'filepath': 'tools/web_dev_style/'\ + '|styleguide/web/', + }, 'web_package': { 'filepath': 'content/browser/loader/prefetch_url_loader'\ '|content/browser/web_package/'\ @@ -1731,6 +1735,11 @@ '|chrome/common/content_settings'\ '|components/content_settings/', }, + 'webui_backend': { + 'filepath': 'content/browser/webui/'\ + '|content/public/browser/web_ui*'\ + '|content/public/test/*web_ui*', + }, 'windows_sandboxing': { 'filepath': 'sandbox/win/', }, @@ -2127,7 +2136,8 @@ 'tikuta+cc@chromium.org', 'ukai+cc@chromium.org', 'yyanagisawa+cc@chromium.org'], - 'cr_elements': ['michaelpg+watch-elements@chromium.org', + 'cr_elements': ['dbeam+watch-cr-elements@chromium.org', + 'michaelpg+watch-elements@chromium.org', 'stevenjb+watch-md-settings@chromium.org'], 'cros_benchmarks': ['cros-perf-detectives@google.com', 'cywang@chromium.org', @@ -2151,7 +2161,8 @@ 'zhaobin+watch@chromium.org'], 'disk_cache': ['gavinp+disk@chromium.org'], 'download': ['dtrainor+watch@chromium.org'], - 'downloads_ui': ['dtrainor+watch@chromium.org'], + 'downloads_ui': ['dbeam+watch-downloads-ui@chromium.org', + 'dtrainor+watch@chromium.org'], 'drive': ['tfarina@chromium.org'], 'drive_resource_metadata': ['hashimoto+watch@chromium.org'], 'eme': ['eme-reviews@chromium.org'], @@ -2195,7 +2206,7 @@ 'mcnee@chromium.org', 'wjmaclean@chromium.org'], 'headless': ['headless-reviews@chromium.org'], - 'history_ui': [], + 'history_ui': ['dbeam+watch-history-ui@chromium.org'], 'i18n': ['jshin+watch@chromium.org'], 'importer': ['tfarina@chromium.org'], 'incident_reporting': ['grt+watch@chromium.org'], @@ -2246,8 +2257,6 @@ 'manifest': ['mlamouri+watch-manifest@chromium.org'], 'mash_buildbot_filters': ['dxie+watch@chromium.org', 'jamescook+watch@chromium.org'], - 'md_settings': ['michaelpg+watch-md-settings@chromium.org', - 'stevenjb+watch-md-settings@chromium.org'], 'media': ['feature-media-reviews@chromium.org'], 'media_capture_from_element': ['emircan+watch+capturefromdom@chromium.org'], 'media_controls': ['steimel+watch-mediacontrols@chromium.org'], @@ -2356,7 +2365,8 @@ 'timloh+watch@chromium.org'], 'picture_in_picture': ['beaufort.francois+pip@gmail.com'], 'policy_templates': ['ljusten+watch@chromium.org'], - 'polymer': ['michaelpg+watch-polymer@chromium.org'], + 'polymer': ['dbeam+watch-polymer@chromium.org', + 'michaelpg+watch-polymer@chromium.org'], 'popup_blocker': ['csharrison+watch-popups@chromium.org'], 'precache': ['wifiprefetch-reviews@google.com'], 'prepopulated_engines': ['vasilii+watch@chromium.org'], @@ -2382,6 +2392,9 @@ 'serviceworker-reviews@chromium.org', 'shimazu+serviceworker@chromium.org'], 'services_public': ['blundell+services-watchlist@chromium.org'], + 'settings': ['dbeam+watch-settings@chromium.org', + 'michaelpg+watch-md-settings@chromium.org', + 'stevenjb+watch-md-settings@chromium.org'], 'settings_reset_prompt': ['alito+watch@chromium.org'], 'site_engagement': ['dominickn+watch-engagement@chromium.org'], 'site_instance': ['ajwong+watch@chromium.org', @@ -2469,6 +2482,7 @@ 'yhanada+watchvk@chromium.org'], 'virtual_reality': ['feature-vr-reviews@chromium.org'], 'wake_lock': ['mattreynolds+watch@chromium.org'], + 'web_dev_style': ['dbeam+watch-web-dev-style@chromium.org'], 'web_package': ['twifkak+watch@chromium.org'], 'web_share': ['mgiuca+watch@chromium.org'], 'webauthn': ['webauthn-reviews@chromium.org'], @@ -2479,6 +2493,7 @@ 'markusheintz@chromium.org', 'msramek+watch@chromium.org', 'raymes+watch@chromium.org'], + 'webui_backend': ['dbeam+watch-webui-backend@chromium.org'], 'windows_sandboxing': ['wfh+watch@chromium.org'], 'x11': ['derat+watch@chromium.org', 'sadrul@chromium.org',
diff --git a/ash/BUILD.gn b/ash/BUILD.gn index 03ed223..517068d0 100644 --- a/ash/BUILD.gn +++ b/ash/BUILD.gn
@@ -157,6 +157,8 @@ "app_list/home_launcher_gesture_handler.h", "ash_export.h", "ash_service.cc", + "assistant/assistant_alarm_timer_controller.cc", + "assistant/assistant_alarm_timer_controller.h", "assistant/assistant_cache_controller.cc", "assistant/assistant_cache_controller.h", "assistant/assistant_controller.cc",
diff --git a/ash/ash_strings.grd b/ash/ash_strings.grd index 3d62e5e..3d22fd2 100644 --- a/ash/ash_strings.grd +++ b/ash/ash_strings.grd
@@ -1766,6 +1766,25 @@ <message name="IDS_ASH_ASSISTANT_CHIP_WHATS_THE_WEATHER" desc="Message shown on suggestion chip in Assistant UI to initiate a query for the current weather."> What's the weather? </message> + <message name="IDS_ASSISTANT_TIMER_NOTIFICATION_TITLE" desc="Title for Assistant timer notification."> + Time's up + </message> + <message name="IDS_ASSISTANT_TIMER_NOTIFICATION_CONTENT" desc="Content for Assistant timer notification."> + 00:00s + </message> + <message name="IDS_ASSISTANT_TIMER_NOTIFICATION_ADD_1_MIN_BUTTON" desc="Label for button to add 1 minute to timer in Assistant timer notification."> + Add 1 min + </message> + <message name="IDS_ASSISTANT_TIMER_NOTIFICATION_ADD_1_MIN_QUERY" desc="Query to issue to add 1 minute to an Assistant timer."> + Add 1 min to timer + </message> + <message name="IDS_ASSISTANT_TIMER_NOTIFICATION_STOP_BUTTON" desc="Label for stop button in Assistant timer notification."> + Stop + </message> + <message name="IDS_ASSISTANT_TIMER_NOTIFICATION_STOP_QUERY" desc="Query to issue to stop Assistant timer."> + Stop timer + </message> + <message name="IDS_ASH_MESSAGE_CENTER_UNLOCK_TO_PERFORM_ACTION" desc="The short message to encourage user to unlock the device so that Chrome OS can perform the notification action selected by user after unlocking."> Unlock device to perform the notification action </message>
diff --git a/ash/assistant/assistant_alarm_timer_controller.cc b/ash/assistant/assistant_alarm_timer_controller.cc new file mode 100644 index 0000000..c949222 --- /dev/null +++ b/ash/assistant/assistant_alarm_timer_controller.cc
@@ -0,0 +1,82 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/assistant/assistant_alarm_timer_controller.h" + +#include "ash/assistant/assistant_controller.h" +#include "ash/assistant/assistant_notification_controller.h" +#include "ash/assistant/util/deep_link_util.h" +#include "ash/strings/grit/ash_strings.h" +#include "chromeos/services/assistant/public/features.h" +#include "chromeos/services/assistant/public/mojom/assistant.mojom.h" +#include "ui/base/l10n/l10n_util.h" + +namespace ash { + +namespace { + +constexpr char kTimerFireNotificationGroupId[] = "assistant/timer_fire"; + +} // namespace + +AssistantAlarmTimerController::AssistantAlarmTimerController( + AssistantController* assistant_controller) + : assistant_controller_(assistant_controller), binding_(this) {} + +AssistantAlarmTimerController::~AssistantAlarmTimerController() = default; + +void AssistantAlarmTimerController::BindRequest( + mojom::AssistantAlarmTimerControllerRequest request) { + DCHECK(chromeos::assistant::features::IsTimerNotificationEnabled()); + binding_.Bind(std::move(request)); +} + +// TODO(dmblack): Abstract this out into a model that tracks timer state so that +// we can observe it to either add a system notification or an in-Assistant +// notification depending on UI visibility state. These notifications will need +// to be updated in sync with clock ticks until the notification is dismissed. +void AssistantAlarmTimerController::OnTimerSoundingStarted() { + // TODO(llin): Migrate to use the AlarmManager API to better support multiple + // timers when the API is available. + const std::string title = + l10n_util::GetStringUTF8(IDS_ASSISTANT_TIMER_NOTIFICATION_TITLE); + const std::string message = + l10n_util::GetStringUTF8(IDS_ASSISTANT_TIMER_NOTIFICATION_CONTENT); + const GURL action_url = assistant::util::CreateAssistantQueryDeepLink( + l10n_util::GetStringUTF8(IDS_ASSISTANT_TIMER_NOTIFICATION_STOP_QUERY)); + + chromeos::assistant::mojom::AssistantNotificationPtr notification = + chromeos::assistant::mojom::AssistantNotification::New(); + + notification->title = title; + notification->message = message; + notification->action_url = action_url; + notification->grouping_key = kTimerFireNotificationGroupId; + + // "STOP" button. + notification->buttons.push_back( + chromeos::assistant::mojom::AssistantNotificationButton::New( + l10n_util::GetStringUTF8( + IDS_ASSISTANT_TIMER_NOTIFICATION_STOP_BUTTON), + action_url)); + + // "ADD 1 MIN" button. + notification->buttons.push_back( + chromeos::assistant::mojom::AssistantNotificationButton::New( + l10n_util::GetStringUTF8( + IDS_ASSISTANT_TIMER_NOTIFICATION_ADD_1_MIN_BUTTON), + assistant::util::CreateAssistantQueryDeepLink( + l10n_util::GetStringUTF8( + IDS_ASSISTANT_TIMER_NOTIFICATION_ADD_1_MIN_QUERY)))); + + assistant_controller_->notification_controller()->OnShowNotification( + std::move(notification)); +} + +void AssistantAlarmTimerController::OnTimerSoundingFinished() { + assistant_controller_->notification_controller()->OnRemoveNotification( + kTimerFireNotificationGroupId); +} + +} // namespace ash
diff --git a/ash/assistant/assistant_alarm_timer_controller.h b/ash/assistant/assistant_alarm_timer_controller.h new file mode 100644 index 0000000..63a30f8 --- /dev/null +++ b/ash/assistant/assistant_alarm_timer_controller.h
@@ -0,0 +1,41 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_ASSISTANT_ASSISTANT_ALARM_TIMER_CONTROLLER_H_ +#define ASH_ASSISTANT_ASSISTANT_ALARM_TIMER_CONTROLLER_H_ + +#include "ash/public/interfaces/assistant_controller.mojom.h" +#include "base/macros.h" +#include "mojo/public/cpp/bindings/binding.h" + +namespace ash { + +class AssistantController; + +// The AssistantAlarmTimerController is a sub-controller of AssistantController +// tasked with tracking alarm/timer state and providing alarm/timer APIs. +class AssistantAlarmTimerController + : public mojom::AssistantAlarmTimerController { + public: + explicit AssistantAlarmTimerController( + AssistantController* assistant_controller); + ~AssistantAlarmTimerController() override; + + void BindRequest(mojom::AssistantAlarmTimerControllerRequest request); + + // mojom::AssistantAlarmTimerController: + void OnTimerSoundingStarted() override; + void OnTimerSoundingFinished() override; + + private: + AssistantController* const assistant_controller_; // Owned by Shell. + + mojo::Binding<mojom::AssistantAlarmTimerController> binding_; + + DISALLOW_COPY_AND_ASSIGN(AssistantAlarmTimerController); +}; + +} // namespace ash + +#endif // ASH_ASSISTANT_ASSISTANT_ALARM_TIMER_CONTROLLER_H_
diff --git a/ash/assistant/assistant_controller.cc b/ash/assistant/assistant_controller.cc index db4f0bd0..6e89a4fd 100644 --- a/ash/assistant/assistant_controller.cc +++ b/ash/assistant/assistant_controller.cc
@@ -8,6 +8,7 @@ #include <utility> #include "ash/accessibility/accessibility_controller.h" +#include "ash/assistant/assistant_alarm_timer_controller.h" #include "ash/assistant/assistant_cache_controller.h" #include "ash/assistant/assistant_controller_observer.h" #include "ash/assistant/assistant_interaction_controller.h" @@ -32,6 +33,8 @@ AssistantController::AssistantController() : assistant_volume_control_binding_(this), + assistant_alarm_timer_controller_( + std::make_unique<AssistantAlarmTimerController>(this)), assistant_cache_controller_( std::make_unique<AssistantCacheController>(this)), assistant_interaction_controller_(
diff --git a/ash/assistant/assistant_controller.h b/ash/assistant/assistant_controller.h index 97b29db..b7ed97d 100644 --- a/ash/assistant/assistant_controller.h +++ b/ash/assistant/assistant_controller.h
@@ -32,6 +32,7 @@ namespace ash { +class AssistantAlarmTimerController; class AssistantCacheController; class AssistantInteractionController; class AssistantNotificationController; @@ -100,6 +101,11 @@ void GetNavigableContentsFactory( content::mojom::NavigableContentsFactoryRequest request); + AssistantAlarmTimerController* alarm_timer_controller() { + DCHECK(assistant_alarm_timer_controller_); + return assistant_alarm_timer_controller_.get(); + } + AssistantCacheController* cache_controller() { DCHECK(assistant_cache_controller_); return assistant_cache_controller_.get(); @@ -156,6 +162,9 @@ mojom::AssistantImageDownloaderPtr assistant_image_downloader_; + std::unique_ptr<AssistantAlarmTimerController> + assistant_alarm_timer_controller_; + std::unique_ptr<AssistantCacheController> assistant_cache_controller_; std::unique_ptr<AssistantInteractionController>
diff --git a/ash/assistant/util/deep_link_util.cc b/ash/assistant/util/deep_link_util.cc index ad6d7220..f5f16ed 100644 --- a/ash/assistant/util/deep_link_util.cc +++ b/ash/assistant/util/deep_link_util.cc
@@ -55,6 +55,11 @@ // Utilities ------------------------------------------------------------------- +GURL CreateAssistantQueryDeepLink(const std::string& query) { + return net::AppendOrReplaceQueryParameter(GURL(kAssistantQueryPrefix), + kQueryParamKey, query); +} + GURL CreateAssistantSettingsDeepLink() { return GURL(kAssistantSettingsPrefix); }
diff --git a/ash/assistant/util/deep_link_util.h b/ash/assistant/util/deep_link_util.h index 4400724..09d181ce 100644 --- a/ash/assistant/util/deep_link_util.h +++ b/ash/assistant/util/deep_link_util.h
@@ -39,6 +39,9 @@ kRelaunch, }; +// Returns a deep link to send an Assistant query. +ASH_EXPORT GURL CreateAssistantQueryDeepLink(const std::string& query); + // Returns a deep link to top level Assistant Settings. ASH_EXPORT GURL CreateAssistantSettingsDeepLink();
diff --git a/ash/assistant/util/deep_link_util_unittest.cc b/ash/assistant/util/deep_link_util_unittest.cc index 2d4e034..a5fc72f 100644 --- a/ash/assistant/util/deep_link_util_unittest.cc +++ b/ash/assistant/util/deep_link_util_unittest.cc
@@ -18,6 +18,11 @@ using DeepLinkUnitTest = AshTestBase; +TEST_F(DeepLinkUnitTest, CreateAssistantQueryDeepLink) { + ASSERT_EQ(GURL("googleassistant://send-query?q=query"), + CreateAssistantQueryDeepLink("query")); +} + TEST_F(DeepLinkUnitTest, CreateAssistantSettingsDeepLink) { ASSERT_EQ(GURL("googleassistant://settings"), CreateAssistantSettingsDeepLink());
diff --git a/ash/login/ui/login_base_bubble_view.cc b/ash/login/ui/login_base_bubble_view.cc index 9105f5b..3ac160e 100644 --- a/ash/login/ui/login_base_bubble_view.cc +++ b/ash/login/ui/login_base_bubble_view.cc
@@ -6,7 +6,14 @@ #include "ash/public/cpp/shell_window_ids.h" #include "ash/shell.h" +#include "base/scoped_observer.h" +#include "ui/aura/client/focus_change_observer.h" +#include "ui/aura/client/focus_client.h" +#include "ui/compositor/layer_animator.h" +#include "ui/compositor/scoped_layer_animation_settings.h" +#include "ui/events/event_handler.h" #include "ui/views/layout/box_layout.h" +#include "ui/wm/core/coordinate_conversion.h" namespace ash { namespace { @@ -23,14 +30,111 @@ // Bottom margin of the bubble view. constexpr int kBubbleBottomMarginDp = 18; +// The amount of time for bubble show/hide animation. +constexpr base::TimeDelta kBubbleAnimationDuration = + base::TimeDelta::FromMilliseconds(300); + } // namespace +// This class handles keyboard, mouse, and focus events, and dismisses the +// associated bubble in response. +class LoginBubbleHandler : public ui::EventHandler, + public aura::client::FocusChangeObserver { + public: + LoginBubbleHandler(LoginBaseBubbleView* bubble) : bubble_(bubble) { + Shell::Get()->AddPreTargetHandler(this); + focus_observer_.Add( + aura::client::GetFocusClient(Shell::GetPrimaryRootWindow())); + } + + ~LoginBubbleHandler() override { Shell::Get()->RemovePreTargetHandler(this); } + + // ui::EventHandler: + void OnMouseEvent(ui::MouseEvent* event) override { + if (event->type() == ui::ET_MOUSE_PRESSED) + ProcessPressedEvent(event->AsLocatedEvent()); + } + + void OnGestureEvent(ui::GestureEvent* event) override { + if (event->type() == ui::ET_GESTURE_TAP || + event->type() == ui::ET_GESTURE_TAP_DOWN) { + ProcessPressedEvent(event->AsLocatedEvent()); + } + } + + void OnKeyEvent(ui::KeyEvent* event) override { + if (event->type() != ui::ET_KEY_PRESSED || + event->key_code() == ui::VKEY_PROCESSKEY) { + return; + } + + if (bubble_->GetBubbleOpener() && bubble_->GetBubbleOpener()->HasFocus()) + return; + + if (!bubble_->GetWidget() || !bubble_->GetWidget()->IsVisible()) + return; + + if (bubble_->GetWidget()->IsActive()) + return; + + if (!bubble_->IsPersistent()) + bubble_->Hide(); + } + + // aura::client::FocusChangeObserver: + void OnWindowFocused(aura::Window* gained_focus, + aura::Window* lost_focus) override { + if (!bubble_->GetWidget() || !bubble_->GetWidget()->IsVisible()) + return; + + if (gained_focus && + bubble_->GetWidget()->GetNativeView()->Contains(gained_focus)) { + return; + } + + if (!bubble_->IsPersistent()) + bubble_->Hide(); + } + + private: + void ProcessPressedEvent(const ui::LocatedEvent* event) { + gfx::Point screen_location = event->location(); + ::wm::ConvertPointToScreen(static_cast<aura::Window*>(event->target()), + &screen_location); + + // Don't do anything with clicks inside the bubble. + if (bubble_->GetBoundsInScreen().Contains(screen_location)) + return; + + // Let the bubble opener handle clicks on itself. + if (bubble_->GetBubbleOpener() && + bubble_->GetBubbleOpener()->GetBoundsInScreen().Contains( + screen_location)) { + return; + } + + if (!bubble_->GetWidget() || !bubble_->GetWidget()->IsVisible()) + return; + + if (!bubble_->IsPersistent()) + bubble_->Hide(); + } + + LoginBaseBubbleView* bubble_; + + ScopedObserver<aura::client::FocusClient, aura::client::FocusChangeObserver> + focus_observer_{this}; + + DISALLOW_COPY_AND_ASSIGN(LoginBubbleHandler); +}; + LoginBaseBubbleView::LoginBaseBubbleView(views::View* anchor_view) : LoginBaseBubbleView(anchor_view, nullptr) {} LoginBaseBubbleView::LoginBaseBubbleView(views::View* anchor_view, aura::Window* parent_window) - : BubbleDialogDelegateView(anchor_view, views::BubbleBorder::NONE) { + : BubbleDialogDelegateView(anchor_view, views::BubbleBorder::NONE), + bubble_handler_(std::make_unique<LoginBubbleHandler>(this)) { set_margins(gfx::Insets(kBubbleTopMarginDp, kBubbleHorizontalMarginDp, kBubbleBottomMarginDp, kBubbleHorizontalMarginDp)); set_color(SK_ColorBLACK); @@ -46,6 +150,27 @@ LoginBaseBubbleView::~LoginBaseBubbleView() = default; +void LoginBaseBubbleView::Show() { + views::Widget* widget = GetWidget(); + + if (!widget) + widget = views::BubbleDialogDelegateView::CreateBubble(this); + + widget->ShowInactive(); + widget->StackAtTop(); + + ScheduleAnimation(true /*visible*/); + + // Tell ChromeVox to read bubble contents. + NotifyAccessibilityEvent(ax::mojom::Event::kAlert, + true /*send_native_event*/); +} + +void LoginBaseBubbleView::Hide() { + if (GetWidget()) + ScheduleAnimation(false /*visible*/); +} + LoginButton* LoginBaseBubbleView::GetBubbleOpener() const { return nullptr; } @@ -71,6 +196,12 @@ return ui::DIALOG_BUTTON_NONE; } +void LoginBaseBubbleView::OnLayerAnimationEnded( + ui::LayerAnimationSequence* sequence) { + layer()->GetAnimator()->RemoveObserver(this); + GetWidget()->Hide(); +} + gfx::Size LoginBaseBubbleView::CalculatePreferredSize() const { gfx::Size size; size.set_width(kBubbleTotalWidthDp); @@ -78,4 +209,67 @@ return size; } +void LoginBaseBubbleView::OnWidgetVisibilityChanged(views::Widget* widget, + bool visible) { + if (visible) + EnsureInScreen(); +} + +void LoginBaseBubbleView::OnWidgetBoundsChanged(views::Widget* widget, + const gfx::Rect& new_bounds) { + EnsureInScreen(); +} + +void LoginBaseBubbleView::ScheduleAnimation(bool visible) { + if (GetBubbleOpener()) { + GetBubbleOpener()->AnimateInkDrop(visible + ? views::InkDropState::ACTIVATED + : views::InkDropState::DEACTIVATED, + nullptr /*event*/); + } + + layer()->GetAnimator()->StopAnimating(); + + float opacity_start = 0.0f; + float opacity_end = 1.0f; + if (!visible) + std::swap(opacity_start, opacity_end); + + // We only need to handle animation ending if we're hiding the bubble. + if (!visible) + layer()->GetAnimator()->AddObserver(this); + + layer()->SetOpacity(opacity_start); + { + ui::ScopedLayerAnimationSettings settings(layer()->GetAnimator()); + settings.SetTransitionDuration(kBubbleAnimationDuration); + settings.SetTweenType(visible ? gfx::Tween::EASE_OUT : gfx::Tween::EASE_IN); + settings.SetPreemptionStrategy( + ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET); + layer()->SetOpacity(opacity_end); + } +} + +void LoginBaseBubbleView::EnsureInScreen() { + DCHECK(GetWidget()); + + const gfx::Rect view_bounds = GetBoundsInScreen(); + const gfx::Rect work_area = + display::Screen::GetScreen() + ->GetDisplayNearestWindow(GetWidget()->GetNativeWindow()) + .work_area(); + + int horizontal_offset = 0; + + // If the widget extends past the right side of the screen, make it go to + // the left instead. + if (work_area.right() < view_bounds.right()) { + horizontal_offset = -view_bounds.width(); + } + + set_anchor_view_insets( + anchor_view_insets().Offset(gfx::Vector2d(horizontal_offset, 0))); + OnAnchorBoundsChanged(); +} + } // namespace ash
diff --git a/ash/login/ui/login_base_bubble_view.h b/ash/login/ui/login_base_bubble_view.h index f8aa76e4..a2bb76f 100644 --- a/ash/login/ui/login_base_bubble_view.h +++ b/ash/login/ui/login_base_bubble_view.h
@@ -7,13 +7,18 @@ #include "ash/ash_export.h" #include "ash/login/ui/login_button.h" +#include "ui/compositor/layer_animation_observer.h" #include "ui/views/bubble/bubble_dialog_delegate_view.h" #include "ui/views/view.h" +#include "ui/views/widget/widget_observer.h" namespace ash { +class LoginBubbleHandler; + // Base bubble view for login screen bubbles. -class ASH_EXPORT LoginBaseBubbleView : public views::BubbleDialogDelegateView { +class ASH_EXPORT LoginBaseBubbleView : public views::BubbleDialogDelegateView, + public ui::LayerAnimationObserver { public: // Without specifying a parent_window, the bubble will default to being in the // same container as anchor_view. @@ -22,6 +27,9 @@ gfx::NativeView parent_window); ~LoginBaseBubbleView() override; + void Show(); + void Hide(); + // Returns the button responsible for opening this bubble. virtual LoginButton* GetBubbleOpener() const; @@ -33,10 +41,25 @@ views::Widget* widget) const override; int GetDialogButtons() const override; + // ui::LayerAnimationObserver: + void OnLayerAnimationEnded(ui::LayerAnimationSequence* sequence) override; + void OnLayerAnimationAborted(ui::LayerAnimationSequence* sequence) override{}; + void OnLayerAnimationScheduled( + ui::LayerAnimationSequence* sequence) override{}; + // views::View: gfx::Size CalculatePreferredSize() const override; + // views::WidgetObserver: + void OnWidgetVisibilityChanged(views::Widget* widget, bool visible) override; + void OnWidgetBoundsChanged(views::Widget* widget, + const gfx::Rect& new_bounds) override; + private: + void ScheduleAnimation(bool visible); + void EnsureInScreen(); + + std::unique_ptr<LoginBubbleHandler> bubble_handler_; DISALLOW_COPY_AND_ASSIGN(LoginBaseBubbleView); };
diff --git a/ash/login/ui/login_bubble.cc b/ash/login/ui/login_bubble.cc index 9c45d6b..68c27ee 100644 --- a/ash/login/ui/login_bubble.cc +++ b/ash/login/ui/login_bubble.cc
@@ -76,9 +76,6 @@ // Vertical spacing between the anchor view and user menu. constexpr int kAnchorViewUserMenuVerticalSpacingDp = 4; -// The amount of time for bubble show/hide animation. -constexpr int kBubbleAnimationDurationMs = 300; - views::Label* CreateLabel(const base::string16& message, SkColor color) { views::Label* label = new views::Label(message, views::style::CONTEXT_LABEL, views::style::STYLE_PRIMARY); @@ -186,8 +183,7 @@ class LoginUserMenuView : public LoginBaseBubbleView, public views::ButtonListener { public: - LoginUserMenuView(LoginBubble* bubble, - const base::string16& username, + LoginUserMenuView(const base::string16& username, const base::string16& email, user_manager::UserType type, bool is_owner, @@ -197,7 +193,6 @@ base::OnceClosure on_remove_user_warning_shown, base::OnceClosure on_remove_user_requested) : LoginBaseBubbleView(anchor_view), - bubble_(bubble), bubble_opener_(bubble_opener_), on_remove_user_warning_shown_(std::move(on_remove_user_warning_shown)), on_remove_user_requested_(std::move(on_remove_user_requested)) { @@ -376,9 +371,7 @@ return; } - // Close the bubble before calling |on_remove_user_requested_|. |bubble_| is - // an unowned reference; |on_remove_user_requested_| may delete it. - bubble_->Close(); + Hide(); if (on_remove_user_requested_) std::move(on_remove_user_requested_).Run(); @@ -391,7 +384,6 @@ views::Label* username_label() { return username_label_; } private: - LoginBubble* bubble_ = nullptr; LoginButton* bubble_opener_ = nullptr; base::OnceClosure on_remove_user_warning_shown_; base::OnceClosure on_remove_user_requested_; @@ -444,15 +436,9 @@ return static_cast<LoginUserMenuView*>(bubble_view_)->username_label(); } -LoginBubble::LoginBubble() { - Shell::Get()->AddPreTargetHandler(this); -} +LoginBubble::LoginBubble() = default; -LoginBubble::~LoginBubble() { - Shell::Get()->RemovePreTargetHandler(this); - if (bubble_view_) - CloseImmediately(); -} +LoginBubble::~LoginBubble() = default; void LoginBubble::ShowErrorBubble(views::View* content, views::View* anchor_view, @@ -465,7 +451,7 @@ bubble_view_ = new LoginErrorBubbleView(content, anchor_view, menu_container, show_persistently); - Show(); + bubble_view_->Show(); } void LoginBubble::ShowUserMenu(const base::string16& username, @@ -481,13 +467,13 @@ CloseImmediately(); bubble_view_ = new LoginUserMenuView( - this, username, email, type, is_owner, anchor_view, bubble_opener, + username, email, type, is_owner, anchor_view, bubble_opener, show_remove_user, std::move(on_remove_user_warning_shown), std::move(on_remove_user_requested)); // Prevent focus from going into |bubble_view_|. bool had_focus = bubble_view_->GetBubbleOpener() && bubble_view_->GetBubbleOpener()->HasFocus(); - Show(); + bubble_view_->Show(); if (had_focus) { // Try to focus the bubble view only if the bubble opener was focused. bubble_view_->RequestFocus(); @@ -500,7 +486,7 @@ CloseImmediately(); bubble_view_ = new LoginTooltipView(message, anchor_view); - Show(); + bubble_view_->Show(); } void LoginBubble::ShowSelectionMenu(LoginMenuView* menu) { @@ -512,7 +498,7 @@ // Transfer the ownership of |menu| to bubble widget. bubble_view_ = menu; - Show(); + bubble_view_->Show(); if (had_focus) { // Try to focus the bubble view only if the bubble opener was focused. @@ -521,205 +507,21 @@ } void LoginBubble::Close() { - ScheduleAnimation(false /*visible*/); + if (bubble_view_) + bubble_view_->Hide(); } void LoginBubble::CloseImmediately() { DCHECK(bubble_view_); - Reset(false /*widget_already_closing*/); + + if (bubble_view_->GetWidget()) + bubble_view_->GetWidget()->Close(); + + bubble_view_ = nullptr; } bool LoginBubble::IsVisible() { return bubble_view_ && bubble_view_->GetWidget()->IsVisible(); } -void LoginBubble::OnWidgetClosing(views::Widget* widget) { - DCHECK_EQ(bubble_view_->GetWidget(), widget); - Reset(true /*widget_already_closing*/); -} - -void LoginBubble::OnWidgetDestroying(views::Widget* widget) { - OnWidgetClosing(widget); -} - -void LoginBubble::OnWidgetBoundsChanged(views::Widget* widget, - const gfx::Rect& new_bounds) { - EnsureBubbleInScreen(); -} - -void LoginBubble::OnMouseEvent(ui::MouseEvent* event) { - if (event->type() == ui::ET_MOUSE_PRESSED) - ProcessPressedEvent(event->AsLocatedEvent()); -} - -void LoginBubble::OnGestureEvent(ui::GestureEvent* event) { - if (event->type() == ui::ET_GESTURE_TAP || - event->type() == ui::ET_GESTURE_TAP_DOWN) { - ProcessPressedEvent(event->AsLocatedEvent()); - } -} - -void LoginBubble::OnKeyEvent(ui::KeyEvent* event) { - // Ignore VKEY_PROCESSKEY; it is an IME event saying that the key has been - // processed. This event is also generated in tablet mode, ie, after - // submitting a password a VKEY_PROCESSKEY event is generated. If we treat - // that as a normal key event the password bubble will be dismissed - // immediately after submitting. - if (!bubble_view_ || event->type() != ui::ET_KEY_PRESSED || - event->key_code() == ui::VKEY_PROCESSKEY) { - return; - } - - // If current focus view is the button view, don't process the event here, - // let the button logic handle the event and determine show/hide behavior. - if (bubble_view_->GetBubbleOpener() && - bubble_view_->GetBubbleOpener()->HasFocus()) - return; - - // If |bubble_view_| is interactive do not close it. - if (bubble_view_->GetWidget()->IsActive()) - return; - - if (!bubble_view_->IsPersistent()) { - Close(); - } -} - -void LoginBubble::OnLayerAnimationEnded(ui::LayerAnimationSequence* sequence) { - if (!bubble_view_) - return; - - bubble_view_->layer()->GetAnimator()->RemoveObserver(this); - if (!is_visible_) - CloseImmediately(); -} - -void LoginBubble::OnWindowFocused(aura::Window* gained_focus, - aura::Window* lost_focus) { - if (!bubble_view_ || !IsVisible()) - return; - - aura::Window* bubble_window = bubble_view_->GetWidget()->GetNativeView(); - // Bubble window has the focus, do nothing. - if (gained_focus && bubble_window->Contains(gained_focus)) - return; - - if (!bubble_view_->IsPersistent()) - Close(); -} - -void LoginBubble::Show() { - DCHECK(bubble_view_); - views::Widget* widget = - views::BubbleDialogDelegateView::CreateBubble(bubble_view_); - EnsureBubbleInScreen(); - widget->ShowInactive(); - widget->AddObserver(this); - widget->StackAtTop(); - aura::client::GetFocusClient(widget->GetNativeView())->AddObserver(this); - - ScheduleAnimation(true /*visible*/); - - // Fire an alert so ChromeVox will read the contents of the bubble. - bubble_view_->NotifyAccessibilityEvent(ax::mojom::Event::kAlert, - true /*send_native_event*/); -} - -void LoginBubble::ProcessPressedEvent(const ui::LocatedEvent* event) { - if (!bubble_view_) - return; - - // Don't process event inside the bubble. - gfx::Point screen_location = event->location(); - ::wm::ConvertPointToScreen(static_cast<aura::Window*>(event->target()), - &screen_location); - gfx::Rect bounds = bubble_view_->GetWidget()->GetWindowBoundsInScreen(); - if (bounds.Contains(screen_location)) - return; - - // If the user clicks on the button view, don't process the event here, - // let the button logic handle the event and determine show/hide behavior. - if (bubble_view_->GetBubbleOpener()) { - gfx::Rect bubble_opener_bounds = - bubble_view_->GetBubbleOpener()->GetBoundsInScreen(); - if (bubble_opener_bounds.Contains(screen_location)) - return; - } - - if (!bubble_view_->IsPersistent()) - Close(); -} - -void LoginBubble::ScheduleAnimation(bool visible) { - if (!bubble_view_ || is_visible_ == visible) - return; - - if (bubble_view_->GetBubbleOpener()) { - bubble_view_->GetBubbleOpener()->AnimateInkDrop( - visible ? views::InkDropState::ACTIVATED - : views::InkDropState::DEACTIVATED, - nullptr /*event*/); - } - - ui::Layer* layer = bubble_view_->layer(); - layer->GetAnimator()->StopAnimating(); - is_visible_ = visible; - - float opacity_start = 0.0f; - float opacity_end = 1.0f; - if (!is_visible_) - std::swap(opacity_start, opacity_end); - - layer->GetAnimator()->AddObserver(this); - layer->SetOpacity(opacity_start); - { - ui::ScopedLayerAnimationSettings settings(layer->GetAnimator()); - settings.SetTransitionDuration( - base::TimeDelta::FromMilliseconds(kBubbleAnimationDurationMs)); - settings.SetTweenType(is_visible_ ? gfx::Tween::EASE_OUT - : gfx::Tween::EASE_IN); - settings.SetPreemptionStrategy( - ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET); - layer->SetOpacity(opacity_end); - } -} - -void LoginBubble::Reset(bool widget_already_closing) { - DCHECK(bubble_view_); - aura::client::GetFocusClient(bubble_view_->GetWidget()->GetNativeView()) - ->RemoveObserver(this); - bubble_view_->GetWidget()->RemoveObserver(this); - bubble_view_->layer()->GetAnimator()->RemoveObserver(this); - - if (!widget_already_closing) - bubble_view_->GetWidget()->Close(); - is_visible_ = false; - bubble_view_ = nullptr; -} - -void LoginBubble::EnsureBubbleInScreen() { - DCHECK(bubble_view_); - DCHECK(bubble_view_->GetWidget()); - - const gfx::Rect view_bounds = bubble_view_->GetBoundsInScreen(); - const gfx::Rect work_area = - display::Screen::GetScreen() - ->GetDisplayNearestWindow( - bubble_view_->GetWidget()->GetNativeWindow()) - .work_area(); - - int horizontal_offset = 0; - - // If the widget extends past the right side of the screen, make it go to - // the left instead. - if (work_area.right() < view_bounds.right()) { - horizontal_offset = -view_bounds.width(); - } - - bubble_view_->set_anchor_view_insets( - bubble_view_->anchor_view_insets().Offset( - gfx::Vector2d(horizontal_offset, 0))); - bubble_view_->OnAnchorBoundsChanged(); -} - } // namespace ash
diff --git a/ash/login/ui/login_bubble.h b/ash/login/ui/login_bubble.h index db3619c..4022fa7 100644 --- a/ash/login/ui/login_bubble.h +++ b/ash/login/ui/login_bubble.h
@@ -10,7 +10,6 @@ #include "base/strings/string16.h" #include "components/user_manager/user_type.h" #include "ui/aura/client/focus_change_observer.h" -#include "ui/compositor/layer_animation_observer.h" #include "ui/views/controls/label.h" #include "ui/views/view.h" #include "ui/views/widget/widget_observer.h" @@ -20,12 +19,7 @@ class LoginMenuView; // A wrapper for the bubble view in the login screen. -// This class observes keyboard events, mouse clicks and touch down events -// and dismisses the bubble accordingly. -class ASH_EXPORT LoginBubble : public views::WidgetObserver, - public ui::EventHandler, - public ui::LayerAnimationObserver, - public aura::client::FocusChangeObserver { +class ASH_EXPORT LoginBubble : public views::WidgetObserver { public: class TestApi { public: @@ -82,51 +76,11 @@ // True if the bubble is visible. bool IsVisible(); - // views::WidgetObservers: - void OnWidgetClosing(views::Widget* widget) override; - void OnWidgetDestroying(views::Widget* widget) override; - void OnWidgetBoundsChanged(views::Widget* widget, - const gfx::Rect& new_bounds) override; - - // ui::EventHandler: - void OnMouseEvent(ui::MouseEvent* event) override; - void OnGestureEvent(ui::GestureEvent* event) override; - void OnKeyEvent(ui::KeyEvent* event) override; - - // gfx::LayerAnimationObserver: - void OnLayerAnimationEnded(ui::LayerAnimationSequence* sequence) override; - void OnLayerAnimationAborted(ui::LayerAnimationSequence* sequence) override{}; - void OnLayerAnimationScheduled( - ui::LayerAnimationSequence* sequence) override{}; - - // aura::client::FocusChangeObserver: - void OnWindowFocused(aura::Window* gained_focus, - aura::Window* lost_focus) override; - LoginBaseBubbleView* bubble_view() { return bubble_view_; } private: - // Show the bubble widget and schedule animation for bubble showing. - void Show(); - - void ProcessPressedEvent(const ui::LocatedEvent* event); - - // Starts show/hide animation. - void ScheduleAnimation(bool visible); - - // Reset local states and close the widget if it is not already closing. - // |widget_already_closing| : True if we don't need to close the widget - // explicitly. False otherwise. - void Reset(bool widget_already_closing); - - // Repositions the bubble view if it extends too far right or down. - void EnsureBubbleInScreen(); - LoginBaseBubbleView* bubble_view_ = nullptr; - // The status of bubble after animation ends. - bool is_visible_ = false; - DISALLOW_COPY_AND_ASSIGN(LoginBubble); };
diff --git a/ash/login/ui/login_bubble_unittest.cc b/ash/login/ui/login_bubble_unittest.cc index 0e51846..461484fb 100644 --- a/ash/login/ui/login_bubble_unittest.cc +++ b/ash/login/ui/login_bubble_unittest.cc
@@ -91,7 +91,7 @@ } void TearDown() override { - bubble_.reset(); + bubble_->Close(); LoginTestBase::TearDown(); }
diff --git a/ash/manifest.json b/ash/manifest.json index 07d2c06..bac91e0 100644 --- a/ash/manifest.json +++ b/ash/manifest.json
@@ -17,6 +17,7 @@ "ash.mojom.AccessibilityFocusRingController", "ash.mojom.AppListController", "ash.mojom.AshMessageCenterController", + "ash.mojom.AssistantAlarmTimerController", "ash.mojom.AssistantController", "ash.mojom.AssistantScreenContextController", "ash.mojom.AssistantSetupController",
diff --git a/ash/mojo_interface_factory.cc b/ash/mojo_interface_factory.cc index 54b8dff..1519abd 100644 --- a/ash/mojo_interface_factory.cc +++ b/ash/mojo_interface_factory.cc
@@ -10,6 +10,7 @@ #include "ash/accessibility/accessibility_controller.h" #include "ash/accessibility/accessibility_focus_ring_controller.h" #include "ash/app_list/app_list_controller_impl.h" +#include "ash/assistant/assistant_alarm_timer_controller.h" #include "ash/assistant/assistant_controller.h" #include "ash/assistant/assistant_screen_context_controller.h" #include "ash/assistant/assistant_setup_controller.h" @@ -85,6 +86,12 @@ Shell::Get()->ash_display_controller()->BindRequest(std::move(request)); } +void BindAssistantAlarmTimerControllerRequestOnMainThread( + mojom::AssistantAlarmTimerControllerRequest request) { + Shell::Get()->assistant_controller()->alarm_timer_controller()->BindRequest( + std::move(request)); +} + void BindAssistantControllerRequestOnMainThread( mojom::AssistantControllerRequest request) { Shell::Get()->assistant_controller()->BindRequest(std::move(request)); @@ -262,6 +269,10 @@ main_thread_task_runner); if (chromeos::switches::IsAssistantEnabled()) { registry->AddInterface( + base::BindRepeating( + &BindAssistantAlarmTimerControllerRequestOnMainThread), + main_thread_task_runner); + registry->AddInterface( base::BindRepeating(&BindAssistantControllerRequestOnMainThread), main_thread_task_runner); registry->AddInterface(
diff --git a/ash/public/interfaces/assistant_controller.mojom b/ash/public/interfaces/assistant_controller.mojom index 6eb95bce..f074db2 100644 --- a/ash/public/interfaces/assistant_controller.mojom +++ b/ash/public/interfaces/assistant_controller.mojom
@@ -26,6 +26,17 @@ OpenAssistantSettings(); }; +// Interface to the AssistantAlarmTimerController which is owned by the +// AssistantController. Currently used by the Assistant service to notify Ash +// of changes to the underlying alarm/timer state in LibAssistant. +interface AssistantAlarmTimerController { + // Invoked when a timer has started sounding. + OnTimerSoundingStarted(); + + // Invoked when a timer has finished sounding. + OnTimerSoundingFinished(); +}; + // Interface to the AssistantScreenContextController which is owned by the // AssistantController. Currently used by the Assistant service to request // screenshots.
diff --git a/ash/wm/overview/window_selector.cc b/ash/wm/overview/window_selector.cc index ffe67b9..8b090abf 100644 --- a/ash/wm/overview/window_selector.cc +++ b/ash/wm/overview/window_selector.cc
@@ -933,8 +933,10 @@ const ui::KeyEvent& key_event) { // Do not do anything with the events if none of the window grids have windows // in them. - if (IsEmpty()) + if (IsEmpty() && key_event.key_code() != ui::VKEY_BROWSER_BACK && + key_event.key_code() != ui::VKEY_ESCAPE) { return true; + } if (key_event.type() != ui::ET_KEY_PRESSED) return false;
diff --git a/build/fuchsia/linux.sdk.sha1 b/build/fuchsia/linux.sdk.sha1 index dfec044..6fb0908 100644 --- a/build/fuchsia/linux.sdk.sha1 +++ b/build/fuchsia/linux.sdk.sha1
@@ -1 +1 @@ -9d623aaaba7126e941d216d88b0d730afa9297b5 \ No newline at end of file +a227b06661c0633bfb9955e996b07dc5b8aa2cea \ No newline at end of file
diff --git a/build/fuchsia/mac.sdk.sha1 b/build/fuchsia/mac.sdk.sha1 index 4de416c..121fd7c 100644 --- a/build/fuchsia/mac.sdk.sha1 +++ b/build/fuchsia/mac.sdk.sha1
@@ -1 +1 @@ -051be9f89bca52d99c5be72257b549669b0c3ea4 \ No newline at end of file +9ec225bad1f63059a9c4e0abb6fa9bea3c78207e \ No newline at end of file
diff --git a/chrome/android/java/res/layout/keyboard_accessory_sheet_tab_legacy_password_info.xml b/chrome/android/java/res/layout/keyboard_accessory_sheet_tab_legacy_password_info.xml new file mode 100644 index 0000000..6faf213 --- /dev/null +++ b/chrome/android/java/res/layout/keyboard_accessory_sheet_tab_legacy_password_info.xml
@@ -0,0 +1,32 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright 2018 The Chromium Authors. All rights reserved. + Use of this source code is governed by a BSD-style license that can be + found in the LICENSE file. --> + +<LinearLayout + xmlns:android="http://schemas.android.com/apk/res/android" + android:gravity="center_vertical|start" + android:fillViewport="true" + android:layout_height="wrap_content" + android:layout_width="match_parent" + android:orientation="vertical"> + + <TextView + android:id="@+id/suggestion_text" + android:gravity="center_vertical|start" + android:fillViewport="true" + android:minHeight="@dimen/keyboard_accessory_suggestion_height" + android:layout_height="wrap_content" + android:layout_width="match_parent" + android:textAppearance="@style/BlackTitle1"/> + + <TextView + android:id="@+id/password_text" + android:gravity="center_vertical|start" + android:fillViewport="true" + android:minHeight="@dimen/keyboard_accessory_suggestion_height" + android:layout_height="wrap_content" + android:layout_width="match_parent" + android:textAppearance="@style/BlackTitle1"/> + +</LinearLayout>
diff --git a/chrome/android/java/res/layout/password_accessory_sheet_divider.xml b/chrome/android/java/res/layout/password_accessory_sheet_divider.xml deleted file mode 100644 index 117e37a1..0000000 --- a/chrome/android/java/res/layout/password_accessory_sheet_divider.xml +++ /dev/null
@@ -1,9 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- Copyright 2018 The Chromium Authors. All rights reserved. - Use of this source code is governed by a BSD-style license that can be - found in the LICENSE file. --> - -<View style="@style/HorizontalDivider" - xmlns:android="http://schemas.android.com/apk/res/android" - android:layout_marginTop="8dp" - android:layout_marginBottom="8dp" /> \ No newline at end of file
diff --git a/chrome/android/java/res/layout/password_accessory_sheet_label.xml b/chrome/android/java/res/layout/password_accessory_sheet_label.xml index 0dda63d..bd6f9c51 100644 --- a/chrome/android/java/res/layout/password_accessory_sheet_label.xml +++ b/chrome/android/java/res/layout/password_accessory_sheet_label.xml
@@ -3,17 +3,29 @@ Use of this source code is governed by a BSD-style license that can be found in the LICENSE file. --> -<org.chromium.ui.widget.TextViewWithLeading +<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" - android:paddingStart="16dp" - android:paddingEnd="16dp" - android:fillViewport="true" android:gravity="center_vertical|start" - android:textAppearance="@style/BlackHint1" - android:minHeight="48dp" - app:leading="@dimen/text_size_large_leading" - android:paddingTop="12dp" - android:paddingBottom="12dp" + android:fillViewport="true" android:layout_height="wrap_content" - android:layout_width="match_parent"/> + android:layout_width="match_parent" + android:orientation="vertical"> + + <View style="@style/HorizontalDivider" + android:layout_marginTop="0dp" + android:layout_marginBottom="@dimen/keyboard_accessory_sheet_padding" /> + + <org.chromium.ui.widget.TextViewWithLeading + android:id="@+id/tab_title" + android:paddingStart="@dimen/keyboard_accessory_suggestion_padding" + android:paddingEnd="@dimen/keyboard_accessory_suggestion_padding" + android:paddingTop="@dimen/keyboard_accessory_suggestion_offset" + android:paddingBottom="@dimen/keyboard_accessory_suggestion_offset" + android:gravity="center_vertical|start" + android:textAppearance="@style/BlackHint1" + android:minHeight="@dimen/keyboard_accessory_height" + app:leading="@dimen/text_size_large_leading" + android:layout_height="wrap_content" + android:layout_width="match_parent"/> +</LinearLayout> \ No newline at end of file
diff --git a/chrome/android/java/res/layout/password_accessory_sheet_legacy_option.xml b/chrome/android/java/res/layout/password_accessory_sheet_legacy_option.xml new file mode 100644 index 0000000..7288a8c --- /dev/null +++ b/chrome/android/java/res/layout/password_accessory_sheet_legacy_option.xml
@@ -0,0 +1,33 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright 2018 The Chromium Authors. All rights reserved. + Use of this source code is governed by a BSD-style license that can be + found in the LICENSE file. --> +<LinearLayout + xmlns:android="http://schemas.android.com/apk/res/android" + android:gravity="center_vertical|start" + android:fillViewport="true" + android:layout_height="wrap_content" + android:layout_width="match_parent" + android:paddingTop="0dp" + android:paddingBottom="0dp" + android:orientation="vertical"> + + <View style="@style/HorizontalDivider" + android:layout_marginTop="@dimen/keyboard_accessory_sheet_padding" + android:layout_marginBottom="@dimen/keyboard_accessory_sheet_padding" + android:paddingStart="0dp" + android:paddingEnd="0dp" /> + + <TextView + android:id="@+id/footer_text" + android:paddingStart="@dimen/keyboard_accessory_suggestion_padding" + android:paddingEnd="@dimen/keyboard_accessory_suggestion_padding" + android:fillViewport="true" + android:minHeight="@dimen/keyboard_accessory_suggestion_height" + android:gravity="center_vertical|start" + android:textAppearance="@style/BlackTitle1" + android:layout_height="wrap_content" + android:layout_width="match_parent" + android:background="?android:attr/selectableItemBackground"/> + +</LinearLayout>
diff --git a/chrome/android/java/res/layout/password_accessory_sheet_option.xml b/chrome/android/java/res/layout/password_accessory_sheet_option.xml deleted file mode 100644 index 99a71e1..0000000 --- a/chrome/android/java/res/layout/password_accessory_sheet_option.xml +++ /dev/null
@@ -1,16 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- Copyright 2018 The Chromium Authors. All rights reserved. - Use of this source code is governed by a BSD-style license that can be - found in the LICENSE file. --> - -<TextView - xmlns:android="http://schemas.android.com/apk/res/android" - android:paddingStart="16dp" - android:paddingEnd="16dp" - android:fillViewport="true" - android:minHeight="48dp" - android:gravity="center_vertical|start" - android:textAppearance="@style/BlackTitle1" - android:layout_height="wrap_content" - android:layout_width="match_parent" - android:background="?android:attr/selectableItemBackground"/>
diff --git a/chrome/android/java/res/layout/password_accessory_sheet_suggestion.xml b/chrome/android/java/res/layout/password_accessory_sheet_suggestion.xml deleted file mode 100644 index 8d0eb919..0000000 --- a/chrome/android/java/res/layout/password_accessory_sheet_suggestion.xml +++ /dev/null
@@ -1,13 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- Copyright 2018 The Chromium Authors. All rights reserved. - Use of this source code is governed by a BSD-style license that can be - found in the LICENSE file. --> - -<TextView - xmlns:android="http://schemas.android.com/apk/res/android" - android:id="@+id/suggestion_text" - android:gravity="center_vertical|start" - android:fillViewport="true" - android:layout_height="@dimen/keyboard_accessory_suggestion_height" - android:layout_width="match_parent" - android:textAppearance="@style/BlackTitle1"/> \ No newline at end of file
diff --git a/chrome/android/java/res/layout/password_accessory_sheet_top_divider.xml b/chrome/android/java/res/layout/password_accessory_sheet_top_divider.xml deleted file mode 100644 index b7d5a8e..0000000 --- a/chrome/android/java/res/layout/password_accessory_sheet_top_divider.xml +++ /dev/null
@@ -1,8 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- Copyright 2018 The Chromium Authors. All rights reserved. - Use of this source code is governed by a BSD-style license that can be - found in the LICENSE file. --> - -<View style="@style/HorizontalDivider" - xmlns:android="http://schemas.android.com/apk/res/android" - android:layout_marginBottom="8dp"/> \ No newline at end of file
diff --git a/chrome/android/java/res/values/dimens.xml b/chrome/android/java/res/values/dimens.xml index a24fc0f3..d015eecf 100644 --- a/chrome/android/java/res/values/dimens.xml +++ b/chrome/android/java/res/values/dimens.xml
@@ -134,7 +134,9 @@ <dimen name="keyboard_accessory_padding">6dp</dimen> <dimen name="keyboard_accessory_shadow">5dp</dimen> <dimen name="keyboard_accessory_sheet_height">330dp</dimen> + <dimen name="keyboard_accessory_sheet_padding">8dp</dimen> <dimen name="keyboard_accessory_suggestion_padding">16dp</dimen> + <dimen name="keyboard_accessory_suggestion_offset">12dp</dimen> <dimen name="keyboard_accessory_suggestion_height">48dp</dimen> <dimen name="keyboard_accessory_suggestion_icon_size">20dp</dimen>
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ChromeFeatureList.java b/chrome/android/java/src/org/chromium/chrome/browser/ChromeFeatureList.java index 31994586..bf2912a6 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/ChromeFeatureList.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/ChromeFeatureList.java
@@ -239,7 +239,7 @@ public static final String MODAL_PERMISSION_DIALOG_VIEW = "ModalPermissionDialogView"; public static final String NEW_CONTACTS_PICKER = "NewContactsPicker"; public static final String NEW_PHOTO_PICKER = "NewPhotoPicker"; - + public static final String NETWORK_SERVICE = "NetworkService"; public static final String NO_CREDIT_CARD_ABORT = "NoCreditCardAbort"; public static final String NTP_ARTICLE_SUGGESTIONS = "NTPArticleSuggestions"; public static final String NTP_BUTTON = "NTPButton";
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/AccessorySheetTabCoordinator.java b/chrome/android/java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/AccessorySheetTabCoordinator.java new file mode 100644 index 0000000..3bd9df9 --- /dev/null +++ b/chrome/android/java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/AccessorySheetTabCoordinator.java
@@ -0,0 +1,54 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package org.chromium.chrome.browser.autofill.keyboard_accessory; + +import android.graphics.drawable.Drawable; +import android.support.annotation.CallSuper; +import android.support.annotation.LayoutRes; +import android.support.annotation.Nullable; +import android.support.v7.widget.RecyclerView; +import android.view.ViewGroup; + +/** + * This coordinator aims to be the base class for sheets to be added to the + * {@link ManualFillingCoordinator}. It mainly enforces a consistent use of scroll listeners in + * {@link RecyclerView}s. + */ +public abstract class AccessorySheetTabCoordinator implements KeyboardAccessoryData.Tab.Listener { + private final KeyboardAccessoryData.Tab mTab; + private final RecyclerView.OnScrollListener mScrollListener; + + /** + * Creates a keyboard accessory sheet tab coordinator. + * @param icon The icon that represents this sheet in the keyboard accessory tab switcher. + * @param contentDescription A description for this sheet used in the tab switcher. + * @param openingAnnouncement The announced string when opening this sheet. + * @param layout The layout containing all views that are used by this sheet. + * @param tabType The type of this tab as used in histograms. + * @param scrollListener An optional listener that will be bound to an inflated recycler view. + */ + public AccessorySheetTabCoordinator(Drawable icon, String contentDescription, + String openingAnnouncement, @LayoutRes int layout, @AccessoryTabType int tabType, + @Nullable RecyclerView.OnScrollListener scrollListener) { + mTab = new KeyboardAccessoryData.Tab( + icon, contentDescription, openingAnnouncement, layout, tabType, this); + mScrollListener = scrollListener; + } + + @CallSuper + @Override + public void onTabCreated(ViewGroup view) { + AccessorySheetTabViewBinder.initializeView((RecyclerView) view, mScrollListener); + } + + /** + * Returns the Tab object that describes the appearance of this class in the keyboard accessory + * or its accessory sheet. The returned object doesn't change for this instance. + * @return Returns a stable {@link KeyboardAccessoryData.Tab} that is connected to this sheet. + */ + public KeyboardAccessoryData.Tab getTab() { + return mTab; + } +}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/AccessorySheetTabModel.java b/chrome/android/java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/AccessorySheetTabModel.java new file mode 100644 index 0000000..f100fd4 --- /dev/null +++ b/chrome/android/java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/AccessorySheetTabModel.java
@@ -0,0 +1,60 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package org.chromium.chrome.browser.autofill.keyboard_accessory; + +import android.support.annotation.IntDef; +import android.support.v7.widget.RecyclerView; + +import org.chromium.chrome.browser.autofill.keyboard_accessory.KeyboardAccessoryData.AccessorySheetData; +import org.chromium.chrome.browser.modelutil.ListModel; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +/** + * This class describes the {@link ListModel} used for keyboard accessory sheets like the + * {@link PasswordAccessorySheetCoordinator}. + */ +class AccessorySheetTabModel extends ListModel<AccessorySheetTabModel.AccessorySheetDataPiece> { + /** + * The {@link AccessorySheetData} has to be mapped to single items in a {@link RecyclerView}. + * This class allows wrapping the {@link AccessorySheetData} into small chunks that are + * organized in a {@link ListModel}. A specific ViewHolder is defined for each piece. + */ + static class AccessorySheetDataPiece { + @IntDef({Type.TITLE, Type.PASSWORD_INFO, Type.FOOTER_COMMAND}) + @Retention(RetentionPolicy.SOURCE) + public @interface Type { + /** + * An item in title style used to display text. Non-interactive. + */ + int TITLE = 1; + /** + * A section with user credentials. + */ + int PASSWORD_INFO = 2; + /** + * A command at the end of the accessory sheet tab. + */ + int FOOTER_COMMAND = 3; + } + + private Object mDataPiece; + private @Type int mType; + + AccessorySheetDataPiece(Object dataPiece, @Type int type) { + mDataPiece = dataPiece; + mType = type; + } + + public static int getType(AccessorySheetDataPiece accessorySheetDataPiece) { + return accessorySheetDataPiece.mType; + } + + public Object getDataPiece() { + return mDataPiece; + } + } +}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/AccessorySheetTabViewBinder.java b/chrome/android/java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/AccessorySheetTabViewBinder.java new file mode 100644 index 0000000..2bb5225 --- /dev/null +++ b/chrome/android/java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/AccessorySheetTabViewBinder.java
@@ -0,0 +1,45 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package org.chromium.chrome.browser.autofill.keyboard_accessory; + +import android.support.annotation.Nullable; +import android.support.v7.widget.LinearLayoutManager; +import android.support.v7.widget.RecyclerView; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; + +import org.chromium.chrome.browser.autofill.keyboard_accessory.AccessorySheetTabModel.AccessorySheetDataPiece; +import org.chromium.chrome.browser.modelutil.ListModel; + +/** + * This stateless class provides methods to bind a {@link ListModel<AccessorySheetDataPiece>} + * to the {@link RecyclerView} used as view of a tab for the accessory sheet component. + */ +class AccessorySheetTabViewBinder { + /** + * Holds any View that represents a list entry. + */ + static class ElementViewHolder<T, V extends View> extends RecyclerView.ViewHolder { + ElementViewHolder(ViewGroup parent, int layout) { + super(LayoutInflater.from(parent.getContext()).inflate(layout, parent, false)); + } + + @SuppressWarnings("unchecked") + void bind(AccessorySheetDataPiece accessorySheetDataWrapper) { + bind((T) accessorySheetDataWrapper.getDataPiece(), (V) itemView); + } + + void bind(T t, V view) {} + } + + static void initializeView( + RecyclerView view, @Nullable RecyclerView.OnScrollListener scrollListener) { + view.setLayoutManager( + new LinearLayoutManager(view.getContext(), LinearLayoutManager.VERTICAL, false)); + view.setItemAnimator(null); + if (scrollListener != null) view.addOnScrollListener(scrollListener); + } +} \ No newline at end of file
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/KeyboardAccessoryData.java b/chrome/android/java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/KeyboardAccessoryData.java index 1582bf92..16941a8 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/KeyboardAccessoryData.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/KeyboardAccessoryData.java
@@ -176,27 +176,13 @@ } /** - * This describes an item in a accessory sheet. They are usually list items that were created - * natively. - * - * TODO(crbug.com/902425): Remove this class once all code in the frontend uses - * AccessorySheetData. + * Represents a Profile, or a Credit Card, or the credentials for a website + * (username + password), to be shown on the manual fallback UI. */ - public final static class Item { - private final int mType; - private final String mCaption; - private final String mContentDescription; - private final boolean mIsObfuscated; - private final @Nullable Callback<Item> mItemSelectedCallback; + public final static class UserInfo { + private final List<Field> mFields = new ArrayList<>(); private final @Nullable FaviconProvider mFaviconProvider; - /** - * Items will call a class that implements this interface to request a favicon. - * - * TODO(crbug.com/902425): Move this to UserInfo.Field once Item is deprecated and - * generalize it so it can handle static assets for credit card - * items. - */ interface FaviconProvider { /** * Starts a request for a favicon. The callback can be called either asynchronously or @@ -207,141 +193,6 @@ } /** - * Creates a new Item of type {@link ItemType#LABEL}. It is not interactive. - * @param caption The text of the displayed item. - * @param contentDescription The description of this item (i.e. used for accessibility). - */ - public static Item createLabel(String caption, String contentDescription) { - return new Item(ItemType.LABEL, caption, contentDescription, false, null, null); - } - - /** - * Creates a new Item of type {@link ItemType#SUGGESTION} if has a callback, otherwise, it - * will be {@link ItemType#NON_INTERACTIVE_SUGGESTION}. It usually is part of a list of - * suggestions and can have a callback that is triggered on selection. - * @param caption The text of the displayed item. Only plain text if |isObfuscated| is - * false. - * @param contentDescription The description of this item (i.e. used for accessibility). - * @param isObfuscated If true, the displayed caption is transformed into stars. - * @param itemSelectedCallback A click on this item will invoke this callback. Optional. - */ - public static Item createSuggestion(String caption, String contentDescription, - boolean isObfuscated, @Nullable Callback<Item> itemSelectedCallback, - @Nullable FaviconProvider faviconProvider) { - if (itemSelectedCallback == null) { - return new Item(ItemType.NON_INTERACTIVE_SUGGESTION, caption, contentDescription, - isObfuscated, null, faviconProvider); - } - return new Item(ItemType.SUGGESTION, caption, contentDescription, isObfuscated, - itemSelectedCallback, faviconProvider); - } - - /** - * Creates an Item of type {@link ItemType#DIVIDER}. Basically, it's a horizontal line. - */ - public static Item createDivider() { - return new Item(ItemType.DIVIDER, null, null, false, null, null); - } - - /** - * Creates a new Item of type {@link ItemType#OPTION}. They are normally independent items - * that trigger a unique action (e.g. generate a password or navigate to an overview). - * @param caption The text of the displayed option. - * @param contentDescription The description of this option (i.e. used for accessibility). - * @param callback A click on this item will invoke this callback. - */ - public static Item createOption( - String caption, String contentDescription, Callback<Item> callback) { - return new Item(ItemType.OPTION, caption, contentDescription, false, callback, null); - } - - /** - * Creates an Item of type {@link ItemType#TOP_DIVIDER}. A horizontal line meant to be - * displayed at the top of the accessory sheet. - */ - public static Item createTopDivider() { - return new Item(ItemType.TOP_DIVIDER, null, null, false, null, null); - } - - /** - * Creates a new item. - * @param type Type of the item (e.g. non-clickable LABEL or clickable SUGGESTION). - * @param caption The text of the displayed item. Only plain text if |isObfuscated| is - * false. - * @param contentDescription The description of this item (i.e. used for accessibility). - * @param isObfuscated If true, the displayed caption is transformed into stars. - * @param itemSelectedCallback If the Item is interactive, a click on it will trigger this. - * @param faviconProvider - */ - private Item(@ItemType int type, String caption, String contentDescription, - boolean isObfuscated, @Nullable Callback<Item> itemSelectedCallback, - @Nullable FaviconProvider faviconProvider) { - mType = type; - mCaption = caption; - mContentDescription = contentDescription; - mIsObfuscated = isObfuscated; - mItemSelectedCallback = itemSelectedCallback; - mFaviconProvider = faviconProvider; - } - - /** - * Returns the type of the item. - * @return Returns a {@link ItemType}. - */ - public @ItemType int getType() { - return mType; - } - - /** - * Returns a human-readable, translated string that will appear as text of the item. - * @return A short descriptive string of the item. - */ - public String getCaption() { - return mCaption; - } - - /** - * Returns a translated description that can be used for accessibility. - * @return A short description of the displayed item. - */ - public String getContentDescription() { - return mContentDescription; - } - - /** - * Returns whether obfuscation should be applied to the item's caption, for example to hide - * passwords. - * @return Returns true if obfuscation should be applied to the caption. - */ - public boolean isObfuscated() { - return mIsObfuscated; - } - - /** - * The delegate is called when the Item is selected by a user. - */ - public Callback<Item> getItemSelectedCallback() { - return mItemSelectedCallback; - } - - public void fetchFavicon(@Px int desiredSize, Callback<Bitmap> faviconCallback) { - if (mFaviconProvider == null) { - faviconCallback.onResult(null); // Use default icon without provider. - return; - } - mFaviconProvider.fetchFavicon(desiredSize, faviconCallback); - } - } - - /** - * Represents a Profile, or a Credit Card, or the credentials for a website - * (username + password), to be shown on the manual fallback UI. - */ - public final static class UserInfo { - private final List<Field> mFields = new ArrayList<>(); - private final @Nullable Item.FaviconProvider mFaviconProvider; - - /** * Represents an item (either selectable or not) presented on the UI, such as the username * or a credit card number. */ @@ -404,7 +255,7 @@ } } - public UserInfo(@Nullable Item.FaviconProvider faviconProvider) { + public UserInfo(@Nullable FaviconProvider faviconProvider) { mFaviconProvider = faviconProvider; } @@ -425,9 +276,9 @@ /** * Possibly holds a favicon provider. - * @return A {@link Item.FaviconProvider}. Optional. + * @return A {@link FaviconProvider}. Optional. */ - public @Nullable Item.FaviconProvider getFaviconProvider() { + public @Nullable FaviconProvider getFaviconProvider() { return mFaviconProvider; } }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/KeyboardAccessoryMetricsRecorder.java b/chrome/android/java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/KeyboardAccessoryMetricsRecorder.java index d25ea7a..a548189 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/KeyboardAccessoryMetricsRecorder.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/KeyboardAccessoryMetricsRecorder.java
@@ -4,13 +4,16 @@ package org.chromium.chrome.browser.autofill.keyboard_accessory; +import static org.chromium.chrome.browser.autofill.keyboard_accessory.AccessorySheetTabModel.AccessorySheetDataPiece.Type.PASSWORD_INFO; +import static org.chromium.chrome.browser.autofill.keyboard_accessory.AccessorySheetTabModel.AccessorySheetDataPiece.getType; import static org.chromium.chrome.browser.autofill.keyboard_accessory.AccessorySheetTrigger.MANUAL_OPEN; import android.support.annotation.Nullable; import org.chromium.base.VisibleForTesting; import org.chromium.base.metrics.RecordHistogram; -import org.chromium.chrome.browser.autofill.keyboard_accessory.KeyboardAccessoryData.Item; +import org.chromium.chrome.browser.autofill.keyboard_accessory.AccessorySheetTabModel.AccessorySheetDataPiece; +import org.chromium.chrome.browser.autofill.keyboard_accessory.KeyboardAccessoryData.UserInfo; import org.chromium.chrome.browser.modelutil.ListModel; import org.chromium.chrome.browser.modelutil.ListObservable; import org.chromium.chrome.browser.modelutil.PropertyKey; @@ -23,7 +26,7 @@ /** * This class provides helpers to record metrics related to the keyboard accessory and its sheets. * It can set up observers to observe {@link KeyboardAccessoryProperties}-based models, {@link - * AccessorySheetProperties}-based models or {@link ListObservable<Item>}s, and records metrics + * AccessorySheetProperties}-based models or {@link ListObservable<>}s, and records metrics * accordingly. */ public class KeyboardAccessoryMetricsRecorder { @@ -305,10 +308,15 @@ * @param suggestionList The list containing all suggestions. */ static void recordSheetSuggestions( - @AccessoryTabType int tabType, ListModel<Item> suggestionList) { + @AccessoryTabType int tabType, ListModel<AccessorySheetDataPiece> suggestionList) { int interactiveSuggestions = 0; for (int i = 0; i < suggestionList.size(); ++i) { - if (suggestionList.get(i).getType() == ItemType.SUGGESTION) ++interactiveSuggestions; + if (getType(suggestionList.get(i)) == PASSWORD_INFO) { + UserInfo info = (UserInfo) suggestionList.get(i).getDataPiece(); + for (UserInfo.Field field : info.getFields()) { + if (field.isSelectable()) ++interactiveSuggestions; + } + } } RecordHistogram.recordCount100Histogram( getHistogramForType(UMA_KEYBOARD_ACCESSORY_SHEET_SUGGESTIONS, tabType),
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/PasswordAccessorySheetCoordinator.java b/chrome/android/java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/PasswordAccessorySheetCoordinator.java index 2eb42d5..2e8678e 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/PasswordAccessorySheetCoordinator.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/PasswordAccessorySheetCoordinator.java
@@ -4,12 +4,7 @@ package org.chromium.chrome.browser.autofill.keyboard_accessory; -import static org.chromium.chrome.browser.autofill.keyboard_accessory.PasswordAccessorySheetProperties.CREDENTIALS; -import static org.chromium.chrome.browser.autofill.keyboard_accessory.PasswordAccessorySheetProperties.PASSWORD_SHEET_DATA; -import static org.chromium.chrome.browser.autofill.keyboard_accessory.PasswordAccessorySheetProperties.SCROLL_LISTENER; - import android.content.Context; -import android.graphics.Bitmap; import android.graphics.drawable.Drawable; import android.support.annotation.Nullable; import android.support.v7.content.res.AppCompatResources; @@ -18,11 +13,10 @@ import org.chromium.base.VisibleForTesting; import org.chromium.chrome.R; -import org.chromium.chrome.browser.autofill.keyboard_accessory.KeyboardAccessoryData.Item; -import org.chromium.chrome.browser.autofill.keyboard_accessory.PasswordAccessorySheetProperties.AccessorySheetDataPiece; -import org.chromium.chrome.browser.autofill.keyboard_accessory.PasswordAccessorySheetViewBinder.ItemViewHolder; +import org.chromium.chrome.browser.autofill.keyboard_accessory.AccessorySheetTabModel.AccessorySheetDataPiece; +import org.chromium.chrome.browser.autofill.keyboard_accessory.KeyboardAccessoryData.AccessorySheetData; +import org.chromium.chrome.browser.autofill.keyboard_accessory.KeyboardAccessoryData.Provider; import org.chromium.chrome.browser.modelutil.ListModel; -import org.chromium.chrome.browser.modelutil.PropertyModel; import org.chromium.chrome.browser.modelutil.RecyclerViewAdapter; import org.chromium.chrome.browser.modelutil.SimpleRecyclerViewMcp; @@ -30,15 +24,9 @@ * This component is a tab that can be added to the {@link ManualFillingCoordinator} which shows it * as bottom sheet below the keyboard accessory. */ -public class PasswordAccessorySheetCoordinator implements KeyboardAccessoryData.Tab.Listener { - private final PropertyModel mModel = - new PropertyModel.Builder(CREDENTIALS, PASSWORD_SHEET_DATA, SCROLL_LISTENER) - .with(CREDENTIALS, new ListModel<>()) - .with(PASSWORD_SHEET_DATA, new ListModel<>()) - .with(SCROLL_LISTENER, null) - .build(); +public class PasswordAccessorySheetCoordinator extends AccessorySheetTabCoordinator { + private final AccessorySheetTabModel mModel = new AccessorySheetTabModel(); private final PasswordAccessorySheetMediator mMediator; - private final KeyboardAccessoryData.Tab mTab; @VisibleForTesting static class IconProvider { @@ -67,11 +55,6 @@ } } - interface FaviconProvider { - @Nullable - Bitmap getFavicon(); - } - /** * Creates the passwords tab. * @param context The {@link Context} containing resources like icons and layouts for this tab. @@ -79,15 +62,16 @@ */ public PasswordAccessorySheetCoordinator( Context context, @Nullable RecyclerView.OnScrollListener scrollListener) { - mMediator = new PasswordAccessorySheetMediator(mModel, scrollListener); - mTab = new KeyboardAccessoryData.Tab(IconProvider.getInstance().getIcon(context), + super(IconProvider.getInstance().getIcon(context), context.getString(R.string.password_accessory_sheet_toggle), context.getString(R.string.password_accessory_sheet_opened), - R.layout.password_accessory_sheet, AccessoryTabType.PASSWORDS, this); + R.layout.password_accessory_sheet, AccessoryTabType.PASSWORDS, scrollListener); + mMediator = new PasswordAccessorySheetMediator(mModel); } @Override public void onTabCreated(ViewGroup view) { + super.onTabCreated(view); PasswordAccessorySheetViewBinder.initializeView((RecyclerView) view, mModel); } @@ -97,42 +81,30 @@ } /** + * Registers the provider pushing a complete new instance of {@link AccessorySheetData} that + * should be displayed as sheet for this tab. + * @param accessorySheetDataProvider A {@link Provider<AccessorySheetData>}. + */ + void registerDataProvider(Provider<AccessorySheetData> accessorySheetDataProvider) { + accessorySheetDataProvider.addObserver(mMediator); + } + + /** * Creates an adapter to an {@link PasswordAccessorySheetViewBinder} that is wired - * up to the model change processor which listens to the {@link ListModel <Item>}. + * up to a model change processor listening to the {@link ListModel <AccessorySheetDataPiece>}. * @param model the {@link ListModel <Item>} the adapter gets its data from. * @return Returns a fully initialized and wired adapter to a PasswordAccessorySheetViewBinder. */ - static RecyclerViewAdapter<ItemViewHolder, Void> createAdapter(ListModel<Item> model) { + static RecyclerViewAdapter<AccessorySheetTabViewBinder.ElementViewHolder, Void> createAdapter( + AccessorySheetTabModel model) { return new RecyclerViewAdapter<>( - new SimpleRecyclerViewMcp<>(model, Item::getType, ItemViewHolder::bind), - ItemViewHolder::create); - } - - /** - * Registered item providers can replace the currently shown data in the password sheet. - * @param dataProvider The provider this component will listen to. - */ - public void registerDataProvider( - KeyboardAccessoryData.Provider<KeyboardAccessoryData.AccessorySheetData> dataProvider) { - dataProvider.addObserver(mMediator); - } - - /** - * Returns the Tab object that describes the appearance of this class in the keyboard accessory - * or its accessory sheet. The returned object doesn't change for this instance. - * @return Returns a stable {@link KeyboardAccessoryData.Tab} that is connected to this sheet. - */ - public KeyboardAccessoryData.Tab getTab() { - return mTab; + new SimpleRecyclerViewMcp<>(model, AccessorySheetDataPiece::getType, + AccessorySheetTabViewBinder.ElementViewHolder::bind), + PasswordAccessorySheetViewBinder::create); } @VisibleForTesting - ListModel<Item> getItemsForTesting() { - return mModel.get(CREDENTIALS); - } - - @VisibleForTesting - ListModel<AccessorySheetDataPiece> getSheetDataPiecesForTesting() { - return mModel.get(PASSWORD_SHEET_DATA); + AccessorySheetTabModel getSheetDataPiecesForTesting() { + return mModel; } }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/PasswordAccessorySheetMediator.java b/chrome/android/java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/PasswordAccessorySheetMediator.java index b289b52..40d7f69 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/PasswordAccessorySheetMediator.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/PasswordAccessorySheetMediator.java
@@ -4,19 +4,11 @@ package org.chromium.chrome.browser.autofill.keyboard_accessory; -import static org.chromium.chrome.browser.autofill.keyboard_accessory.PasswordAccessorySheetProperties.CREDENTIALS; -import static org.chromium.chrome.browser.autofill.keyboard_accessory.PasswordAccessorySheetProperties.PASSWORD_SHEET_DATA; -import static org.chromium.chrome.browser.autofill.keyboard_accessory.PasswordAccessorySheetProperties.SCROLL_LISTENER; - -import android.support.annotation.Nullable; -import android.support.v7.widget.RecyclerView; - +import org.chromium.chrome.browser.autofill.keyboard_accessory.AccessorySheetTabModel.AccessorySheetDataPiece; +import org.chromium.chrome.browser.autofill.keyboard_accessory.AccessorySheetTabModel.AccessorySheetDataPiece.Type; import org.chromium.chrome.browser.autofill.keyboard_accessory.KeyboardAccessoryData.AccessorySheetData; import org.chromium.chrome.browser.autofill.keyboard_accessory.KeyboardAccessoryData.FooterCommand; -import org.chromium.chrome.browser.autofill.keyboard_accessory.KeyboardAccessoryData.Item; import org.chromium.chrome.browser.autofill.keyboard_accessory.KeyboardAccessoryData.UserInfo; -import org.chromium.chrome.browser.autofill.keyboard_accessory.PasswordAccessorySheetProperties.AccessorySheetDataPiece; -import org.chromium.chrome.browser.autofill.keyboard_accessory.PasswordAccessorySheetProperties.AccessorySheetDataPiece.Type; import org.chromium.chrome.browser.modelutil.PropertyModel; import org.chromium.chrome.browser.modelutil.PropertyModelChangeProcessor; @@ -26,53 +18,23 @@ /** * This class contains all logic for the password accessory sheet component. Changes to its internal * {@link PropertyModel} are observed by a {@link PropertyModelChangeProcessor} and affect the - * {@link PasswordAccessorySheetView}. + * password accessory sheet tab view. */ class PasswordAccessorySheetMediator implements KeyboardAccessoryData.Observer<AccessorySheetData> { - private final PropertyModel mModel; + private final AccessorySheetTabModel mModel; @Override public void onItemAvailable(int typeId, AccessorySheetData accessorySheetData) { - mModel.get(CREDENTIALS).set(convertToItems(accessorySheetData)); - mModel.get(PASSWORD_SHEET_DATA).set(splitIntoDataPieces(accessorySheetData)); + mModel.set(splitIntoDataPieces(accessorySheetData)); } - PasswordAccessorySheetMediator( - PropertyModel model, @Nullable RecyclerView.OnScrollListener scrollListener) { + PasswordAccessorySheetMediator(AccessorySheetTabModel model) { mModel = model; - mModel.set(SCROLL_LISTENER, scrollListener); } void onTabShown() { KeyboardAccessoryMetricsRecorder.recordActionImpression(AccessoryAction.MANAGE_PASSWORDS); - KeyboardAccessoryMetricsRecorder.recordSheetSuggestions( - AccessoryTabType.PASSWORDS, mModel.get(CREDENTIALS)); - } - - private Item[] convertToItems(AccessorySheetData accessorySheetData) { - if (accessorySheetData == null) return new Item[0]; - - List<Item> items = new ArrayList<>(); - - items.add(Item.createTopDivider()); - items.add(Item.createLabel(accessorySheetData.getTitle(), accessorySheetData.getTitle())); - - for (UserInfo userInfo : accessorySheetData.getUserInfoList()) { - for (UserInfo.Field field : userInfo.getFields()) { - items.add(Item.createSuggestion(field.getDisplayText(), field.getA11yDescription(), - field.isObfuscated(), - field.isSelectable() ? (item -> field.triggerSelection()) : null, - userInfo.getFaviconProvider())); - } - } - - if (!accessorySheetData.getFooterCommands().isEmpty()) items.add(Item.createDivider()); - for (FooterCommand command : accessorySheetData.getFooterCommands()) { - items.add(Item.createOption( - command.getDisplayText(), command.getDisplayText(), (i) -> command.execute())); - } - - return items.toArray(new Item[0]); + KeyboardAccessoryMetricsRecorder.recordSheetSuggestions(AccessoryTabType.PASSWORDS, mModel); } private AccessorySheetDataPiece[] splitIntoDataPieces(AccessorySheetData accessorySheetData) {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/PasswordAccessorySheetProperties.java b/chrome/android/java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/PasswordAccessorySheetProperties.java deleted file mode 100644 index b999e8d..0000000 --- a/chrome/android/java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/PasswordAccessorySheetProperties.java +++ /dev/null
@@ -1,78 +0,0 @@ -// Copyright 2018 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -package org.chromium.chrome.browser.autofill.keyboard_accessory; - -import static android.support.v7.widget.RecyclerView.OnScrollListener; - -import android.support.annotation.IntDef; -import android.support.v7.widget.RecyclerView; - -import org.chromium.chrome.browser.autofill.keyboard_accessory.KeyboardAccessoryData.AccessorySheetData; -import org.chromium.chrome.browser.autofill.keyboard_accessory.PasswordAccessorySheetViewBinder.ItemViewHolder; -import org.chromium.chrome.browser.modelutil.ListModel; -import org.chromium.chrome.browser.modelutil.PropertyModel.ReadableObjectPropertyKey; -import org.chromium.chrome.browser.modelutil.PropertyModel.WritableObjectPropertyKey; - -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; - -// TODO(crbug.com/902425): Drop the "Password-" as soon as its used for other sheets. -/** - * This class holds properties that are used to build a model for the password accessory sheet - * component. These properties store the state of the {@link PasswordAccessorySheetView} which is - * bound to model using the {@link PasswordAccessorySheetViewBinder}. - * It is built in the {@link PasswordAccessorySheetCoordinator} and modified by the - * {@link PasswordAccessorySheetMediator}. - */ -class PasswordAccessorySheetProperties { - static final ReadableObjectPropertyKey<ListModel<KeyboardAccessoryData.Item>> CREDENTIALS = - new ReadableObjectPropertyKey<>(); - static final ReadableObjectPropertyKey<ListModel<AccessorySheetDataPiece>> PASSWORD_SHEET_DATA = - new ReadableObjectPropertyKey<>(); - static final WritableObjectPropertyKey<OnScrollListener> SCROLL_LISTENER = - new WritableObjectPropertyKey<>(); - - /** - * The {@link AccessorySheetData} has to be mapped to single items in a {@link RecyclerView}. - * This class allows to wrap the {@link AccessorySheetData} into small chunks that are organized - * in a {@link ListModel}. A specific {@link ItemViewHolder}s is defined for each piece. - */ - static class AccessorySheetDataPiece { - @IntDef({Type.TITLE, Type.PASSWORD_INFO, Type.FOOTER_COMMAND}) - @Retention(RetentionPolicy.SOURCE) - public @interface Type { - /** - * An item in title style used to display text. Non-interactive. - */ - int TITLE = 1; - /** - * A section with user credentials. - */ - int PASSWORD_INFO = 2; - /** - * A command at the end of the accessory sheet tab. - */ - int FOOTER_COMMAND = 3; - } - - private Object mDataPiece; - private @Type int mType; - - AccessorySheetDataPiece(Object dataPiece, @Type int type) { - mDataPiece = dataPiece; - mType = type; - } - - public static int getType(AccessorySheetDataPiece accessorySheetDataPiece) { - return accessorySheetDataPiece.mType; - } - - public Object getDataPiece() { - return mDataPiece; - } - } - - private PasswordAccessorySheetProperties() {} -}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/PasswordAccessorySheetView.java b/chrome/android/java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/PasswordAccessorySheetView.java deleted file mode 100644 index 1f87db6..0000000 --- a/chrome/android/java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/PasswordAccessorySheetView.java +++ /dev/null
@@ -1,7 +0,0 @@ -// Copyright 2018 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -package org.chromium.chrome.browser.autofill.keyboard_accessory; - -class PasswordAccessorySheetView {} \ No newline at end of file
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/PasswordAccessorySheetViewBinder.java b/chrome/android/java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/PasswordAccessorySheetViewBinder.java index b08f01c..38da317 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/PasswordAccessorySheetViewBinder.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/PasswordAccessorySheetViewBinder.java
@@ -4,129 +4,87 @@ package org.chromium.chrome.browser.autofill.keyboard_accessory; -import static org.chromium.chrome.browser.autofill.keyboard_accessory.PasswordAccessorySheetProperties.CREDENTIALS; -import static org.chromium.chrome.browser.autofill.keyboard_accessory.PasswordAccessorySheetProperties.SCROLL_LISTENER; - import android.content.res.TypedArray; import android.graphics.Bitmap; import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.Drawable; import android.support.annotation.Nullable; import android.support.v7.content.res.AppCompatResources; -import android.support.v7.widget.LinearLayoutManager; import android.support.v7.widget.RecyclerView; import android.text.method.PasswordTransformationMethod; -import android.view.LayoutInflater; -import android.view.View; import android.view.ViewGroup; +import android.widget.LinearLayout; import android.widget.TextView; import org.chromium.base.ApiCompatibilityUtils; import org.chromium.chrome.R; -import org.chromium.chrome.browser.autofill.keyboard_accessory.KeyboardAccessoryData.Item; +import org.chromium.chrome.browser.autofill.keyboard_accessory.AccessorySheetTabModel.AccessorySheetDataPiece; +import org.chromium.chrome.browser.autofill.keyboard_accessory.AccessorySheetTabViewBinder.ElementViewHolder; +import org.chromium.chrome.browser.autofill.keyboard_accessory.KeyboardAccessoryData.FooterCommand; import org.chromium.chrome.browser.modelutil.ListModel; -import org.chromium.chrome.browser.modelutil.PropertyModel; /** * This stateless class provides methods to bind the items in a {@link ListModel <Item>} * to the {@link RecyclerView} used as view of the Password accessory sheet component. */ class PasswordAccessorySheetViewBinder { - /** - * Holds any View that represents a list entry. - */ - static class ItemViewHolder extends RecyclerView.ViewHolder { - ItemViewHolder(View itemView) { - super(itemView); + static ElementViewHolder create(ViewGroup parent, @AccessorySheetDataPiece.Type int viewType) { + switch (viewType) { + case AccessorySheetDataPiece.Type.TITLE: + return new PasswordsTitleViewHolder(parent); + case AccessorySheetDataPiece.Type.PASSWORD_INFO: + return new PasswordsInfoViewHolder(parent); + case AccessorySheetDataPiece.Type.FOOTER_COMMAND: + return new FooterCommandViewHolder(parent); } - - static ItemViewHolder create(ViewGroup parent, @ItemType int viewType) { - switch (viewType) { - case ItemType.LABEL: - return new TextViewHolder( - LayoutInflater.from(parent.getContext()) - .inflate(R.layout.password_accessory_sheet_label, parent, - false)); - case ItemType.SUGGESTION: // Intentional fallthrough. - case ItemType.NON_INTERACTIVE_SUGGESTION: { - return new IconTextViewHolder( - LayoutInflater.from(parent.getContext()) - .inflate(R.layout.password_accessory_sheet_suggestion, parent, - false)); - } - case ItemType.DIVIDER: - return new ItemViewHolder( - LayoutInflater.from(parent.getContext()) - .inflate(R.layout.password_accessory_sheet_divider, parent, - false)); - case ItemType.OPTION: - return new TextViewHolder( - LayoutInflater.from(parent.getContext()) - .inflate(R.layout.password_accessory_sheet_option, parent, - false)); - case ItemType.TOP_DIVIDER: - return new ItemViewHolder( - LayoutInflater.from(parent.getContext()) - .inflate(R.layout.password_accessory_sheet_top_divider, parent, - false)); - } - assert false : viewType; - return null; - } - - /** - * Binds the item's state to the held {@link View}. Subclasses of this generic view holder - * might want to actually bind the item state to the view. - * @param item The item that determines the state of the held View. - */ - protected void bind(Item item) {} + assert false : "Unhandled type of data piece: " + viewType; + return null; } /** - * Holds a TextView that represents a list entry. + * Holds a the TextView with the title of the sheet and a divider for the accessory bar. */ - static class TextViewHolder extends ItemViewHolder { - TextViewHolder(View itemView) { - super(itemView); - } - - /** - * Returns the text view of this item if there is one. - * @return Returns a {@link TextView}. - */ - protected TextView getTextView() { - return (TextView) itemView; + static class PasswordsTitleViewHolder extends ElementViewHolder<String, LinearLayout> { + PasswordsTitleViewHolder(ViewGroup parent) { + super(parent, R.layout.password_accessory_sheet_label); } @Override - protected void bind(Item item) { - super.bind(item); - getTextView().setTransformationMethod( - item.isObfuscated() ? new PasswordTransformationMethod() : null); - getTextView().setText(item.getCaption()); - getTextView().setContentDescription(item.getContentDescription()); - if (item.getItemSelectedCallback() != null) { - getTextView().setOnClickListener( - src -> item.getItemSelectedCallback().onResult(item)); - } else { - getTextView().setOnClickListener(null); - } - // |setOnClickListener| has set this to |true|, so update it afterwards. - getTextView().setClickable(item.getItemSelectedCallback() != null); + protected void bind(String displayText, LinearLayout view) { + TextView titleView = view.findViewById(R.id.tab_title); + titleView.setText(displayText); + titleView.setContentDescription(displayText); } } /** - * Holds a TextView that represents a list entry. + * Holds a TextView that represents a bottom command and is separated to the top by a divider. */ - static class IconTextViewHolder extends TextViewHolder { - private final TextView mSuggestionText; + static class FooterCommandViewHolder extends ElementViewHolder<FooterCommand, LinearLayout> { + FooterCommandViewHolder(ViewGroup parent) { + super(parent, R.layout.password_accessory_sheet_legacy_option); + } + + @Override + protected void bind(FooterCommand footerCommand, LinearLayout layout) { + TextView view = layout.findViewById(R.id.footer_text); + view.setText(footerCommand.getDisplayText()); + view.setContentDescription(footerCommand.getDisplayText()); + view.setOnClickListener(v -> footerCommand.execute()); + view.setClickable(true); + } + } + + /** + * Holds a layout for a username and a password with a small icon. + */ + static class PasswordsInfoViewHolder + extends ElementViewHolder<KeyboardAccessoryData.UserInfo, LinearLayout> { private final int mPadding; private final int mIconSize; - IconTextViewHolder(View itemView) { - super(itemView); - mSuggestionText = itemView.findViewById(R.id.suggestion_text); + PasswordsInfoViewHolder(ViewGroup parent) { + super(parent, R.layout.keyboard_accessory_sheet_tab_legacy_password_info); mPadding = itemView.getContext().getResources().getDimensionPixelSize( R.dimen.keyboard_accessory_suggestion_padding); mIconSize = itemView.getContext().getResources().getDimensionPixelSize( @@ -134,42 +92,44 @@ } @Override - protected TextView getTextView() { - return mSuggestionText; + protected void bind(KeyboardAccessoryData.UserInfo info, LinearLayout layout) { + TextView username = layout.findViewById(R.id.suggestion_text); + TextView password = layout.findViewById(R.id.password_text); + bindTextView(username, info.getFields().get(0)); + bindTextView(password, info.getFields().get(1)); + + // Set the default icon for username, then try to get a better one. + setIconForBitmap(username, null); + if (info.getFaviconProvider() != null) { + info.getFaviconProvider().fetchFavicon( + mIconSize, icon -> setIconForBitmap(username, icon)); + } + username.setPadding(mPadding, 0, mPadding, 0); + // Passwords have no icon, so increase the offset. + password.setPadding(2 * mPadding + mIconSize, 0, mPadding, 0); } - @Override - protected void bind(Item item) { - super.bind(item); - getTextView().setClickable(true); // Ensures that "disabled" is announced. - if (item.getItemSelectedCallback() == null) { - mSuggestionText.setEnabled(false); - mSuggestionText.setBackground(null); - } else { - mSuggestionText.setEnabled(true); - TypedArray a = mSuggestionText.getContext().obtainStyledAttributes( - new int[] {R.attr.selectableItemBackground}); - Drawable suggestionBackground = a.getDrawable(0); - a.recycle(); - mSuggestionText.setBackground(suggestionBackground); - } - - // Setting the background to selectableItemBackground resets the padding to 0 on - // Jelly Bean, so the padding should be set after the background. - if (!item.isObfuscated()) { - setIconForBitmap(null); // Set the default icon, then try to get a better one. - item.fetchFavicon(itemView.getContext().getResources().getDimensionPixelSize( - R.dimen.keyboard_accessory_suggestion_icon_size), - this::setIconForBitmap); - mSuggestionText.setPadding(mPadding, 0, mPadding, 0); - } else { - ApiCompatibilityUtils.setCompoundDrawablesRelative( - mSuggestionText, null, null, null, null); - mSuggestionText.setPadding(2 * mPadding + mIconSize, 0, mPadding, 0); - } + private void bindTextView(TextView text, KeyboardAccessoryData.UserInfo.Field field) { + text.setTransformationMethod( + field.isObfuscated() ? new PasswordTransformationMethod() : null); + text.setText(field.getDisplayText()); + text.setContentDescription(field.getA11yDescription()); + text.setOnClickListener(!field.isSelectable() ? null : src -> field.triggerSelection()); + text.setClickable(true); // Ensures that "disabled" is announced. + text.setEnabled(field.isSelectable()); + text.setBackground(getBackgroundDrawable(field.isSelectable())); } - private void setIconForBitmap(@Nullable Bitmap favicon) { + private @Nullable Drawable getBackgroundDrawable(boolean selectable) { + if (!selectable) return null; + TypedArray a = itemView.getContext().obtainStyledAttributes( + new int[] {R.attr.selectableItemBackground}); + Drawable suggestionBackground = a.getDrawable(0); + a.recycle(); + return suggestionBackground; + } + + private void setIconForBitmap(TextView text, @Nullable Bitmap favicon) { Drawable icon; if (favicon == null) { icon = AppCompatResources.getDrawable( @@ -180,19 +140,12 @@ if (icon != null) { // AppCompatResources.getDrawable is @Nullable. icon.setBounds(0, 0, mIconSize, mIconSize); } - mSuggestionText.setCompoundDrawablePadding(mPadding); - ApiCompatibilityUtils.setCompoundDrawablesRelative( - mSuggestionText, icon, null, null, null); + text.setCompoundDrawablePadding(mPadding); + ApiCompatibilityUtils.setCompoundDrawablesRelative(text, icon, null, null, null); } } - public static void initializeView(RecyclerView view, PropertyModel model) { - view.setLayoutManager( - new LinearLayoutManager(view.getContext(), LinearLayoutManager.VERTICAL, false)); - view.setItemAnimator(null); - view.setAdapter(PasswordAccessorySheetCoordinator.createAdapter(model.get(CREDENTIALS))); - if (model.get(SCROLL_LISTENER) != null) { - view.addOnScrollListener(model.get(SCROLL_LISTENER)); - } + public static void initializeView(RecyclerView view, AccessorySheetTabModel model) { + view.setAdapter(PasswordAccessorySheetCoordinator.createAdapter(model)); } }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/compositor/CompositorViewHolder.java b/chrome/android/java/src/org/chromium/chrome/browser/compositor/CompositorViewHolder.java index 63d1a8a..14ab7b6 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/compositor/CompositorViewHolder.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/compositor/CompositorViewHolder.java
@@ -694,6 +694,15 @@ } @Override + public void onTopControlsHeightChanged(int topControlsHeight, boolean controlsResizeView) { + if (mTabVisible == null) return; + mTabVisible.setTopControlsHeight(topControlsHeight, controlsResizeView); + Point viewportSize = getViewportSize(); + setSize(mTabVisible.getWebContents(), mTabVisible.getContentView(), viewportSize.x, + viewportSize.y); + } + + @Override public void onToggleOverlayVideoMode(boolean enabled) { if (mCompositorView != null) { mCompositorView.setOverlayVideoMode(enabled);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabActivity.java index 32a69e7..a1577137 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabActivity.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabActivity.java
@@ -218,6 +218,8 @@ private int mDefaultToolbarShadowVisibility; // Whether the progress bar is enabled prior to any header customization. private boolean mDefaultIsProgressBarEnabled; + // Default height of the top control container prior to any header customization. + private int mDefaultTopControlContainerHeight; /** * Return true when the activity has been launched in a separate task. The default behavior is @@ -409,7 +411,7 @@ new ActivityDelegatePostMessageBackend()); } // Show CCT header (or top bar) if module fails (or succeeds) to load. - maybeUpdateCctHeaderVisibility(mIntentDataProvider.getUrlToLoad()); + maybeCustomizeCctHeader(mIntentDataProvider.getUrlToLoad()); } } @@ -472,7 +474,7 @@ public void setTopBarContentView(View view) { mTopBarDelegate.setTopBarContentView(view); - maybeUpdateCctHeaderVisibility(mIntentDataProvider.getUrlToLoad()); + maybeCustomizeCctHeader(mIntentDataProvider.getUrlToLoad()); } /** @@ -511,6 +513,11 @@ return mDynamicModulePostMessageHandler.postMessageFromClientApp(message); } + public void setTopBarHeight(int height) { + mTopBarDelegate.setTopBarHeight(height); + maybeCustomizeCctHeader(mIntentDataProvider.getUrlToLoad()); + } + @Override public boolean shouldAllocateChildConnection() { return !mHasCreatedTabEarly && !mHasSpeculated @@ -553,6 +560,7 @@ mDefaultToolbarVisibility = getToolbarManager().getToolbarVisibility(); mDefaultToolbarShadowVisibility = getToolbarManager().getToolbarShadowVisibility(); mDefaultIsProgressBarEnabled = getToolbarManager().isProgressBarEnabled(); + mDefaultTopControlContainerHeight = getFullscreenManager().getTopControlsHeight(); } @Override @@ -943,7 +951,7 @@ boolean isFragmentNavigation, @Nullable Integer pageTransition, int errorCode, int httpStatusCode) { if (!isInMainFrame || !hasCommitted) return; - maybeUpdateCctHeaderVisibility(url); + maybeCustomizeCctHeader(url); } /** @@ -1721,7 +1729,19 @@ return false; } - private void maybeUpdateCctHeaderVisibility(String url) { + private int getTopBarHeight() { + Integer topBarHeight = mTopBarDelegate.getTopBarHeight(); + // Custom top bar height must not be too small compared to the default top control container + // height, nor shall it be larger than the height of the web content. + if (topBarHeight != null && topBarHeight >= 0 + && topBarHeight > mDefaultTopControlContainerHeight / 2 && getWindow() != null + && topBarHeight < getWindow().getDecorView().getHeight() / 2) { + return topBarHeight; + } + return mDefaultTopControlContainerHeight; + } + + private void maybeCustomizeCctHeader(String url) { if (!ChromeFeatureList.isEnabled(ChromeFeatureList.CCT_MODULE) || (!isModuleLoaded() && !isModuleLoading())) { return; @@ -1736,6 +1756,8 @@ isModuleManagedUrl ? View.GONE : mDefaultToolbarShadowVisibility); getToolbarManager().setProgressBarEnabled( isModuleManagedUrl ? false : mDefaultIsProgressBarEnabled); + getFullscreenManager().setTopControlsHeight( + isModuleManagedUrl ? getTopBarHeight() : mDefaultTopControlContainerHeight); } }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabTopBarDelegate.java b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabTopBarDelegate.java index 23007fe4..2e8bdcac 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabTopBarDelegate.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabTopBarDelegate.java
@@ -16,10 +16,12 @@ * Delegate that manages top bar area inside of {@link CustomTabActivity}. */ class CustomTabTopBarDelegate { - private ChromeActivity mActivity; + private final ChromeActivity mActivity; private ViewGroup mTopBarView; @Nullable private View mTopBarContentView; + @Nullable + private Integer mTopBarHeight; public CustomTabTopBarDelegate(ChromeActivity activity) { mActivity = activity; @@ -45,6 +47,21 @@ } /** + * Sets the height of the top bar. + */ + public void setTopBarHeight(int height) { + mTopBarHeight = height; + } + + /** + * Gets the height of the top bar, or null if it is not specified. + */ + @Nullable + public Integer getTopBarHeight() { + return mTopBarHeight; + } + + /** * Gets the {@link ViewGroup} of the top bar. If it has not been inflated, inflate it first. */ private ViewGroup getTopBarView() {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/dynamicmodule/ActivityHostImpl.java b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/dynamicmodule/ActivityHostImpl.java index 49172ae..5f19c79a 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/dynamicmodule/ActivityHostImpl.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/dynamicmodule/ActivityHostImpl.java
@@ -58,4 +58,9 @@ public int postMessage(String message) { return mActivity.postMessage(message); } + + @Override + public void setTopBarHeight(int heightInPx) { + mActivity.setTopBarHeight(heightInPx); + } }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadBroadcastManager.java b/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadBroadcastManager.java index dda8688..f8757fa 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadBroadcastManager.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadBroadcastManager.java
@@ -47,6 +47,9 @@ import org.chromium.components.offline_items_collection.PendingState; import org.chromium.content_public.browser.BrowserStartupController; +import java.util.HashSet; +import java.util.Set; + /** * Class that spins up native when an interaction with a notification happens and passes the * relevant information on to native. @@ -192,8 +195,10 @@ @Override public boolean startServiceManagerOnly() { - return ServiceManagerStartupUtils.canStartServiceManager( - ChromeFeatureList.SERVICE_MANAGER_FOR_DOWNLOAD) + Set<String> features = new HashSet<String>(); + features.add(ChromeFeatureList.SERVICE_MANAGER_FOR_DOWNLOAD); + features.add(ChromeFeatureList.NETWORK_SERVICE); + return ServiceManagerStartupUtils.canStartServiceManager(features) && !ACTION_DOWNLOAD_OPEN.equals(intent.getAction()); } };
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/fullscreen/ChromeFullscreenManager.java b/chrome/android/java/src/org/chromium/chrome/browser/fullscreen/ChromeFullscreenManager.java index 94defc2..db23ffa 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/fullscreen/ChromeFullscreenManager.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/fullscreen/ChromeFullscreenManager.java
@@ -109,11 +109,17 @@ public void onToggleOverlayVideoMode(boolean enabled); /** - * Called when the height of the controls are changed. + * Called when the height of the bottom controls are changed. */ public void onBottomControlsHeightChanged(int bottomControlsHeight); /** + * Called when the height of the top controls are changed. + */ + public default void onTopControlsHeightChanged( + int topControlsHeight, boolean controlsResizeView) {} + + /** * Called when the viewport size of the active content is updated. */ public default void onUpdateViewportSize() {} @@ -361,6 +367,18 @@ } } + /** + * Sets the height of the top controls. + */ + public void setTopControlsHeight(int topControlsHeight) { + if (mTopControlContainerHeight == topControlsHeight) return; + mTopControlContainerHeight = topControlsHeight; + for (int i = 0; i < mListeners.size(); i++) { + mListeners.get(i).onTopControlsHeightChanged( + mTopControlContainerHeight, mControlsResizeView); + } + } + @Override public int getTopControlsHeight() { return mTopControlContainerHeight;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/init/ServiceManagerStartupUtils.java b/chrome/android/java/src/org/chromium/chrome/browser/init/ServiceManagerStartupUtils.java index f88ab5cb..2a080be 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/init/ServiceManagerStartupUtils.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/init/ServiceManagerStartupUtils.java
@@ -26,21 +26,26 @@ ChromeFeatureList.ALLOW_STARTING_SERVICE_MANAGER_ONLY; // List of features that supports starting ServiceManager on startup. - private static final String[] SERVICE_MANAGER_FEATURES = { - EARLY_START_FLAG, ChromeFeatureList.SERVICE_MANAGER_FOR_DOWNLOAD}; + private static final String[] SERVICE_MANAGER_FEATURES = {EARLY_START_FLAG, + ChromeFeatureList.NETWORK_SERVICE, ChromeFeatureList.SERVICE_MANAGER_FOR_DOWNLOAD}; // Key in the SharedPreferences for storing all features that will start ServiceManager. private static final String SERVICE_MANAGER_FEATURES_KEY = "ServiceManagerFeatures"; /** - * Check whether ServiceManager can be started for |featureName|. - * @param featureName Feature to query. - * @return Whether the feature can start service manager. + * Check whether ServiceManager can be started for a set of |featureNames|. + * @param |featureNames| Feature names to query. + * @return Whether the features can start service manager. */ - public static boolean canStartServiceManager(String featureName) { + public static boolean canStartServiceManager(Set<String> featureNames) { Set<String> features = ContextUtils.getAppSharedPreferences().getStringSet( SERVICE_MANAGER_FEATURES_KEY, null); - return features != null && features.contains(EARLY_START_FLAG) - && features.contains(featureName); + if (features == null) return false; + for (String featureName : featureNames) { + if (!features.contains(featureName)) { + return false; + } + } + return features.contains(EARLY_START_FLAG); } /**
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/QueryInOmnibox.java b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/QueryInOmnibox.java deleted file mode 100644 index 734090139..0000000 --- a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/QueryInOmnibox.java +++ /dev/null
@@ -1,34 +0,0 @@ -// Copyright 2018 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -package org.chromium.chrome.browser.omnibox; - -import org.chromium.chrome.browser.profiles.Profile; -import org.chromium.components.security_state.ConnectionSecurityLevel; - -/** - * Bridge to the native QueryInOmniboxAndroid. - */ -public class QueryInOmnibox { - /** - * Extracts query terms from the current URL if it's a SRP URL from the default search engine. - * - * @param profile The Profile associated with the tab. - * @param securityLevel The {@link ConnectionSecurityLevel} of the tab. - * @param ignoreSecurityLevel When this is set to true, Query in Omnibox ignores the security - * level when determining whether to display search terms or not. - * Use this to avoid a flicker during page load for an SRP URL - * before the SSL state updates. - * @param url The URL to extract search terms from. - * @return The extracted search terms. Returns null if the Omnibox should not display the - * search terms. - */ - public static String getDisplaySearchTerms(Profile profile, - @ConnectionSecurityLevel int securityLevel, boolean ignoreSecurityLevel, String url) { - return nativeGetDisplaySearchTerms(profile, securityLevel, ignoreSecurityLevel, url); - } - - private static native String nativeGetDisplaySearchTerms( - Profile profile, int securityLevel, boolean ignoreSecurityLevel, String url); -}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/LocationBarModel.java b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/LocationBarModel.java index 3152724..acc5425 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/LocationBarModel.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/LocationBarModel.java
@@ -15,7 +15,6 @@ import org.chromium.base.ContextUtils; import org.chromium.base.VisibleForTesting; import org.chromium.base.annotations.CalledByNative; -import org.chromium.base.library_loader.LibraryProcessType; import org.chromium.chrome.R; import org.chromium.chrome.browser.ChromeFeatureList; import org.chromium.chrome.browser.ChromeTabbedActivity; @@ -26,7 +25,6 @@ import org.chromium.chrome.browser.ntp.NewTabPage; import org.chromium.chrome.browser.offlinepages.OfflinePageUtils; import org.chromium.chrome.browser.omnibox.OmniboxUrlEmphasizer; -import org.chromium.chrome.browser.omnibox.QueryInOmnibox; import org.chromium.chrome.browser.omnibox.UrlBarData; import org.chromium.chrome.browser.previews.PreviewsAndroidBridge; import org.chromium.chrome.browser.profiles.Profile; @@ -36,7 +34,6 @@ import org.chromium.components.dom_distiller.core.DomDistillerService; import org.chromium.components.dom_distiller.core.DomDistillerUrlUtils; import org.chromium.components.security_state.ConnectionSecurityLevel; -import org.chromium.content_public.browser.BrowserStartupController; import org.chromium.content_public.browser.WebContents; import java.net.URI; @@ -447,26 +444,15 @@ /** * If the current tab state is eligible for displaying the search query terms instead of the - * URL, this extracts the query terms from the current URL. See {@link QueryInOmnibox}. + * URL, this extracts the query terms from the current URL. * * @return The search terms. Returns null if the tab is ineligible to display the search terms * instead of the URL. */ - private String getDisplaySearchTerms() { + public String getDisplaySearchTerms() { + if (mNativeLocationBarModelAndroid == 0) return null; if (mTab != null && !(mTab.getActivity() instanceof ChromeTabbedActivity)) return null; - - // We can't fetch the Profile while the browser is still starting. - if (!BrowserStartupController.get(LibraryProcessType.PROCESS_BROWSER) - .isStartupSuccessfullyCompleted()) { - return null; - } - - boolean ignoreSecurityLevel = false; - if (mNativeLocationBarModelAndroid != 0) { - ignoreSecurityLevel = !nativeIsSecurityInfoInitialized(mNativeLocationBarModelAndroid); - } - return QueryInOmnibox.getDisplaySearchTerms( - getProfile(), getSecurityLevel(), ignoreSecurityLevel, getCurrentUrl()); + return nativeGetDisplaySearchTerms(mNativeLocationBarModelAndroid); } /** @return The formatted URL suitable for editing. */ @@ -485,5 +471,5 @@ private native void nativeDestroy(long nativeLocationBarModelAndroid); private native String nativeGetFormattedFullURL(long nativeLocationBarModelAndroid); private native String nativeGetURLForDisplay(long nativeLocationBarModelAndroid); - private native boolean nativeIsSecurityInfoInitialized(long nativeLocationBarModelAndroid); + private native String nativeGetDisplaySearchTerms(long nativeLocationBarModelAndroid); }
diff --git a/chrome/android/java_sources.gni b/chrome/android/java_sources.gni index 1d238c1a..54833fa 100644 --- a/chrome/android/java_sources.gni +++ b/chrome/android/java_sources.gni
@@ -105,6 +105,9 @@ "java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/AccessorySheetMediator.java", "java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/AccessorySheetProperties.java", "java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/KeyboardAccessoryCoordinator.java", + "java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/AccessorySheetTabCoordinator.java", + "java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/AccessorySheetTabModel.java", + "java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/AccessorySheetTabViewBinder.java", "java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/AccessorySheetView.java", "java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/AccessorySheetViewBinder.java", "java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/KeyboardAccessoryData.java", @@ -121,7 +124,6 @@ "java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/ManualFillingBridge.java", "java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/PasswordAccessorySheetCoordinator.java", "java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/PasswordAccessorySheetMediator.java", - "java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/PasswordAccessorySheetProperties.java", "java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/PasswordAccessorySheetViewBinder.java", "java/src/org/chromium/chrome/browser/autofill_assistant/AnimatedProgressBar.java", "java/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantFacade.java", @@ -1117,7 +1119,6 @@ "java/src/org/chromium/chrome/browser/omnibox/OmniboxPrerender.java", "java/src/org/chromium/chrome/browser/omnibox/OmniboxUrlEmphasizer.java", "java/src/org/chromium/chrome/browser/omnibox/OmniboxViewUtil.java", - "java/src/org/chromium/chrome/browser/omnibox/QueryInOmnibox.java", "java/src/org/chromium/chrome/browser/omnibox/SpannableAutocompleteEditTextModel.java", "java/src/org/chromium/chrome/browser/omnibox/UrlBar.java", "java/src/org/chromium/chrome/browser/omnibox/UrlBarCoordinator.java",
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/autofill/keyboard_accessory/AccessorySheetViewTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/autofill/keyboard_accessory/AccessorySheetViewTest.java index 2ac5648..6f5cc8b 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/autofill/keyboard_accessory/AccessorySheetViewTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/autofill/keyboard_accessory/AccessorySheetViewTest.java
@@ -12,11 +12,10 @@ import static android.support.test.espresso.matcher.ViewMatchers.withId; import static android.support.test.espresso.matcher.ViewMatchers.withText; -import static junit.framework.Assert.assertEquals; -import static junit.framework.Assert.assertNotNull; -import static junit.framework.Assert.assertNull; - +import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import static org.chromium.chrome.browser.autofill.keyboard_accessory.AccessorySheetProperties.ACTIVE_TAB_INDEX;
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/autofill/keyboard_accessory/PasswordAccessoryIntegrationTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/autofill/keyboard_accessory/PasswordAccessoryIntegrationTest.java index 8395ff7..7730bc7 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/autofill/keyboard_accessory/PasswordAccessoryIntegrationTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/autofill/keyboard_accessory/PasswordAccessoryIntegrationTest.java
@@ -7,10 +7,8 @@ import static android.support.test.espresso.Espresso.onView; import static android.support.test.espresso.action.ViewActions.click; import static android.support.test.espresso.assertion.ViewAssertions.matches; -import static android.support.test.espresso.contrib.RecyclerViewActions.scrollToPosition; import static android.support.test.espresso.matcher.ViewMatchers.assertThat; import static android.support.test.espresso.matcher.ViewMatchers.isDisplayed; -import static android.support.test.espresso.matcher.ViewMatchers.withChild; import static android.support.test.espresso.matcher.ViewMatchers.withId; import static android.support.test.espresso.matcher.ViewMatchers.withText; @@ -171,8 +169,6 @@ mHelper.sendCredentials(accessorySheetData); // Scroll down and click the suggestion. - whenDisplayed(withChild(withText("Suggest strong password..."))) - .perform(scrollToPosition(2)); whenDisplayed(withText("Suggest strong password...")).perform(click()); // The callback should have triggered and set the reference to the selected Item.
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/autofill/keyboard_accessory/PasswordAccessorySheetViewTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/autofill/keyboard_accessory/PasswordAccessorySheetViewTest.java index cc7f8327..b251616 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/autofill/keyboard_accessory/PasswordAccessorySheetViewTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/autofill/keyboard_accessory/PasswordAccessorySheetViewTest.java
@@ -6,16 +6,17 @@ import static org.hamcrest.Matchers.instanceOf; import static org.hamcrest.Matchers.is; +import static org.hamcrest.Matchers.not; +import static org.hamcrest.Matchers.nullValue; import static org.junit.Assert.assertThat; -import static org.chromium.chrome.browser.autofill.keyboard_accessory.PasswordAccessorySheetProperties.CREDENTIALS; -import static org.chromium.chrome.browser.autofill.keyboard_accessory.PasswordAccessorySheetProperties.SCROLL_LISTENER; - import android.support.annotation.LayoutRes; import android.support.test.filters.MediumTest; import android.support.v7.widget.RecyclerView; import android.text.method.PasswordTransformationMethod; +import android.view.View; import android.view.ViewGroup; +import android.widget.LinearLayout; import android.widget.TextView; import org.junit.After; @@ -29,9 +30,8 @@ import org.chromium.chrome.R; import org.chromium.chrome.browser.ChromeSwitches; import org.chromium.chrome.browser.ChromeTabbedActivity; -import org.chromium.chrome.browser.autofill.keyboard_accessory.KeyboardAccessoryData.Item; -import org.chromium.chrome.browser.modelutil.ListModel; -import org.chromium.chrome.browser.modelutil.PropertyModel; +import org.chromium.chrome.browser.autofill.keyboard_accessory.AccessorySheetTabModel.AccessorySheetDataPiece; +import org.chromium.chrome.browser.autofill.keyboard_accessory.KeyboardAccessoryData.UserInfo; import org.chromium.chrome.test.ChromeActivityTestRule; import org.chromium.chrome.test.ChromeJUnit4ClassRunner; import org.chromium.content_public.browser.test.util.Criteria; @@ -47,10 +47,7 @@ @RunWith(ChromeJUnit4ClassRunner.class) @CommandLineFlags.Add({ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE}) public class PasswordAccessorySheetViewTest { - private final PropertyModel mModel = new PropertyModel.Builder(CREDENTIALS, SCROLL_LISTENER) - .with(CREDENTIALS, new ListModel<>()) - .with(SCROLL_LISTENER, null) - .build(); + private final AccessorySheetTabModel mModel = new AccessorySheetTabModel(); private AtomicReference<RecyclerView> mView = new AtomicReference<>(); @Rule @@ -90,6 +87,7 @@ mView.set((RecyclerView) view); // Reuse coordinator code to create and wire the adapter. No mediator // involved. + AccessorySheetTabViewBinder.initializeView(mView.get(), null); PasswordAccessorySheetViewBinder.initializeView(mView.get(), mModel); } @@ -109,58 +107,63 @@ public void testAddingCaptionsToTheModelRendersThem() { assertThat(mView.get().getChildCount(), is(0)); - ThreadUtils.runOnUiThreadBlocking( - () -> mModel.get(CREDENTIALS).add(Item.createLabel("Passwords", null))); + ThreadUtils.runOnUiThreadBlocking(() -> { + mModel.add( + new AccessorySheetDataPiece("Passwords", AccessorySheetDataPiece.Type.TITLE)); + }); CriteriaHelper.pollUiThread(Criteria.equals(1, () -> mView.get().getChildCount())); - assertThat(mView.get().getChildAt(0), instanceOf(TextView.class)); - assertThat(((TextView) mView.get().getChildAt(0)).getText(), is("Passwords")); + View title = mView.get().findViewById(R.id.tab_title); + assertThat(title, is(not(nullValue()))); + assertThat(title, instanceOf(TextView.class)); + assertThat(((TextView) title).getText(), is("Passwords")); } @Test @MediumTest - public void testAddingSuggestionsToTheModelRendersClickableActions() throws ExecutionException { + public void testAddingUserInfoToTheModelRendersClickableActions() throws ExecutionException { final AtomicReference<Boolean> clicked = new AtomicReference<>(false); assertThat(mView.get().getChildCount(), is(0)); - ThreadUtils.runOnUiThreadBlocking( - () - -> mModel.get(CREDENTIALS) - .add(Item.createSuggestion("Name Suggestion", null, false, - item -> clicked.set(true), null))); + UserInfo testInfo = new UserInfo(null); + testInfo.addField(new UserInfo.Field( + "Name Suggestion", "Name Suggestion", false, item -> clicked.set(true))); + testInfo.addField(new UserInfo.Field( + "Password Suggestion", "Password Suggestion", true, item -> clicked.set(true))); + ThreadUtils.runOnUiThreadBlocking(() -> { + mModel.add(new AccessorySheetDataPiece( + testInfo, AccessorySheetDataPiece.Type.PASSWORD_INFO)); + }); CriteriaHelper.pollUiThread(Criteria.equals(1, () -> mView.get().getChildCount())); - assertThat(getFirstSuggestion().getText(), is("Name Suggestion")); - - ThreadUtils.runOnUiThreadBlocking(getFirstSuggestion()::performClick); - assertThat(clicked.get(), is(true)); - } - - @Test - @MediumTest - public void testAddingPasswordsToTheModelRendersThemHidden() throws ExecutionException { - final AtomicReference<Boolean> clicked = new AtomicReference<>(false); - assertThat(mView.get().getChildCount(), is(0)); - - ThreadUtils.runOnUiThreadBlocking( - () - -> mModel.get(CREDENTIALS) - .add(Item.createSuggestion("Password Suggestion", null, true, - item -> clicked.set(true), null))); - - CriteriaHelper.pollUiThread(Criteria.equals(1, () -> mView.get().getChildCount())); - - assertThat(getFirstSuggestion().getText(), is("Password Suggestion")); - assertThat(getFirstSuggestion().getTransformationMethod(), + assertThat(getNameSuggestion().getText(), is("Name Suggestion")); + assertThat(getPasswordSuggestion().getText(), is("Password Suggestion")); + assertThat(getPasswordSuggestion().getTransformationMethod(), instanceOf(PasswordTransformationMethod.class)); - ThreadUtils.runOnUiThreadBlocking(getFirstSuggestion()::performClick); + ThreadUtils.runOnUiThreadBlocking(getNameSuggestion()::performClick); + assertThat(clicked.get(), is(true)); + clicked.set(false); + ThreadUtils.runOnUiThreadBlocking(getPasswordSuggestion()::performClick); assertThat(clicked.get(), is(true)); } - private TextView getFirstSuggestion() { - assertThat(mView.get().getChildAt(0), instanceOf(TextView.class)); - return (TextView) mView.get().getChildAt(0); + private TextView getNameSuggestion() { + assertThat(mView.get().getChildAt(0), instanceOf(LinearLayout.class)); + LinearLayout layout = (LinearLayout) mView.get().getChildAt(0); + View view = layout.findViewById(R.id.suggestion_text); + assertThat(view, is(not(nullValue()))); + assertThat(view, instanceOf(TextView.class)); + return (TextView) view; + } + + private TextView getPasswordSuggestion() { + assertThat(mView.get().getChildAt(0), instanceOf(LinearLayout.class)); + LinearLayout layout = (LinearLayout) mView.get().getChildAt(0); + View view = layout.findViewById(R.id.password_text); + assertThat(view, is(not(nullValue()))); + assertThat(view, instanceOf(TextView.class)); + return (TextView) view; } } \ No newline at end of file
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/CustomTabActivityTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/CustomTabActivityTest.java index 5932cc64..e56ab98 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/CustomTabActivityTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/CustomTabActivityTest.java
@@ -1523,6 +1523,75 @@ @Test @SmallTest + @DisableFeatures(ChromeFeatureList.CCT_MODULE_CUSTOM_HEADER) + public void testSetTopBarHeight_featureDisabled_heightNotChanged() throws Exception { + setupHttpsTestServerAndPages(); + String relativeUrl = "/chrome/test/data/android/about.html"; + String moduleManagedUrl = mTestServer.getURL(relativeUrl); + Intent intent = CustomTabsDynamicModuleTestUtils.makeDynamicModuleIntent( + moduleManagedUrl, "^(" + relativeUrl + ")$"); + intent.putExtra( + CustomTabIntentDataProvider.EXTRA_HIDE_CCT_HEADER_ON_MODULE_MANAGED_URLS, true); + mCustomTabActivityTestRule.startCustomTabActivityWithIntent(intent); + + ThreadUtils.runOnUiThread(() -> { + CustomTabActivity cctActivity = mCustomTabActivityTestRule.getActivity(); + int defaultHeight = cctActivity.getFullscreenManager().getTopControlsHeight(); + int newHeight = defaultHeight + 10; + cctActivity.setTopBarHeight(newHeight); + Assert.assertEquals( + defaultHeight, cctActivity.getFullscreenManager().getTopControlsHeight()); + }); + } + + @Test + @SmallTest + @EnableFeatures({ChromeFeatureList.CCT_MODULE, ChromeFeatureList.CCT_MODULE_CUSTOM_HEADER}) + public void testSetTopBarHeight_cctHeaderNotHidden_heightNotChanged() throws Exception { + setupHttpsTestServerAndPages(); + String relativeUrl = "/chrome/test/data/android/about.html"; + String moduleManagedUrl = mTestServer.getURL(relativeUrl); + Intent intent = CustomTabsDynamicModuleTestUtils.makeDynamicModuleIntent( + moduleManagedUrl, "^(" + relativeUrl + ")$"); + intent.putExtra( + CustomTabIntentDataProvider.EXTRA_HIDE_CCT_HEADER_ON_MODULE_MANAGED_URLS, false); + mCustomTabActivityTestRule.startCustomTabActivityWithIntent(intent); + + ThreadUtils.runOnUiThread(() -> { + CustomTabActivity cctActivity = mCustomTabActivityTestRule.getActivity(); + int defaultHeight = cctActivity.getFullscreenManager().getTopControlsHeight(); + int newHeight = defaultHeight + 10; + cctActivity.setTopBarHeight(newHeight); + Assert.assertEquals( + defaultHeight, cctActivity.getFullscreenManager().getTopControlsHeight()); + }); + } + + @Test + @SmallTest + @EnableFeatures({ChromeFeatureList.CCT_MODULE, ChromeFeatureList.CCT_MODULE_CUSTOM_HEADER}) + public void testSetTopBarHeight_withModuleAndExtras_heightUpdated() throws Exception { + setupHttpsTestServerAndPages(); + String relativeUrl = "/chrome/test/data/android/about.html"; + String moduleManagedUrl = mTestServer.getURL(relativeUrl); + Intent intent = CustomTabsDynamicModuleTestUtils.makeDynamicModuleIntent( + moduleManagedUrl, "^(" + relativeUrl + ")$"); + intent.putExtra( + CustomTabIntentDataProvider.EXTRA_HIDE_CCT_HEADER_ON_MODULE_MANAGED_URLS, true); + mCustomTabActivityTestRule.startCustomTabActivityWithIntent(intent); + + ThreadUtils.runOnUiThread(() -> { + CustomTabActivity cctActivity = mCustomTabActivityTestRule.getActivity(); + int defaultHeight = cctActivity.getFullscreenManager().getTopControlsHeight(); + int newHeight = defaultHeight + 10; + cctActivity.setTopBarHeight(newHeight); + Assert.assertEquals( + newHeight, cctActivity.getFullscreenManager().getTopControlsHeight()); + }); + } + + @Test + @SmallTest @Feature({"UiCatalogue"}) public void testRemoteViews() throws Exception { Intent intent = createMinimalCustomTabIntent();
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/omnibox/LocationBarLayoutTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/omnibox/LocationBarLayoutTest.java index f3aedfb1..3456a6b 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/omnibox/LocationBarLayoutTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/omnibox/LocationBarLayoutTest.java
@@ -23,7 +23,6 @@ import org.chromium.chrome.browser.ChromeActivity; import org.chromium.chrome.browser.ChromeFeatureList; import org.chromium.chrome.browser.ChromeSwitches; -import org.chromium.chrome.browser.search_engines.TemplateUrlServiceTestUtils; import org.chromium.chrome.browser.toolbar.LocationBarModel; import org.chromium.chrome.test.ChromeActivityTestRule; import org.chromium.chrome.test.ChromeJUnit4ClassRunner; @@ -34,7 +33,6 @@ import java.util.concurrent.Callable; import java.util.concurrent.ExecutionException; -import java.util.concurrent.TimeoutException; /** * Unit tests for {@link LocationBarLayout}. @@ -64,6 +62,7 @@ private String mCurrentUrl; private String mEditingText; private String mDisplayText; + private String mDisplaySearchTerms; private Integer mSecurityLevel; public TestLocationBarModel() { @@ -75,6 +74,10 @@ mCurrentUrl = url; } + void setDisplaySearchTerms(String terms) { + mDisplaySearchTerms = terms; + } + void setSecurityLevel(@ConnectionSecurityLevel int securityLevel) { mSecurityLevel = securityLevel; } @@ -86,6 +89,12 @@ } @Override + public String getDisplaySearchTerms() { + if (mDisplaySearchTerms == null) return super.getDisplaySearchTerms(); + return mDisplaySearchTerms; + } + + @Override @ConnectionSecurityLevel public int getSecurityLevel() { if (mSecurityLevel == null) return super.getSecurityLevel(); @@ -211,121 +220,19 @@ @SmallTest @EnableFeatures(ChromeFeatureList.QUERY_IN_OMNIBOX) @Feature({"QueryInOmnibox"}) - public void testIsOnlyShowingSearchTermsIfSrpIsGoogle() { + public void testIsViewShowingModelSearchTerms() { final UrlBar urlBar = getUrlBar(); final LocationBarLayout locationBar = getLocationBar(); mTestLocationBarModel.setCurrentUrl(GOOGLE_SRP_URL); mTestLocationBarModel.setSecurityLevel(ConnectionSecurityLevel.SECURE); + mTestLocationBarModel.setDisplaySearchTerms(null); setUrlToPageUrl(locationBar); - - Assert.assertEquals(SEARCH_TERMS, getUrlText(urlBar)); - } - - @Test - @SmallTest - @EnableFeatures(ChromeFeatureList.QUERY_IN_OMNIBOX) - @Feature({"QueryInOmnibox"}) - public void testIsOnlyShowingSearchTermsIfSrpIsBing() - throws ExecutionException, InterruptedException, TimeoutException { - final UrlBar urlBar = getUrlBar(); - final LocationBarLayout locationBar = getLocationBar(); - - TemplateUrlServiceTestUtils.setSearchEngine("bing.com"); - mTestLocationBarModel.setCurrentUrl(BING_SRP_URL); - mTestLocationBarModel.setSecurityLevel(ConnectionSecurityLevel.SECURE); - setUrlToPageUrl(locationBar); - - Assert.assertEquals(SEARCH_TERMS, getUrlText(urlBar)); - } - - @Test - @SmallTest - @EnableFeatures(ChromeFeatureList.QUERY_IN_OMNIBOX) - @Feature({"QueryInOmnibox"}) - public void testIsNotShowingSearchTermsIfSrpIsBingAndSrpUrlIsGoogle() - throws ExecutionException, InterruptedException, TimeoutException { - final UrlBar urlBar = getUrlBar(); - final LocationBarLayout locationBar = getLocationBar(); - - TemplateUrlServiceTestUtils.setSearchEngine("bing.com"); - mTestLocationBarModel.setCurrentUrl(GOOGLE_SRP_URL); - mTestLocationBarModel.setSecurityLevel(ConnectionSecurityLevel.SECURE); - setUrlToPageUrl(locationBar); - Assert.assertNotEquals(SEARCH_TERMS, getUrlText(urlBar)); - } - @Test - @SmallTest - @EnableFeatures(ChromeFeatureList.QUERY_IN_OMNIBOX) - @Feature({"QueryInOmnibox"}) - public void testNotShowingSearchIconOnMixedContent() { - final UrlBar urlBar = getUrlBar(); - final LocationBarLayout locationBar = getLocationBar(); - - mTestLocationBarModel.setCurrentUrl(GOOGLE_SRP_URL); - mTestLocationBarModel.setSecurityLevel(ConnectionSecurityLevel.NONE); + mTestLocationBarModel.setDisplaySearchTerms(SEARCH_TERMS); setUrlToPageUrl(locationBar); - - ImageButton securityButton = getSecurityButton(); - Assert.assertNotEquals(SEARCH_TERMS, urlBar.getText().toString()); - ThreadUtils.runOnUiThreadBlocking(() -> { - Assert.assertNotEquals(mTestLocationBarModel.getSecurityIconResource( - mActivityTestRule.getActivity().isTablet()), - SEARCH_ICON_RESOURCE); - }); - } - - @Test - @SmallTest - @EnableFeatures(ChromeFeatureList.QUERY_IN_OMNIBOX) - @Feature({"QueryInOmnibox"}) - public void testIsShowingSearchIconSecureContent() { - final LocationBarLayout locationBar = getLocationBar(); - - mTestLocationBarModel.setCurrentUrl(GOOGLE_SRP_URL); - mTestLocationBarModel.setSecurityLevel(ConnectionSecurityLevel.SECURE); - setUrlToPageUrl(locationBar); - - ImageButton securityButton = getSecurityButton(); - Assert.assertEquals(securityButton.getVisibility(), View.VISIBLE); - ThreadUtils.runOnUiThreadBlocking(() -> { - Assert.assertEquals(mTestLocationBarModel.getSecurityIconResource( - mActivityTestRule.getActivity().isTablet()), - SEARCH_ICON_RESOURCE); - }); - } - - @Test - @SmallTest - @EnableFeatures(ChromeFeatureList.QUERY_IN_OMNIBOX) - @Feature({"QueryInOmnibox"}) - public void testNotShowingSearchTermsIfLooksLikeUrl() throws ExecutionException { - final UrlBar urlBar = getUrlBar(); - final LocationBarLayout locationBar = getLocationBar(); - - mTestLocationBarModel.setCurrentUrl(GOOGLE_SRP_URL_LIKE_URL); - mTestLocationBarModel.setSecurityLevel(ConnectionSecurityLevel.SECURE); - setUrlToPageUrl(locationBar); - - Assert.assertNotEquals(SEARCH_TERMS_URL, getUrlText(urlBar)); - } - - @Test - @SmallTest - @DisableFeatures(ChromeFeatureList.QUERY_IN_OMNIBOX) - @Feature({"QueryInOmnibox"}) - public void testNotShowingSearchTermsIfSrpIsGoogleAndFlagIsDisabled() - throws ExecutionException { - final UrlBar urlBar = getUrlBar(); - final LocationBarLayout locationBar = getLocationBar(); - - mTestLocationBarModel.setCurrentUrl(GOOGLE_SRP_URL); - mTestLocationBarModel.setSecurityLevel(ConnectionSecurityLevel.SECURE); - setUrlToPageUrl(locationBar); - - Assert.assertNotEquals(SEARCH_TERMS, getUrlText(urlBar)); + Assert.assertEquals(SEARCH_TERMS, getUrlText(urlBar)); } @Test
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/autofill/keyboard_accessory/ManualFillingControllerTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/autofill/keyboard_accessory/ManualFillingControllerTest.java index 454593a..d28892a 100644 --- a/chrome/android/junit/src/org/chromium/chrome/browser/autofill/keyboard_accessory/ManualFillingControllerTest.java +++ b/chrome/android/junit/src/org/chromium/chrome/browser/autofill/keyboard_accessory/ManualFillingControllerTest.java
@@ -18,10 +18,10 @@ import static org.mockito.Mockito.when; import static org.chromium.chrome.browser.autofill.keyboard_accessory.AccessoryAction.GENERATE_PASSWORD_AUTOMATIC; +import static org.chromium.chrome.browser.autofill.keyboard_accessory.AccessorySheetTabModel.AccessorySheetDataPiece.Type.PASSWORD_INFO; +import static org.chromium.chrome.browser.autofill.keyboard_accessory.AccessorySheetTabModel.AccessorySheetDataPiece.getType; import static org.chromium.chrome.browser.autofill.keyboard_accessory.KeyboardAccessoryProperties.ACTIVE_TAB; import static org.chromium.chrome.browser.autofill.keyboard_accessory.KeyboardAccessoryProperties.TABS; -import static org.chromium.chrome.browser.autofill.keyboard_accessory.PasswordAccessorySheetProperties.AccessorySheetDataPiece.Type.PASSWORD_INFO; -import static org.chromium.chrome.browser.autofill.keyboard_accessory.PasswordAccessorySheetProperties.AccessorySheetDataPiece.getType; import static org.chromium.chrome.browser.tab.Tab.INVALID_TAB_ID; import static org.chromium.chrome.browser.tabmodel.TabModel.TabLaunchType.FROM_BROWSER_ACTIONS; import static org.chromium.chrome.browser.tabmodel.TabModel.TabSelectionType.FROM_CLOSE; @@ -455,7 +455,7 @@ if (oldState.mPasswordAccessorySheet == null) return; // Having no password sheet is fine - it would be completely destroyed then. - assertThat(oldState.mPasswordAccessorySheet.getItemsForTesting().size(), is(0)); + assertThat(oldState.mPasswordAccessorySheet.getSheetDataPiecesForTesting().size(), is(0)); } @Test
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/autofill/keyboard_accessory/PasswordAccessorySheetControllerTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/autofill/keyboard_accessory/PasswordAccessorySheetControllerTest.java index fff2020..828af9b 100644 --- a/chrome/android/junit/src/org/chromium/chrome/browser/autofill/keyboard_accessory/PasswordAccessorySheetControllerTest.java +++ b/chrome/android/junit/src/org/chromium/chrome/browser/autofill/keyboard_accessory/PasswordAccessorySheetControllerTest.java
@@ -13,10 +13,10 @@ import static org.mockito.Mockito.verifyNoMoreInteractions; import static org.mockito.Mockito.when; -import static org.chromium.chrome.browser.autofill.keyboard_accessory.PasswordAccessorySheetProperties.AccessorySheetDataPiece.Type.FOOTER_COMMAND; -import static org.chromium.chrome.browser.autofill.keyboard_accessory.PasswordAccessorySheetProperties.AccessorySheetDataPiece.Type.PASSWORD_INFO; -import static org.chromium.chrome.browser.autofill.keyboard_accessory.PasswordAccessorySheetProperties.AccessorySheetDataPiece.Type.TITLE; -import static org.chromium.chrome.browser.autofill.keyboard_accessory.PasswordAccessorySheetProperties.AccessorySheetDataPiece.getType; +import static org.chromium.chrome.browser.autofill.keyboard_accessory.AccessorySheetTabModel.AccessorySheetDataPiece.Type.FOOTER_COMMAND; +import static org.chromium.chrome.browser.autofill.keyboard_accessory.AccessorySheetTabModel.AccessorySheetDataPiece.Type.PASSWORD_INFO; +import static org.chromium.chrome.browser.autofill.keyboard_accessory.AccessorySheetTabModel.AccessorySheetDataPiece.Type.TITLE; +import static org.chromium.chrome.browser.autofill.keyboard_accessory.AccessorySheetTabModel.AccessorySheetDataPiece.getType; import android.support.v7.widget.RecyclerView; @@ -34,11 +34,8 @@ import org.chromium.base.test.BaseRobolectricTestRunner; import org.chromium.chrome.browser.autofill.keyboard_accessory.KeyboardAccessoryData.AccessorySheetData; import org.chromium.chrome.browser.autofill.keyboard_accessory.KeyboardAccessoryData.FooterCommand; -import org.chromium.chrome.browser.autofill.keyboard_accessory.KeyboardAccessoryData.Item; import org.chromium.chrome.browser.autofill.keyboard_accessory.KeyboardAccessoryData.PropertyProvider; import org.chromium.chrome.browser.autofill.keyboard_accessory.KeyboardAccessoryData.UserInfo; -import org.chromium.chrome.browser.autofill.keyboard_accessory.PasswordAccessorySheetProperties.AccessorySheetDataPiece; -import org.chromium.chrome.browser.modelutil.ListModel; import org.chromium.chrome.browser.modelutil.ListObservable; /** @@ -54,8 +51,7 @@ private ListObservable.ListObserver<Void> mMockItemListObserver; private PasswordAccessorySheetCoordinator mCoordinator; - private ListModel<Item> mItemList; - private ListModel<AccessorySheetDataPiece> mSheetDataPieces; + private AccessorySheetTabModel mSheetDataPieces; @Before public void setUp() { @@ -63,7 +59,6 @@ MockitoAnnotations.initMocks(this); mCoordinator = new PasswordAccessorySheetCoordinator(RuntimeEnvironment.application, null); assertNotNull(mCoordinator); - mItemList = mCoordinator.getItemsForTesting(); mSheetDataPieces = mCoordinator.getSheetDataPiecesForTesting(); } @@ -86,35 +81,6 @@ } @Test - public void testModelNotifiesAboutActionsChangedByProvider() { - final PropertyProvider<AccessorySheetData> testProvider = new PropertyProvider<>(); - - mItemList.addObserver(mMockItemListObserver); - mCoordinator.registerDataProvider(testProvider); - - // If the coordinator receives an initial items, the model should report an insertion. - testProvider.notifyObservers(new AccessorySheetData("Passwords")); - verify(mMockItemListObserver).onItemRangeInserted(mItemList, 0, 2); - assertThat(mItemList.size(), is(2)); - assertThat(mItemList.get(1).getCaption(), is(equalTo("Passwords"))); - - // If the coordinator receives a new set of items, the model should report a change. - testProvider.notifyObservers(new AccessorySheetData("Other Passwords")); - verify(mMockItemListObserver).onItemRangeChanged(mItemList, 0, 2, null); - assertThat(mItemList.size(), is(2)); - assertThat(mItemList.get(1).getCaption(), is(equalTo("Other Passwords"))); - - // If the coordinator receives an empty set of items, the model should report a deletion. - testProvider.notifyObservers(null); - verify(mMockItemListObserver).onItemRangeRemoved(mItemList, 0, 2); - assertThat(mItemList.size(), is(0)); - - // There should be no notification if no item are reported repeatedly. - testProvider.notifyObservers(null); - verifyNoMoreInteractions(mMockItemListObserver); - } - - @Test public void testModelNotifiesAboutTabDataChangedByProvider() { final PropertyProvider<AccessorySheetData> testProvider = new PropertyProvider<>(); @@ -142,7 +108,7 @@ } @Test - public void testWrapsTabDataToElements() { + public void testSplitsTabDataToList() { final PropertyProvider<AccessorySheetData> testProvider = new PropertyProvider<>(); final AccessorySheetData testData = new AccessorySheetData("Passwords for this site"); testData.getUserInfoList().add(new UserInfo(null)); @@ -175,6 +141,8 @@ @Test public void testRecordsSuggestionsImpressionsWhenShown() { + final PropertyProvider<AccessorySheetData> testProvider = new PropertyProvider<>(); + mCoordinator.registerDataProvider(testProvider); assertThat( RecordHistogram.getHistogramTotalCountForTesting( KeyboardAccessoryMetricsRecorder.UMA_KEYBOARD_ACCESSORY_SHEET_SUGGESTIONS), @@ -183,24 +151,29 @@ assertThat(getSuggestionsImpressions(AccessoryTabType.ALL, 0), is(0)); // If the tab is shown without interactive item, log "0" samples. - mItemList.set(new Item[] {Item.createLabel("No passwords!", ""), Item.createDivider(), - Item.createOption("Manage all passwords", "", null), - Item.createOption("Generate password", "", null)}); + AccessorySheetData accessorySheetData = new AccessorySheetData("No passwords!"); + accessorySheetData.getFooterCommands().add(new FooterCommand("Manage all passwords", null)); + accessorySheetData.getFooterCommands().add(new FooterCommand("Generate password", null)); + testProvider.notifyObservers(accessorySheetData); mCoordinator.onTabShown(); assertThat(getSuggestionsImpressions(AccessoryTabType.PASSWORDS, 0), is(1)); assertThat(getSuggestionsImpressions(AccessoryTabType.ALL, 0), is(1)); // If the tab is shown with X interactive item, record "X" samples. - mItemList.set(new Item[] {Item.createLabel("Your passwords", ""), - Item.createSuggestion("Interactive 1", "", false, (v) -> {}, null), - Item.createSuggestion("Non-interactive 1", "", true, null, null), - Item.createSuggestion("Interactive 2", "", false, (v) -> {}, null), - Item.createSuggestion("Non-interactive 2", "", true, null, null), - Item.createSuggestion("Interactive 3", "", false, (v) -> {}, null), - Item.createSuggestion("Non-interactive 3", "", true, null, null), - Item.createDivider(), Item.createOption("Manage all passwords", "", null), - Item.createOption("Generate password", "", null)}); + UserInfo userInfo1 = new UserInfo(null); + userInfo1.addField(new UserInfo.Field("Interactive 1", "", false, (v) -> {})); + userInfo1.addField(new UserInfo.Field("Non-Interactive 1", "", true, null)); + accessorySheetData.getUserInfoList().add(userInfo1); + UserInfo userInfo2 = new UserInfo(null); + userInfo2.addField(new UserInfo.Field("Interactive 2", "", false, (v) -> {})); + userInfo2.addField(new UserInfo.Field("Non-Interactive 2", "", true, null)); + accessorySheetData.getUserInfoList().add(userInfo2); + UserInfo userInfo3 = new UserInfo(null); + userInfo3.addField(new UserInfo.Field("Interactive 3", "", false, (v) -> {})); + userInfo3.addField(new UserInfo.Field("Non-Interactive 3", "", true, null)); + accessorySheetData.getUserInfoList().add(userInfo3); + testProvider.notifyObservers(accessorySheetData); mCoordinator.onTabShown(); assertThat(getSuggestionsImpressions(AccessoryTabType.PASSWORDS, 3), is(1));
diff --git a/chrome/app/generated_resources.grd b/chrome/app/generated_resources.grd index 46296761..3d51027 100644 --- a/chrome/app/generated_resources.grd +++ b/chrome/app/generated_resources.grd
@@ -6276,6 +6276,13 @@ Your account <ph name="EMAIL">$1<ex>john.doe@example.com</ex></ph> is no longer allowed as the primary account. Because this account is managed by <ph name="DOMAIN">$2<ex>example.com</ex></ph>, your bookmarks, history, passwords, and other settings will be cleared from this device. </message> + <!-- Managed UI on pages like chrome://settings and chrome://downloads --> + <if expr="not is_android"> + <message name="IDS_MANAGED_BY_ORG_WITH_HYPERLINK"> + Your <ph name="BEGIN_LINK"><a target="_blank" href="$1"></ph>browser is managed<ph name="END_LINK"></a></ph> by your organization + </message> + </if> + <!-- Cookies Window --> <message name="IDS_COOKIES_REMOVE_LABEL" desc="The label of the 'Remove' button in the Cookies Window"> Remove
diff --git a/chrome/app/generated_resources_grd/IDS_MANAGED_BY_ORG_WITH_HYPERLINK.png.sha1 b/chrome/app/generated_resources_grd/IDS_MANAGED_BY_ORG_WITH_HYPERLINK.png.sha1 new file mode 100644 index 0000000..8ec22ab --- /dev/null +++ b/chrome/app/generated_resources_grd/IDS_MANAGED_BY_ORG_WITH_HYPERLINK.png.sha1
@@ -0,0 +1 @@ +e833678c2cc9804565724acfd9b6f78e0d211314 \ No newline at end of file
diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn index 31886e5f..f4d9dd5 100644 --- a/chrome/browser/BUILD.gn +++ b/chrome/browser/BUILD.gn
@@ -2286,7 +2286,6 @@ "android/omnibox/autocomplete_controller_android.h", "android/omnibox/omnibox_prerender.cc", "android/omnibox/omnibox_prerender.h", - "android/omnibox/query_in_omnibox_android.cc", "android/oom_intervention/near_oom_monitor.cc", "android/oom_intervention/near_oom_monitor.h", "android/oom_intervention/oom_intervention_config.cc", @@ -4809,7 +4808,6 @@ "../android/java/src/org/chromium/chrome/browser/omnibox/OmniboxPrerender.java", "../android/java/src/org/chromium/chrome/browser/omnibox/OmniboxUrlEmphasizer.java", "../android/java/src/org/chromium/chrome/browser/omnibox/OmniboxViewUtil.java", - "../android/java/src/org/chromium/chrome/browser/omnibox/QueryInOmnibox.java", "../android/java/src/org/chromium/chrome/browser/omnibox/geo/GeolocationHeader.java", "../android/java/src/org/chromium/chrome/browser/omnibox/suggestions/AnswersImageFetcher.java", "../android/java/src/org/chromium/chrome/browser/omnibox/suggestions/AutocompleteController.java",
diff --git a/chrome/browser/android/chrome_feature_list.cc b/chrome/browser/android/chrome_feature_list.cc index 24bac436..172ee25 100644 --- a/chrome/browser/android/chrome_feature_list.cc +++ b/chrome/browser/android/chrome_feature_list.cc
@@ -33,6 +33,7 @@ #include "jni/ChromeFeatureList_jni.h" #include "media/base/media_switches.h" #include "services/device/public/cpp/device_features.h" +#include "services/network/public/cpp/features.h" #include "ui/base/ui_base_features.h" using base::android::ConvertJavaStringToUTF8; @@ -148,6 +149,7 @@ &kTrustedWebActivityPostMessage, &kVideoPersistence, &kVrBrowsingFeedback, + &network::features::kNetworkService, &payments::features::kReturnGooglePayInBasicCard, &payments::features::kWebPaymentsMethodSectionOrderV2, &payments::features::kWebPaymentsModifiers,
diff --git a/chrome/browser/android/omnibox/query_in_omnibox_android.cc b/chrome/browser/android/omnibox/query_in_omnibox_android.cc deleted file mode 100644 index db2da50..0000000 --- a/chrome/browser/android/omnibox/query_in_omnibox_android.cc +++ /dev/null
@@ -1,33 +0,0 @@ -// Copyright 2018 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/android/jni_string.h" -#include "chrome/browser/profiles/profile_android.h" -#include "chrome/browser/ui/omnibox/query_in_omnibox_factory.h" -#include "components/omnibox/browser/query_in_omnibox.h" -#include "jni/QueryInOmnibox_jni.h" - -using base::android::JavaParamRef; - -static base::android::ScopedJavaLocalRef<jstring> -JNI_QueryInOmnibox_GetDisplaySearchTerms(JNIEnv* env, - const JavaParamRef<jobject>& j_profile, - jint j_security_level, - jboolean j_ignore_security_level, - const JavaParamRef<jstring>& j_url) { - Profile* profile = ProfileAndroid::FromProfileAndroid(j_profile); - security_state::SecurityLevel security_level = - static_cast<security_state::SecurityLevel>(j_security_level); - GURL url = GURL(base::android::ConvertJavaStringToUTF16(env, j_url)); - - base::string16 search_terms; - bool should_display = - QueryInOmniboxFactory::GetForProfile(profile)->GetDisplaySearchTerms( - security_level, j_ignore_security_level, url, &search_terms); - - if (!should_display) - return nullptr; - - return base::android::ConvertUTF16ToJavaString(env, search_terms); -}
diff --git a/chrome/browser/android/tab_android.cc b/chrome/browser/android/tab_android.cc index a250d55..5e88e20e5 100644 --- a/chrome/browser/android/tab_android.cc +++ b/chrome/browser/android/tab_android.cc
@@ -68,6 +68,7 @@ #include "content/public/browser/render_process_host.h" #include "content/public/browser/render_view_host.h" #include "content/public/browser/web_contents.h" +#include "content/public/browser/web_contents_user_data.h" #include "content/public/common/resource_request_body_android.h" #include "jni/Tab_jni.h" #include "mojo/public/cpp/bindings/strong_binding.h" @@ -101,6 +102,34 @@ namespace { +class TabAndroidHelper : public content::WebContentsUserData<TabAndroidHelper> { + public: + explicit TabAndroidHelper(content::WebContents*) {} + static void SetTabForWebContents(WebContents* contents, + TabAndroid* tab_android) { + content::WebContentsUserData<TabAndroidHelper>::CreateForWebContents( + contents); + content::WebContentsUserData<TabAndroidHelper>::FromWebContents(contents) + ->tab_android_ = tab_android; + } + static TabAndroid* FromWebContents(const WebContents* contents) { + if (TabAndroidHelper* helper = static_cast<TabAndroidHelper*>( + contents->GetUserData(UserDataKey()))) { + return helper->tab_android_; + } + return nullptr; + } + + private: + friend class content::WebContentsUserData<TabAndroidHelper>; + + TabAndroid* tab_android_; + + WEB_CONTENTS_USER_DATA_KEY_DECL(); +}; + +WEB_CONTENTS_USER_DATA_KEY_IMPL(TabAndroidHelper) + GURL GetPublisherURLForTrustedCDN( content::NavigationHandle* navigation_handle) { if (!trusted_cdn::IsTrustedCDN(navigation_handle->GetURL())) @@ -169,17 +198,8 @@ }; TabAndroid* TabAndroid::FromWebContents( - const content::WebContents* web_contents) { - const CoreTabHelper* core_tab_helper = CoreTabHelper::FromWebContents( - web_contents); - if (!core_tab_helper) - return NULL; - - CoreTabHelperDelegate* core_delegate = core_tab_helper->delegate(); - if (!core_delegate) - return NULL; - - return static_cast<TabAndroid*>(core_delegate); + const content::WebContents* web_contents) { + return TabAndroidHelper::FromWebContents(web_contents); } TabAndroid* TabAndroid::GetNativeTab(JNIEnv* env, const JavaRef<jobject>& obj) { @@ -377,7 +397,7 @@ jcontext_menu_populator); ViewAndroidHelper::FromWebContents(web_contents())-> SetViewAndroid(web_contents()->GetNativeView()); - CoreTabHelper::FromWebContents(web_contents())->set_delegate(this); + TabAndroidHelper::SetTabForWebContents(web_contents(), this); web_contents_delegate_ = std::make_unique<android::TabWebContentsDelegateAndroid>( env, jweb_contents_delegate); @@ -455,7 +475,7 @@ } else { // Remove the link from the native WebContents to |this|, since the // lifetimes of the two objects are no longer intertwined. - CoreTabHelper::FromWebContents(web_contents())->set_delegate(nullptr); + TabAndroidHelper::SetTabForWebContents(web_contents(), nullptr); // Release the WebContents so it does not get deleted by the scoped_ptr. ignore_result(web_contents_.release()); }
diff --git a/chrome/browser/android/tab_android.h b/chrome/browser/android/tab_android.h index 00414eb..320608e 100644 --- a/chrome/browser/android/tab_android.h +++ b/chrome/browser/android/tab_android.h
@@ -18,7 +18,6 @@ #include "base/strings/string16.h" #include "chrome/browser/android/tab_state.h" #include "chrome/browser/sync/glue/synced_tab_delegate_android.h" -#include "chrome/browser/ui/tab_contents/core_tab_helper_delegate.h" #include "components/favicon/core/favicon_driver_observer.h" #include "components/infobars/core/infobar_manager.h" #include "components/omnibox/browser/location_bar_model.h" @@ -51,8 +50,7 @@ class PrerenderManager; } -class TabAndroid : public CoreTabHelperDelegate, - public favicon::FaviconDriverObserver, +class TabAndroid : public favicon::FaviconDriverObserver, public content::WebContentsObserver { public: // A Java counterpart will be generated for this enum.
diff --git a/chrome/browser/apps/app_shim/app_shim_interactive_uitest_mac.mm b/chrome/browser/apps/app_shim/app_shim_interactive_uitest_mac.mm index 4dab2d9a..fea77e8 100644 --- a/chrome/browser/apps/app_shim/app_shim_interactive_uitest_mac.mm +++ b/chrome/browser/apps/app_shim/app_shim_interactive_uitest_mac.mm
@@ -86,7 +86,12 @@ WindowedAppShimLaunchObserver(const std::string& app_id) : app_mode_id_(app_id), observed_(false) { - apps::AppShimHandler::RegisterHandler(app_id, this); + StartObserving(); + } + + void StartObserving() { + observed_ = false; + apps::AppShimHandler::RegisterHandler(app_mode_id_, this); } void Wait() { @@ -112,7 +117,14 @@ apps::AppShimFocusType focus_type, const std::vector<base::FilePath>& files) override {} void OnShimSetHidden(AppShimHost* host, bool hidden) override {} - void OnShimQuit(AppShimHost* host) override {} + void OnShimQuit(AppShimHost* host) override { + // Remove self and pass through to the default handler. + apps::AppShimHandler::RemoveHandler(app_mode_id_); + apps::AppShimHandler::GetForAppMode(app_mode_id_)->OnShimQuit(host); + observed_ = true; + if (run_loop_.get()) + run_loop_->Quit(); + } private: std::string app_mode_id_; @@ -291,7 +303,7 @@ #define MAYBE_ShowWindow DISABLED_ShowWindow #define MAYBE_RebuildShim DISABLED_RebuildShim #else -#define MAYBE_Launch DISABLED_Launch // http://crbug.com/913490 +#define MAYBE_Launch Launch #define MAYBE_HostedAppLaunch DISABLED_HostedAppLaunch #define MAYBE_ShowWindow ShowWindow // http://crbug.com/517744 HostedAppLaunch fails with open as tab for apps @@ -387,10 +399,9 @@ EXPECT_TRUE(HasAppShimHost(profile(), app->id())); // Quitting the shim will eventually cause it to quit. It actually - // intercepts the -terminate, sends an AppShimHostMsg_QuitApp to Chrome, - // and returns NSTerminateLater. Chrome responds by closing all windows of - // the app. Once all windows are closed, Chrome closes the IPC channel, - // which causes the shim to actually terminate. + // intercepts the -terminate, sends an QuitApp message to Chrome, and then + // immediately quits. Chrome closes all windows of the app when QuitApp is + // received. NSArray* running_shim = [NSRunningApplication runningApplicationsWithBundleIdentifier:bundle_id]; ASSERT_EQ(1u, [running_shim count]); @@ -399,8 +410,10 @@ initForWorkspaceNotification: NSWorkspaceDidTerminateApplicationNotification bundleId:bundle_id]); + observer.StartObserving(); [base::mac::ObjCCastStrict<NSRunningApplication>( [running_shim objectAtIndex:0]) terminate]; + observer.Wait(); EXPECT_TRUE([ns_observer wait]); EXPECT_FALSE(GetFirstAppWindow());
diff --git a/chrome/browser/chromeos/BUILD.gn b/chrome/browser/chromeos/BUILD.gn index e114d40..fed90925 100644 --- a/chrome/browser/chromeos/BUILD.gn +++ b/chrome/browser/chromeos/BUILD.gn
@@ -96,6 +96,7 @@ "//chromeos/components/proximity_auth/logging", "//chromeos/components/tether", "//chromeos/network", + "//chromeos/services/device_sync/proto", "//chromeos/services/device_sync/public/cpp", "//chromeos/services/machine_learning/public/cpp", "//chromeos/services/machine_learning/public/mojom", @@ -118,7 +119,6 @@ "//components/crash/content/app", "//components/crx_file", "//components/cryptauth", - "//components/cryptauth/proto", "//components/device_event_log", "//components/download/content/public", "//components/drive",
diff --git a/chrome/browser/chromeos/crostini/crostini_share_path.cc b/chrome/browser/chromeos/crostini/crostini_share_path.cc index affe64a..c9cd8314 100644 --- a/chrome/browser/chromeos/crostini/crostini_share_path.cc +++ b/chrome/browser/chromeos/crostini/crostini_share_path.cc
@@ -146,6 +146,8 @@ bool allowed_path = false; base::FilePath my_files = file_manager::util::GetMyFilesFolderForProfile(profile_); + base::FilePath android_files(file_manager::util::kAndroidFilesPath); + base::FilePath removable_media(file_manager::util::kRemovableMediaPath); if (my_files == path || my_files.AppendRelativePath(path, &relative_path)) { allowed_path = true; request.set_storage_location( @@ -191,8 +193,13 @@ // but is included to make it explicit that .Trash should not be shared. allowed_path = false; } - } else if (base::FilePath("/media/removable") - .AppendRelativePath(path, &relative_path)) { + } else if (path == android_files || + android_files.AppendRelativePath(path, &relative_path)) { + // Allow Android files and subdirs. + allowed_path = true; + request.set_storage_location( + vm_tools::seneschal::SharePathRequest::PLAY_FILES); + } else if (removable_media.AppendRelativePath(path, &relative_path)) { // Allow subdirs of /media/removable. allowed_path = true; request.set_storage_location(
diff --git a/chrome/browser/chromeos/cryptauth/chrome_cryptauth_service.cc b/chrome/browser/chromeos/cryptauth/chrome_cryptauth_service.cc index 9d4135c..e64b321 100644 --- a/chrome/browser/chromeos/cryptauth/chrome_cryptauth_service.cc +++ b/chrome/browser/chromeos/cryptauth/chrome_cryptauth_service.cc
@@ -19,6 +19,7 @@ #include "chrome/browser/signin/identity_manager_factory.h" #include "chrome/common/pref_names.h" #include "chromeos/components/proximity_auth/logging/logging.h" +#include "chromeos/services/device_sync/proto/cryptauth_api.pb.h" #include "chromeos/services/multidevice_setup/public/cpp/prefs.h" #include "components/cryptauth/cryptauth_client.h" #include "components/cryptauth/cryptauth_client_impl.h" @@ -29,7 +30,6 @@ #include "components/cryptauth/cryptauth_enrollment_utils.h" #include "components/cryptauth/cryptauth_gcm_manager_impl.h" #include "components/cryptauth/device_classifier_util.h" -#include "components/cryptauth/proto/cryptauth_api.pb.h" #include "components/cryptauth/secure_message_delegate_impl.h" #include "components/gcm_driver/gcm_profile_service.h" #include "components/prefs/pref_service.h"
diff --git a/chrome/browser/chromeos/cryptauth/chrome_cryptauth_service.h b/chrome/browser/chromeos/cryptauth/chrome_cryptauth_service.h index 8931e18..56725767 100644 --- a/chrome/browser/chromeos/cryptauth/chrome_cryptauth_service.h +++ b/chrome/browser/chromeos/cryptauth/chrome_cryptauth_service.h
@@ -9,9 +9,9 @@ #include "base/macros.h" #include "base/memory/weak_ptr.h" +#include "chromeos/services/device_sync/proto/cryptauth_api.pb.h" #include "components/cryptauth/cryptauth_enrollment_manager.h" #include "components/cryptauth/cryptauth_service.h" -#include "components/cryptauth/proto/cryptauth_api.pb.h" #include "components/keyed_service/core/keyed_service.h" #include "components/prefs/pref_change_registrar.h" #include "services/identity/public/cpp/identity_manager.h"
diff --git a/chrome/browser/chromeos/cryptauth/gcm_device_info_provider_impl.h b/chrome/browser/chromeos/cryptauth/gcm_device_info_provider_impl.h index 7168743..95d4d8b4 100644 --- a/chrome/browser/chromeos/cryptauth/gcm_device_info_provider_impl.h +++ b/chrome/browser/chromeos/cryptauth/gcm_device_info_provider_impl.h
@@ -7,8 +7,8 @@ #include "base/macros.h" #include "base/no_destructor.h" +#include "chromeos/services/device_sync/proto/cryptauth_api.pb.h" #include "components/cryptauth/gcm_device_info_provider.h" -#include "components/cryptauth/proto/cryptauth_api.pb.h" namespace chromeos {
diff --git a/chrome/browser/chromeos/file_manager/file_manager_jstest.cc b/chrome/browser/chromeos/file_manager/file_manager_jstest.cc index 2576930..8cfccd0 100644 --- a/chrome/browser/chromeos/file_manager/file_manager_jstest.cc +++ b/chrome/browser/chromeos/file_manager/file_manager_jstest.cc
@@ -126,8 +126,8 @@ } IN_PROC_BROWSER_TEST_F(FileManagerJsTest, ExternalMetadataProvider) { - RunTest(base::FilePath(FILE_PATH_LITERAL( - "foreground/js/metadata/external_metadata_provider_unittest.html"))); + RunGeneratedTest( + "/foreground/js/metadata/external_metadata_provider_unittest.html"); } IN_PROC_BROWSER_TEST_F(FileManagerJsTest, ContentMetadataProvider) {
diff --git a/chrome/browser/chromeos/file_manager/path_util.cc b/chrome/browser/chromeos/file_manager/path_util.cc index cc53910..83bc815 100644 --- a/chrome/browser/chromeos/file_manager/path_util.cc +++ b/chrome/browser/chromeos/file_manager/path_util.cc
@@ -43,6 +43,7 @@ constexpr char kAndroidFilesMountPointName[] = "android_files"; constexpr char kCrostiniMapGoogleDrive[] = "GoogleDrive"; constexpr char kCrostiniMapMyDrive[] = "MyDrive"; +constexpr char kCrostiniMapPlayFiles[] = "PlayFiles"; constexpr char kCrostiniMapTeamDrives[] = "TeamDrives"; constexpr char kFolderNameDownloads[] = "Downloads"; constexpr char kFolderNameMyFiles[] = "MyFiles"; @@ -251,8 +252,6 @@ // File system root requires strip trailing separator. base::FilePath path = base::FilePath(file_system_url.virtual_path()).StripTrailingSeparators(); - std::string mount_point_name_crostini = GetCrostiniMountPointName(profile); - std::string mount_point_name_downloads = GetDownloadsMountPointName(profile); // Include drive if using DriveFS. std::string mount_point_name_drive; auto* integration_service = @@ -269,10 +268,10 @@ // /<home-directory>/path/to/file (path is already in crostini volume) // /ChromeOS/<mapping>/path/to/file (path is shared with crostini) base::FilePath base_to_exclude(id); - if (id == mount_point_name_crostini) { + if (id == GetCrostiniMountPointName(profile)) { // Crostini. *inside = crostini::ContainerHomeDirectoryForProfile(profile); - } else if (id == mount_point_name_downloads) { + } else if (id == GetDownloadsMountPointName(profile)) { // MyFiles or Downloads. if (base::FeatureList::IsEnabled(chromeos::features::kMyFilesVolume)) { // MyFiles. @@ -306,6 +305,9 @@ // Removable. *inside = crostini::ContainerChromeOSBaseDirectory().Append( chromeos::kSystemMountNameRemovable); + } else if (id == GetAndroidFilesMountPointName()) { + *inside = crostini::ContainerChromeOSBaseDirectory().Append( + kCrostiniMapPlayFiles); } else { return false; }
diff --git a/chrome/browser/chromeos/file_manager/path_util_unittest.cc b/chrome/browser/chromeos/file_manager/path_util_unittest.cc index 0049b08..791129d 100644 --- a/chrome/browser/chromeos/file_manager/path_util_unittest.cc +++ b/chrome/browser/chromeos/file_manager/path_util_unittest.cc
@@ -331,7 +331,7 @@ base::test::ScopedFeatureList features; features.InitAndEnableFeature(chromeos::features::kDriveFs); - // Register crostini, downloads, drive. + // Register crostini, downloads, drive, android. mount_points->RegisterFileSystem(GetCrostiniMountPointName(&profile), storage::kFileSystemTypeNativeLocal, storage::FileSystemMountOption(), @@ -340,6 +340,9 @@ storage::kFileSystemTypeNativeLocal, storage::FileSystemMountOption(), GetDownloadsFolderForProfile(&profile)); + mount_points->RegisterFileSystem( + GetAndroidFilesMountPointName(), storage::kFileSystemTypeNativeLocal, + storage::FileSystemMountOption(), base::FilePath(kAndroidFilesPath)); drive::DriveIntegrationService* integration_service = drive::DriveIntegrationServiceFactory::GetForProfile(&profile); base::FilePath mount_point_drive = integration_service->GetMountPointPath(); @@ -396,6 +399,13 @@ EXPECT_TRUE(ConvertFileSystemURLToPathInsideCrostini( &profile, mount_points->CreateExternalFileSystemURL( + GURL(), "android_files", base::FilePath("path/in/android")), + &inside)); + EXPECT_EQ("/mnt/chromeos/PlayFiles/path/in/android", inside.value()); + + EXPECT_TRUE(ConvertFileSystemURLToPathInsideCrostini( + &profile, + mount_points->CreateExternalFileSystemURL( GURL(), "drivefs-84675c855b63e12f384d45f033826980", base::FilePath("root/path/in/mydrive")), &inside));
diff --git a/chrome/browser/chromeos/login/easy_unlock/easy_unlock_challenge_wrapper.cc b/chrome/browser/chromeos/login/easy_unlock/easy_unlock_challenge_wrapper.cc index 9a4e61f..1fc86d3 100644 --- a/chrome/browser/chromeos/login/easy_unlock/easy_unlock_challenge_wrapper.cc +++ b/chrome/browser/chromeos/login/easy_unlock/easy_unlock_challenge_wrapper.cc
@@ -7,7 +7,7 @@ #include "base/bind.h" #include "chrome/browser/chromeos/login/easy_unlock/easy_unlock_tpm_key_manager.h" #include "chromeos/components/proximity_auth/logging/logging.h" -#include "components/cryptauth/proto/securemessage.pb.h" +#include "chromeos/services/device_sync/proto/securemessage.pb.h" namespace chromeos {
diff --git a/chrome/browser/chromeos/login/easy_unlock/easy_unlock_challenge_wrapper_unittest.cc b/chrome/browser/chromeos/login/easy_unlock/easy_unlock_challenge_wrapper_unittest.cc index d1aa85f..345b574 100644 --- a/chrome/browser/chromeos/login/easy_unlock/easy_unlock_challenge_wrapper_unittest.cc +++ b/chrome/browser/chromeos/login/easy_unlock/easy_unlock_challenge_wrapper_unittest.cc
@@ -6,7 +6,7 @@ #include "base/bind.h" #include "base/macros.h" -#include "components/cryptauth/proto/securemessage.pb.h" +#include "chromeos/services/device_sync/proto/securemessage.pb.h" #include "testing/gtest/include/gtest/gtest.h" namespace chromeos {
diff --git a/chrome/browser/chromeos/login/sync_consent_interactive_ui_test.cc b/chrome/browser/chromeos/login/sync_consent_interactive_ui_test.cc index c2138a9f..e2e165c 100644 --- a/chrome/browser/chromeos/login/sync_consent_interactive_ui_test.cc +++ b/chrome/browser/chromeos/login/sync_consent_interactive_ui_test.cc
@@ -4,6 +4,8 @@ #include "base/command_line.h" #include "base/macros.h" +#include "base/strings/utf_string_conversions.h" +#include "chrome/browser/browser_process.h" #include "chrome/browser/chrome_notification_types.h" #include "chrome/browser/chromeos/login/screens/gaia_view.h" #include "chrome/browser/chromeos/login/screens/sync_consent_screen.h" @@ -15,12 +17,12 @@ #include "chrome/browser/ui/webui/chromeos/login/signin_screen_handler.h" #include "chrome/grit/generated_resources.h" #include "content/public/browser/notification_service.h" +#include "ui/base/l10n/l10n_util.h" namespace chromeos { namespace { constexpr base::TimeDelta kJsConditionCheckFrequency = base::TimeDelta::FromMilliseconds(2000); -} // anonymous namespace class ConsentRecordedWaiter : public SyncConsentScreen::SyncConsentScreenTestDelegate { @@ -111,6 +113,16 @@ DISALLOW_COPY_AND_ASSIGN(JsConditionWaiter); }; +std::string GetLocalizedConsentString(const int id) { + std::string sanitized_string = + base::UTF16ToUTF8(l10n_util::GetStringUTF16(id)); + base::ReplaceSubstringsAfterOffset(&sanitized_string, 0, "\u00A0" /* NBSP */, + " "); + return sanitized_string; +} + +} // anonymous namespace + class SyncConsentTest : public OobeBaseTest { public: SyncConsentTest() = default; @@ -127,15 +139,26 @@ OobeBaseTest::TearDownOnMainThread(); } - void LoginToSyncConsentScreen() { + void WaitForUIToLoad() { content::WindowedNotificationObserver observer( chrome::NOTIFICATION_LOGIN_OR_LOCK_WEBUI_VISIBLE, content::NotificationService::AllSources()); + observer.Wait(); + } + + void SwitchLanguage(const std::string& language) { + const char get_num_reloads[] = "Oobe.getInstance().reloadContentNumEvents_"; + const int prev_reloads = JS().GetInt(get_num_reloads); + JS().Evaluate("$('connect').onLanguageSelected_('" + language + "');"); + const std::string condition = + base::StringPrintf("%s > %d", get_num_reloads, prev_reloads); + JsConditionWaiter(js_checker_, condition).Wait(); + } + + void LoginToSyncConsentScreen() { WizardController::default_controller()->SkipToLoginForTesting( LoginScreenContext()); - observer.Wait(); WaitForGaiaPageEvent("ready"); - LoginDisplayHost::default_host() ->GetOobeUI() ->GetGaiaScreenView() @@ -148,30 +171,67 @@ .Wait(); } + protected: + void SyncConsentRecorderTestImpl( + const std::vector<std::string>& expected_consent_strings, + const std::string expected_consent_confirmation_string) { + SyncConsentScreen* screen = static_cast<SyncConsentScreen*>( + WizardController::default_controller()->GetScreen( + OobeScreen::SCREEN_SYNC_CONSENT)); + ConsentRecordedWaiter consent_recorded_waiter; + screen->SetDelegateForTesting(&consent_recorded_waiter); + + screen->SetProfileSyncDisabledByPolicyForTesting(false); + screen->SetProfileSyncEngineInitializedForTesting(true); + screen->OnStateChanged(nullptr); + + JsConditionWaiter(js_checker_, "!$('sync-consent-impl').hidden").Wait(); + JsExpect("!$('sync-consent-impl').$.syncConsentOverviewDialog.hidden"); + JS().Evaluate( + "$('sync-consent-impl').$. settingsSaveAndContinueButton.click()"); + consent_recorded_waiter.Wait(); + screen->SetDelegateForTesting(nullptr); // cleanup + + const int expected_consent_confirmation_id = + IDS_LOGIN_SYNC_CONSENT_SCREEN_ACCEPT_AND_CONTINUE; + + EXPECT_EQ(expected_consent_strings, + consent_recorded_waiter.get_consent_description_strings()); + EXPECT_EQ(expected_consent_confirmation_string, + consent_recorded_waiter.get_consent_confirmation_string()); + EXPECT_EQ(expected_consent_ids, + consent_recorded_waiter.get_consent_description_ids()); + EXPECT_EQ(expected_consent_confirmation_id, + consent_recorded_waiter.get_consent_confirmation_id()); + } + + std::vector<std::string> GetLocalizedExpectedConsentStrings() const { + std::vector<std::string> result; + for (const int& id : expected_consent_ids) { + result.push_back(GetLocalizedConsentString(id)); + } + return result; + } + + const std::vector<int> expected_consent_ids = { + IDS_LOGIN_SYNC_CONSENT_SCREEN_TITLE, + IDS_LOGIN_SYNC_CONSENT_SCREEN_CHROME_SYNC_NAME, + IDS_LOGIN_SYNC_CONSENT_SCREEN_CHROME_SYNC_DESCRIPTION, + IDS_LOGIN_SYNC_CONSENT_SCREEN_PERSONALIZE_GOOGLE_SERVICES_NAME, + IDS_LOGIN_SYNC_CONSENT_SCREEN_PERSONALIZE_GOOGLE_SERVICES_DESCRIPTION, + IDS_LOGIN_SYNC_CONSENT_SCREEN_REVIEW_SYNC_OPTIONS_LATER, + IDS_LOGIN_SYNC_CONSENT_SCREEN_ACCEPT_AND_CONTINUE, + }; + private: DISALLOW_COPY_AND_ASSIGN(SyncConsentTest); }; IN_PROC_BROWSER_TEST_F(SyncConsentTest, SyncConsentRecorder) { + WaitForUIToLoad(); + EXPECT_EQ(g_browser_process->GetApplicationLocale(), "en-US"); LoginToSyncConsentScreen(); - - SyncConsentScreen* screen = static_cast<SyncConsentScreen*>( - WizardController::default_controller()->GetScreen( - OobeScreen::SCREEN_SYNC_CONSENT)); - ConsentRecordedWaiter consent_recorded_waiter; - screen->SetDelegateForTesting(&consent_recorded_waiter); - - screen->SetProfileSyncDisabledByPolicyForTesting(false); - screen->SetProfileSyncEngineInitializedForTesting(true); - screen->OnStateChanged(nullptr); - - JsConditionWaiter(js_checker_, "!$('sync-consent-impl').hidden").Wait(); - JsExpect("!$('sync-consent-impl').$.syncConsentOverviewDialog.hidden"); - JS().Evaluate( - "$('sync-consent-impl').$. settingsSaveAndContinueButton.click()"); - consent_recorded_waiter.Wait(); - screen->SetDelegateForTesting(nullptr); // cleanup - + // For En-US we hardcode strings here to catch string issues too. const std::vector<std::string> expected_consent_strings( {"You're signed in!", "Chrome sync", "Your bookmarks, history, passwords, and other settings will be synced " @@ -181,32 +241,44 @@ "other Google services. You can change this anytime at " "myaccount.google.com/activitycontrols/search", "Review sync options following setup", "Accept and continue"}); - - const std::vector<int> expected_consent_ids({ - IDS_LOGIN_SYNC_CONSENT_SCREEN_TITLE, - IDS_LOGIN_SYNC_CONSENT_SCREEN_CHROME_SYNC_NAME, - IDS_LOGIN_SYNC_CONSENT_SCREEN_CHROME_SYNC_DESCRIPTION, - IDS_LOGIN_SYNC_CONSENT_SCREEN_PERSONALIZE_GOOGLE_SERVICES_NAME, - IDS_LOGIN_SYNC_CONSENT_SCREEN_PERSONALIZE_GOOGLE_SERVICES_DESCRIPTION, - IDS_LOGIN_SYNC_CONSENT_SCREEN_REVIEW_SYNC_OPTIONS_LATER, - IDS_LOGIN_SYNC_CONSENT_SCREEN_ACCEPT_AND_CONTINUE, - }); - const std::string expected_consent_confirmation_string = "Accept and continue"; - const int expected_consent_confirmation_id = - IDS_LOGIN_SYNC_CONSENT_SCREEN_ACCEPT_AND_CONTINUE; - - EXPECT_EQ(expected_consent_strings, - consent_recorded_waiter.get_consent_description_strings()); - EXPECT_EQ(expected_consent_confirmation_string, - consent_recorded_waiter.get_consent_confirmation_string()); - EXPECT_EQ(expected_consent_ids, - consent_recorded_waiter.get_consent_description_ids()); - EXPECT_EQ(expected_consent_confirmation_id, - consent_recorded_waiter.get_consent_confirmation_id()); + SyncConsentRecorderTestImpl(expected_consent_strings, + expected_consent_confirmation_string); } +class SyncConsentTestWithParams + : public SyncConsentTest, + public ::testing::WithParamInterface<std::string> { + public: + SyncConsentTestWithParams() = default; + ~SyncConsentTestWithParams() = default; + + private: + DISALLOW_COPY_AND_ASSIGN(SyncConsentTestWithParams); +}; + +IN_PROC_BROWSER_TEST_P(SyncConsentTestWithParams, SyncConsentTestWithLocale) { + LOG(INFO) << "SyncConsentTestWithParams() started with param='" << GetParam() + << "'"; + WaitForUIToLoad(); + EXPECT_EQ(g_browser_process->GetApplicationLocale(), "en-US"); + SwitchLanguage(GetParam()); + LoginToSyncConsentScreen(); + const std::vector<std::string> expected_consent_strings = + GetLocalizedExpectedConsentStrings(); + const std::string expected_consent_confirmation_string = + GetLocalizedConsentString( + IDS_LOGIN_SYNC_CONSENT_SCREEN_ACCEPT_AND_CONTINUE); + SyncConsentRecorderTestImpl(expected_consent_strings, + expected_consent_confirmation_string); +} + +// "es" tests language switching, "en-GB" checks switching to language varants. +INSTANTIATE_TEST_CASE_P(SyncConsentTestWithParamsImpl, + SyncConsentTestWithParams, + testing::Values("es", "en-GB")); + // Check that policy-disabled sync does not trigger SyncConsent screen. // // We need to check that "disabled by policy" disables SyncConsent screen
diff --git a/chrome/browser/dom_distiller/tab_utils.cc b/chrome/browser/dom_distiller/tab_utils.cc index 6d63b42f..c97601e 100644 --- a/chrome/browser/dom_distiller/tab_utils.cc +++ b/chrome/browser/dom_distiller/tab_utils.cc
@@ -11,7 +11,6 @@ #include "base/threading/thread_task_runner_handle.h" #include "chrome/browser/dom_distiller/dom_distiller_service_factory.h" #include "chrome/browser/ui/tab_contents/core_tab_helper.h" -#include "chrome/browser/ui/tab_contents/core_tab_helper_delegate.h" #include "components/dom_distiller/content/browser/distiller_page_web_contents.h" #include "components/dom_distiller/core/distiller_page.h" #include "components/dom_distiller/core/dom_distiller_service.h"
diff --git a/chrome/browser/extensions/active_tab_unittest.cc b/chrome/browser/extensions/active_tab_unittest.cc index 2b4be91..0d44679 100644 --- a/chrome/browser/extensions/active_tab_unittest.cc +++ b/chrome/browser/extensions/active_tab_unittest.cc
@@ -180,7 +180,8 @@ bool script = permissions_data->CanAccessPage(url, tab_id, nullptr) && permissions_data->CanRunContentScriptOnPage(url, tab_id, nullptr); - bool capture = permissions_data->CanCaptureVisiblePage(url, tab_id, NULL); + bool capture = permissions_data->CanCaptureVisiblePage( + url, tab_id, NULL, extensions::CaptureRequirement::kActiveTabOrAllUrls); switch (feature) { case PERMITTED_SCRIPT_ONLY: return script && !capture; @@ -361,15 +362,18 @@ EXPECT_EQ(url, web_contents()->GetLastCommittedURL()); // By default, there should be no access. EXPECT_FALSE(extension->permissions_data()->CanCaptureVisiblePage( - url, tab_id(), nullptr /*error*/)); + url, tab_id(), nullptr /*error*/, + extensions::CaptureRequirement::kActiveTabOrAllUrls)); // Granting permission should allow page capture. active_tab_permission_granter()->GrantIfRequested(extension.get()); EXPECT_TRUE(extension->permissions_data()->CanCaptureVisiblePage( - url, tab_id(), nullptr /*error*/)); + url, tab_id(), nullptr /*error*/, + extensions::CaptureRequirement::kActiveTabOrAllUrls)); // Navigating away should revoke access. NavigateAndCommit(kAboutBlank); EXPECT_FALSE(extension->permissions_data()->CanCaptureVisiblePage( - url, tab_id(), nullptr /*error*/)); + url, tab_id(), nullptr /*error*/, + extensions::CaptureRequirement::kActiveTabOrAllUrls)); } } @@ -705,11 +709,13 @@ EXPECT_NE(extension_misc::kUnknownTabId, tab_id); EXPECT_FALSE(extension->permissions_data()->CanCaptureVisiblePage( - web_contents->GetLastCommittedURL(), tab_id, nullptr)); + web_contents->GetLastCommittedURL(), tab_id, nullptr, + extensions::CaptureRequirement::kActiveTabOrAllUrls)); permission_granter->GrantIfRequested(extension.get()); EXPECT_FALSE(extension->permissions_data()->CanCaptureVisiblePage( - web_contents->GetLastCommittedURL(), tab_id, nullptr)); + web_contents->GetLastCommittedURL(), tab_id, nullptr, + extensions::CaptureRequirement::kActiveTabOrAllUrls)); permission_granter->RevokeForTesting(); TestExtensionRegistryObserver observer(registry(), id); @@ -719,10 +725,12 @@ ASSERT_TRUE(extension); EXPECT_FALSE(extension->permissions_data()->CanCaptureVisiblePage( - web_contents->GetLastCommittedURL(), tab_id, nullptr)); + web_contents->GetLastCommittedURL(), tab_id, nullptr, + extensions::CaptureRequirement::kActiveTabOrAllUrls)); permission_granter->GrantIfRequested(extension.get()); EXPECT_TRUE(extension->permissions_data()->CanCaptureVisiblePage( - web_contents->GetLastCommittedURL(), tab_id, nullptr)); + web_contents->GetLastCommittedURL(), tab_id, nullptr, + extensions::CaptureRequirement::kActiveTabOrAllUrls)); } } // namespace
diff --git a/chrome/browser/extensions/api/autofill_private/autofill_private_api.cc b/chrome/browser/extensions/api/autofill_private/autofill_private_api.cc index 6021e64..3fea3a1 100644 --- a/chrome/browser/extensions/api/autofill_private/autofill_private_api.cc +++ b/chrome/browser/extensions/api/autofill_private/autofill_private_api.cc
@@ -595,4 +595,27 @@ return RespondNow(NoArguments()); } +//////////////////////////////////////////////////////////////////////////////// +// AutofillPrivateLogServerCardLinkClickedFunction + +AutofillPrivateLogServerCardLinkClickedFunction:: + AutofillPrivateLogServerCardLinkClickedFunction() + : chrome_details_(this) {} + +AutofillPrivateLogServerCardLinkClickedFunction:: + ~AutofillPrivateLogServerCardLinkClickedFunction() {} + +ExtensionFunction::ResponseAction +AutofillPrivateLogServerCardLinkClickedFunction::Run() { + autofill::PersonalDataManager* personal_data = + autofill::PersonalDataManagerFactory::GetForProfile( + chrome_details_.GetProfile()); + + if (!personal_data || !personal_data->IsDataLoaded()) + return RespondNow(Error(kErrorDataUnavailable)); + + personal_data->LogServerCardLinkClicked(); + return RespondNow(NoArguments()); +} + } // namespace extensions
diff --git a/chrome/browser/extensions/api/autofill_private/autofill_private_api.h b/chrome/browser/extensions/api/autofill_private/autofill_private_api.h index a1b14bed..dde502d 100644 --- a/chrome/browser/extensions/api/autofill_private/autofill_private_api.h +++ b/chrome/browser/extensions/api/autofill_private/autofill_private_api.h
@@ -193,6 +193,25 @@ DISALLOW_COPY_AND_ASSIGN(AutofillPrivateMigrateCreditCardsFunction); }; +class AutofillPrivateLogServerCardLinkClickedFunction + : public UIThreadExtensionFunction { + public: + AutofillPrivateLogServerCardLinkClickedFunction(); + DECLARE_EXTENSION_FUNCTION("autofillPrivate.logServerCardLinkClicked", + AUTOFILLPRIVATE_SERVERCARDLINKCLICKED); + + protected: + ~AutofillPrivateLogServerCardLinkClickedFunction() override; + + // ExtensionFunction overrides. + ResponseAction Run() override; + + private: + ChromeExtensionFunctionDetails chrome_details_; + + DISALLOW_COPY_AND_ASSIGN(AutofillPrivateLogServerCardLinkClickedFunction); +}; + } // namespace extensions #endif // CHROME_BROWSER_EXTENSIONS_API_AUTOFILL_PRIVATE_AUTOFILL_PRIVATE_API_H_
diff --git a/chrome/browser/extensions/api/page_capture/page_capture_api.cc b/chrome/browser/extensions/api/page_capture/page_capture_api.cc index 28bbd0c..3edc8b9 100644 --- a/chrome/browser/extensions/api/page_capture/page_capture_api.cc +++ b/chrome/browser/extensions/api/page_capture/page_capture_api.cc
@@ -13,8 +13,10 @@ #include "base/task/post_task.h" #include "chrome/browser/browser_process.h" #include "chrome/browser/extensions/extension_tab_util.h" +#include "chrome/browser/extensions/extension_util.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/profiles/profiles_state.h" +#include "chrome/browser/sessions/session_tab_helper.h" #include "content/public/browser/browser_task_traits.h" #include "content/public/browser/browser_thread.h" #include "content/public/browser/child_process_security_policy.h" @@ -45,10 +47,11 @@ const char kMHTMLGenerationFailedError[] = "Failed to generate MHTML."; const char kTemporaryFileError[] = "Failed to create a temporary file."; const char kTabClosedError[] = "Cannot find the tab for this request."; +const char kPageCaptureNotAllowed[] = + "Don't have permissions required to capture this page."; #if defined(OS_CHROMEOS) const char kUserDenied[] = "User denied request."; #endif - constexpr base::TaskTraits kCreateTemporaryFileTaskTraits = { // Requires IO. base::MayBlock(), @@ -113,6 +116,9 @@ } #endif + if (!CanCaptureCurrentPage()) { + return false; + } base::PostTaskWithTraits( FROM_HERE, kCreateTemporaryFileTaskTraits, base::BindOnce(&PageCaptureSaveAsMHTMLFunction::CreateTemporaryFile, @@ -120,6 +126,34 @@ return true; } +bool PageCaptureSaveAsMHTMLFunction::CanCaptureCurrentPage() { + WebContents* web_contents = GetWebContents(); + if (!web_contents) { + error_ = kTabClosedError; + return false; + } + const GURL& url = web_contents->GetLastCommittedURL(); + const GURL origin_url = url::Origin::Create(url).GetURL(); + bool can_capture_page = false; + if (origin_url.SchemeIs(url::kFileScheme)) { + // We special case file schemes, since we don't check for URL permissions + // in CanCaptureVisiblePage() with the pageCapture API. This ensures + // file:// URLs are only capturable with the proper permission. + can_capture_page = extensions::util::AllowFileAccess( + extension()->id(), web_contents->GetBrowserContext()); + } else { + std::string error; + can_capture_page = extension()->permissions_data()->CanCaptureVisiblePage( + url, SessionTabHelper::IdForTab(web_contents).id(), &error, + extensions::CaptureRequirement::kPageCapture); + } + + if (!can_capture_page) { + error_ = kPageCaptureNotAllowed; + } + return can_capture_page; +} + bool PageCaptureSaveAsMHTMLFunction::OnMessageReceived( const IPC::Message& message) { if (message.type() != ExtensionHostMsg_ResponseAck::ID)
diff --git a/chrome/browser/extensions/api/page_capture/page_capture_api.h b/chrome/browser/extensions/api/page_capture/page_capture_api.h index 68ff9cb..bf79224 100644 --- a/chrome/browser/extensions/api/page_capture/page_capture_api.h +++ b/chrome/browser/extensions/api/page_capture/page_capture_api.h
@@ -47,6 +47,10 @@ void ResolvePermissionRequest(const PermissionIDSet& allowed_permissions); #endif + // Returns whether or not the extension has permission to capture the current + // page. + bool CanCaptureCurrentPage(); + // Called on the file thread. void CreateTemporaryFile();
diff --git a/chrome/browser/extensions/api/page_capture/page_capture_apitest.cc b/chrome/browser/extensions/api/page_capture/page_capture_apitest.cc index 96e50f1b..045f0249 100644 --- a/chrome/browser/extensions/api/page_capture/page_capture_apitest.cc +++ b/chrome/browser/extensions/api/page_capture/page_capture_apitest.cc
@@ -5,21 +5,34 @@ #include "base/base_switches.h" #include "base/command_line.h" #include "base/threading/thread_restrictions.h" +#include "chrome/browser/extensions/active_tab_permission_granter.h" #include "chrome/browser/extensions/api/page_capture/page_capture_api.h" +#include "chrome/browser/extensions/extension_action_runner.h" #include "chrome/browser/extensions/extension_apitest.h" +#include "chrome/browser/extensions/extension_util.h" +#include "chrome/browser/extensions/tab_helper.h" #include "chrome/common/chrome_switches.h" +#include "chrome/test/base/ui_test_utils.h" #include "chromeos/login/scoped_test_public_session_login_state.h" #include "content/public/browser/browser_thread.h" #include "content/public/common/content_switches.h" #include "content/public/test/test_utils.h" #include "extensions/browser/extension_dialog_auto_confirm.h" +#include "extensions/common/permissions/permission_set.h" +#include "extensions/common/permissions/permissions_data.h" +#include "extensions/common/url_pattern_set.h" +#include "extensions/test/extension_test_message_listener.h" +#include "extensions/test/result_catcher.h" #include "net/dns/mock_host_resolver.h" #if defined(OS_CHROMEOS) #include "chromeos/login/login_state.h" #endif // defined(OS_CHROMEOS) +using extensions::Extension; +using extensions::ExtensionActionRunner; using extensions::PageCaptureSaveAsMHTMLFunction; +using extensions::ResultCatcher; using extensions::ScopedTestDialogAutoConfirm; class ExtensionPageCaptureApiTest : public extensions::ExtensionApiTest { @@ -55,6 +68,24 @@ IN_PROC_BROWSER_TEST_F(ExtensionPageCaptureApiTest, SaveAsMHTML) { ASSERT_TRUE(StartEmbeddedTestServer()); PageCaptureSaveAsMHTMLDelegate delegate; + ASSERT_TRUE(RunExtensionTestWithFlagsAndArg( + "page_capture", "ONLY_PAGE_CAPTURE_PERMISSION", kFlagNone)) + << message_; + // Make sure the MHTML data gets written to the temporary file. + ASSERT_FALSE(delegate.temp_file_.empty()); + // Flush the message loops to make sure the delete happens. + content::RunAllTasksUntilIdle(); + content::RunAllPendingInMessageLoop(content::BrowserThread::IO); + // Make sure the temporary file is destroyed once the javascript side reads + // the contents. + base::ScopedAllowBlockingForTesting allow_blocking; + ASSERT_FALSE(base::PathExists(delegate.temp_file_)); +} + +IN_PROC_BROWSER_TEST_F(ExtensionPageCaptureApiTest, + SaveAsMHTMLWithActiveTabWithFileAccess) { + ASSERT_TRUE(StartEmbeddedTestServer()); + PageCaptureSaveAsMHTMLDelegate delegate; ASSERT_TRUE(RunExtensionTest("page_capture")) << message_; // Make sure the MHTML data gets written to the temporary file. ASSERT_FALSE(delegate.temp_file_.empty());
diff --git a/chrome/browser/extensions/api/tabs/tabs_api.cc b/chrome/browser/extensions/api/tabs/tabs_api.cc index e02a27d..064cc24 100644 --- a/chrome/browser/extensions/api/tabs/tabs_api.cc +++ b/chrome/browser/extensions/api/tabs/tabs_api.cc
@@ -1712,7 +1712,8 @@ if (!extension()->permissions_data()->CanCaptureVisiblePage( contents->GetLastCommittedURL(), - SessionTabHelper::IdForTab(contents).id(), error)) { + SessionTabHelper::IdForTab(contents).id(), error, + extensions::CaptureRequirement::kActiveTabOrAllUrls)) { return nullptr; } return contents;
diff --git a/chrome/browser/extensions/extension_apitest.cc b/chrome/browser/extensions/extension_apitest.cc index 121bcc3..b9f0d6d 100644 --- a/chrome/browser/extensions/extension_apitest.cc +++ b/chrome/browser/extensions/extension_apitest.cc
@@ -200,6 +200,13 @@ kFlagEnableFileAccess); } +bool ExtensionApiTest::RunExtensionTestWithFlagsAndArg( + const std::string& extension_name, + const char* custom_arg, + int flag) { + return RunExtensionTestImpl(extension_name, std::string(), custom_arg, flag); +} + bool ExtensionApiTest::RunExtensionTestIncognito( const std::string& extension_name) { return RunExtensionTestImpl(extension_name,
diff --git a/chrome/browser/extensions/extension_apitest.h b/chrome/browser/extensions/extension_apitest.h index 92f0c732..23400bc4 100644 --- a/chrome/browser/extensions/extension_apitest.h +++ b/chrome/browser/extensions/extension_apitest.h
@@ -84,6 +84,13 @@ bool RunExtensionTestWithArg(const std::string& extension_name, const char* custom_arg); + // Similar to RunExtensionTest, except sets an additional string arguments + // |customArg| to the test config object and |flags| (as defined in the Flags + // enum). + bool RunExtensionTestWithFlagsAndArg(const std::string& extension_name, + const char* custom_arg, + int flags); + // Same as RunExtensionTest, but enables the extension for incognito mode. bool RunExtensionTestIncognito(const std::string& extension_name);
diff --git a/chrome/browser/flag-metadata.json b/chrome/browser/flag-metadata.json index e8c735992..a8edd79 100644 --- a/chrome/browser/flag-metadata.json +++ b/chrome/browser/flag-metadata.json
@@ -1961,8 +1961,9 @@ }, { "name": "enable-virtual-keyboard", - // "owners": [ "your-team" ], - "expiry_milestone": 76 + "owners": [ "//ui/keyboard/OWNERS" ], + // Useful for debugging the virtual keyboard on non-tablet devices. + "expiry_milestone": -1 }, { "name": "enable-virtual-keyboard-md-ui",
diff --git a/chrome/browser/media/webrtc/webrtc_browsertest_base.cc b/chrome/browser/media/webrtc/webrtc_browsertest_base.cc index 14d0a36..b1b4490 100644 --- a/chrome/browser/media/webrtc/webrtc_browsertest_base.cc +++ b/chrome/browser/media/webrtc/webrtc_browsertest_base.cc
@@ -68,6 +68,8 @@ const char WebRtcTestBase::kUseDefaultCertKeygen[] = "null"; const char WebRtcTestBase::kUseDefaultAudioCodec[] = ""; const char WebRtcTestBase::kUseDefaultVideoCodec[] = ""; +const char WebRtcTestBase::kVP9Profile0Specifier[] = "profile-id=0"; +const char WebRtcTestBase::kVP9Profile2Specifier[] = "profile-id=2"; const char WebRtcTestBase::kUndefined[] = "undefined"; namespace { @@ -590,11 +592,20 @@ void WebRtcTestBase::SetDefaultVideoCodec(content::WebContents* tab, const std::string& video_codec, - bool prefer_hw_codec) const { - EXPECT_EQ("ok", - ExecuteJavascript("setDefaultVideoCodec('" + video_codec + "'," + - (prefer_hw_codec ? "true" : "false") + ")", - tab)); + bool prefer_hw_codec, + const std::string& profile) const { + std::string codec_profile = profile; + // When no |profile| is given, we default VP9 to Profile 0. + if (video_codec.compare("VP9") == 0 && codec_profile.empty()) + codec_profile = kVP9Profile0Specifier; + + EXPECT_EQ("ok", ExecuteJavascript( + "setDefaultVideoCodec('" + video_codec + "'," + + (prefer_hw_codec ? "true" : "false") + "," + + (codec_profile.empty() ? "null" + : "'" + codec_profile + "'") + + ")", + tab)); } void WebRtcTestBase::EnableOpusDtx(content::WebContents* tab) const {
diff --git a/chrome/browser/media/webrtc/webrtc_browsertest_base.h b/chrome/browser/media/webrtc/webrtc_browsertest_base.h index 4375fe7d..1c351a1 100644 --- a/chrome/browser/media/webrtc/webrtc_browsertest_base.h +++ b/chrome/browser/media/webrtc/webrtc_browsertest_base.h
@@ -50,6 +50,9 @@ static const char kUseDefaultAudioCodec[]; static const char kUseDefaultVideoCodec[]; + static const char kVP9Profile0Specifier[]; + static const char kVP9Profile2Specifier[]; + static const char kUndefined[]; enum class StreamArgumentType { @@ -204,12 +207,14 @@ // Change the default audio/video codec in the offer SDP. void SetDefaultAudioCodec(content::WebContents* tab, const std::string& audio_codec) const; - // |prefer_hw_codec| controls what codec with name |video_codec| should be - // selected. This parameter only matters if there are multiple codecs with the - // same name, which can be the case for H264. + // |prefer_hw_codec| controls what codec with name |video_codec| (and with + // profile |profile| if given)should be selected. This parameter only matters + // if there are multiple codecs with the same name, which can be the case for + // H264. void SetDefaultVideoCodec(content::WebContents* tab, const std::string& video_codec, - bool prefer_hw_codec = false) const; + bool prefer_hw_codec = false, + const std::string& profile = std::string()) const; // Add 'usedtx=1' to the offer SDP. void EnableOpusDtx(content::WebContents* tab) const;
diff --git a/chrome/browser/media/webrtc/webrtc_internals_perf_browsertest.cc b/chrome/browser/media/webrtc/webrtc_internals_perf_browsertest.cc index 9f8b40a..964eb451 100644 --- a/chrome/browser/media/webrtc/webrtc_internals_perf_browsertest.cc +++ b/chrome/browser/media/webrtc/webrtc_internals_perf_browsertest.cc
@@ -115,7 +115,8 @@ void RunsAudioVideoCall60SecsAndLogsInternalMetrics( const std::string& video_codec, - bool prefer_hw_video_codec) { + bool prefer_hw_video_codec = false, + const std::string& video_codec_profile = std::string()) { ASSERT_TRUE(test::HasReferenceFilesInCheckout()); ASSERT_TRUE(embedded_test_server()->Start()); @@ -229,16 +230,14 @@ WebRtcInternalsPerfBrowserTest, MANUAL_RunsAudioVideoCall60SecsAndLogsInternalMetricsVp8) { base::ScopedAllowBlockingForTesting allow_blocking; - RunsAudioVideoCall60SecsAndLogsInternalMetrics( - "VP8", false /* prefer_hw_video_codec */); + RunsAudioVideoCall60SecsAndLogsInternalMetrics("VP8"); } IN_PROC_BROWSER_TEST_F( WebRtcInternalsPerfBrowserTest, MANUAL_RunsAudioVideoCall60SecsAndLogsInternalMetricsVp9) { base::ScopedAllowBlockingForTesting allow_blocking; - RunsAudioVideoCall60SecsAndLogsInternalMetrics( - "VP9", false /* prefer_hw_video_codec */); + RunsAudioVideoCall60SecsAndLogsInternalMetrics("VP9"); } #if BUILDFLAG(RTC_USE_H264) @@ -249,10 +248,11 @@ base::ScopedAllowBlockingForTesting allow_blocking; // Only run test if run-time feature corresponding to |rtc_use_h264| is on. if (!base::FeatureList::IsEnabled(content::kWebRtcH264WithOpenH264FFmpeg)) { - LOG(WARNING) << "Run-time feature WebRTC-H264WithOpenH264FFmpeg disabled. " - "Skipping WebRtcInternalsPerfBrowserTest." - "MANUAL_RunsAudioVideoCall60SecsAndLogsInternalMetricsH264 (test " - "\"OK\")"; + LOG(WARNING) + << "Run-time feature WebRTC-H264WithOpenH264FFmpeg disabled. " + "Skipping WebRtcInternalsPerfBrowserTest." + "MANUAL_RunsAudioVideoCall60SecsAndLogsInternalMetricsH264 (test " + "\"OK\")"; return; } RunsAudioVideoCall60SecsAndLogsInternalMetrics(
diff --git a/chrome/browser/media/webrtc/webrtc_stats_perf_browsertest.cc b/chrome/browser/media/webrtc/webrtc_stats_perf_browsertest.cc index 5fbf326..aaeca1a 100644 --- a/chrome/browser/media/webrtc/webrtc_stats_perf_browsertest.cc +++ b/chrome/browser/media/webrtc/webrtc_stats_perf_browsertest.cc
@@ -89,7 +89,8 @@ void StartCall(const std::string& audio_codec, const std::string& video_codec, - bool prefer_hw_video_codec) { + bool prefer_hw_video_codec, + const std::string& video_codec_profile) { ASSERT_TRUE(test::HasReferenceFilesInCheckout()); ASSERT_TRUE(embedded_test_server()->Start()); @@ -104,8 +105,10 @@ SetupPeerconnectionWithLocalStream(right_tab_); SetDefaultAudioCodec(left_tab_, audio_codec); SetDefaultAudioCodec(right_tab_, audio_codec); - SetDefaultVideoCodec(left_tab_, video_codec, prefer_hw_video_codec); - SetDefaultVideoCodec(right_tab_, video_codec, prefer_hw_video_codec); + SetDefaultVideoCodec(left_tab_, video_codec, prefer_hw_video_codec, + video_codec_profile); + SetDefaultVideoCodec(right_tab_, video_codec, prefer_hw_video_codec, + video_codec_profile); CreateDataChannel(left_tab_, "data"); CreateDataChannel(right_tab_, "data"); NegotiateCall(left_tab_, right_tab_); @@ -125,20 +128,26 @@ void RunsAudioAndVideoCallCollectingMetricsWithAudioCodec( const std::string& audio_codec) { RunsAudioAndVideoCallCollectingMetrics(audio_codec, kUseDefaultVideoCodec, - false /* prefer_hw_video_codec */); + false /* prefer_hw_video_codec */, + ""); } void RunsAudioAndVideoCallCollectingMetricsWithVideoCodec( const std::string& video_codec, - bool prefer_hw_video_codec) { + bool prefer_hw_video_codec = false, + const std::string& video_codec_profile = std::string()) { RunsAudioAndVideoCallCollectingMetrics(kUseDefaultAudioCodec, video_codec, - prefer_hw_video_codec); + prefer_hw_video_codec, + video_codec_profile); } - void RunsAudioAndVideoCallCollectingMetrics(const std::string& audio_codec, - const std::string& video_codec, - bool prefer_hw_video_codec) { - StartCall(audio_codec, video_codec, prefer_hw_video_codec); + void RunsAudioAndVideoCallCollectingMetrics( + const std::string& audio_codec, + const std::string& video_codec, + bool prefer_hw_video_codec, + const std::string& video_codec_profile) { + StartCall(audio_codec, video_codec, prefer_hw_video_codec, + video_codec_profile); // Call for 60 seconds so that values may stabilize, bandwidth ramp up, etc. test::SleepInJavascript(left_tab_, 60000); @@ -215,7 +224,7 @@ EXPECT_TRUE(base::TimeTicks::IsHighResolution()); StartCall(kUseDefaultAudioCodec, kUseDefaultVideoCodec, - false /* prefer_hw_video_codec */); + false /* prefer_hw_video_codec */, ""); double invocation_time = 0.0; switch (variation) { @@ -285,16 +294,14 @@ WebRtcStatsPerfBrowserTest, MANUAL_RunsAudioAndVideoCallCollectingMetrics_VideoCodec_VP8) { base::ScopedAllowBlockingForTesting allow_blocking; - RunsAudioAndVideoCallCollectingMetricsWithVideoCodec( - "VP8", false /* prefer_hw_video_codec */); + RunsAudioAndVideoCallCollectingMetricsWithVideoCodec("VP8"); } IN_PROC_BROWSER_TEST_F( WebRtcStatsPerfBrowserTest, MANUAL_RunsAudioAndVideoCallCollectingMetrics_VideoCodec_VP9) { base::ScopedAllowBlockingForTesting allow_blocking; - RunsAudioAndVideoCallCollectingMetricsWithVideoCodec( - "VP9", false /* prefer_hw_video_codec */); + RunsAudioAndVideoCallCollectingMetricsWithVideoCodec("VP9"); } #if BUILDFLAG(RTC_USE_H264) @@ -306,9 +313,10 @@ // Only run test if run-time feature corresponding to |rtc_use_h264| is on. if (!base::FeatureList::IsEnabled(content::kWebRtcH264WithOpenH264FFmpeg)) { LOG(WARNING) << "Run-time feature WebRTC-H264WithOpenH264FFmpeg disabled. " - "Skipping WebRtcPerfBrowserTest." - "MANUAL_RunsAudioAndVideoCallCollectingMetrics_VideoCodec_H264 (test " - "\"OK\")"; + "Skipping WebRtcPerfBrowserTest." + "MANUAL_RunsAudioAndVideoCallCollectingMetrics_VideoCodec_" + "H264 (test " + "\"OK\")"; return; } RunsAudioAndVideoCallCollectingMetricsWithVideoCodec(
diff --git a/chrome/browser/net/network_quality_estimator_prefs_browsertest.cc b/chrome/browser/net/network_quality_estimator_prefs_browsertest.cc index 4b14752..3194854c 100644 --- a/chrome/browser/net/network_quality_estimator_prefs_browsertest.cc +++ b/chrome/browser/net/network_quality_estimator_prefs_browsertest.cc
@@ -5,6 +5,7 @@ #include <string> #include "base/command_line.h" +#include "base/deferred_sequenced_task_runner.h" #include "base/files/file_path.h" #include "base/logging.h" #include "base/macros.h" @@ -50,7 +51,8 @@ namespace { -void SimulateNetworkQualityChangeOnIO(net::EffectiveConnectionType type) { +void SimulateNetworkQualityChangeOnNetworkThread( + net::EffectiveConnectionType type) { network::NetworkService::GetNetworkServiceForTesting() ->network_quality_estimator() ->SimulateNetworkQualityChangeForTesting(type); @@ -150,9 +152,9 @@ void SimulateNetworkQualityChange(net::EffectiveConnectionType type) { DCHECK(network_service_enabled_); if (!content::IsOutOfProcessNetworkService()) { - base::PostTaskWithTraits( - FROM_HERE, {content::BrowserThread::IO}, - base::BindOnce(&SimulateNetworkQualityChangeOnIO, type)); + content::GetNetworkTaskRunner()->PostTask( + FROM_HERE, + base::BindOnce(&SimulateNetworkQualityChangeOnNetworkThread, type)); return; }
diff --git a/chrome/browser/net/network_quality_tracker_browsertest.cc b/chrome/browser/net/network_quality_tracker_browsertest.cc index d7d6fa9..c37b8264 100644 --- a/chrome/browser/net/network_quality_tracker_browsertest.cc +++ b/chrome/browser/net/network_quality_tracker_browsertest.cc
@@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include "base/deferred_sequenced_task_runner.h" #include "base/logging.h" #include "base/macros.h" #include "base/run_loop.h" @@ -37,8 +38,10 @@ // Simulates a network quality change. This is only called when network service // is running in the browser process, in which case, the network quality -// estimator lives on the browser IO thread. -void SimulateNetworkQualityChangeOnIO(net::EffectiveConnectionType type) { +// estimator lives on the network thread (which will be the IO thread if network +// service is disabled). +void SimulateNetworkQualityChangeOnNetworkThread( + net::EffectiveConnectionType type) { if (content::IsInProcessNetworkService()) { network::NetworkService::GetNetworkServiceForTesting() ->network_quality_estimator() @@ -129,9 +132,14 @@ // Simulates a network quality change. void SimulateNetworkQualityChange(net::EffectiveConnectionType type) { if (!content::IsOutOfProcessNetworkService()) { - base::PostTaskWithTraits( - FROM_HERE, {content::BrowserThread::IO}, - base::BindOnce(&SimulateNetworkQualityChangeOnIO, type)); + scoped_refptr<base::SequencedTaskRunner> task_runner = + base::CreateSequencedTaskRunnerWithTraits( + {content::BrowserThread::IO}); + if (content::IsInProcessNetworkService()) + task_runner = content::GetNetworkTaskRunner(); + task_runner->PostTask( + FROM_HERE, + base::BindOnce(&SimulateNetworkQualityChangeOnNetworkThread, type)); return; }
diff --git a/chrome/browser/page_load_metrics/observers/core_page_load_metrics_observer.cc b/chrome/browser/page_load_metrics/observers/core_page_load_metrics_observer.cc index 12a8aa94..c881278e 100644 --- a/chrome/browser/page_load_metrics/observers/core_page_load_metrics_observer.cc +++ b/chrome/browser/page_load_metrics/observers/core_page_load_metrics_observer.cc
@@ -763,22 +763,19 @@ } } -void CorePageLoadMetricsObserver::OnLoadedResource( - const page_load_metrics::ExtraRequestCompleteInfo& - extra_request_complete_info) { - if (extra_request_complete_info.was_cached) { - ++num_cache_resources_; - cache_bytes_ += extra_request_complete_info.raw_body_bytes; - } else { - ++num_network_resources_; - network_bytes_ += extra_request_complete_info.raw_body_bytes; - } -} - void CorePageLoadMetricsObserver::OnResourceDataUseObserved( const std::vector<page_load_metrics::mojom::ResourceDataUpdatePtr>& resources) { for (auto const& resource : resources) { + if (resource->is_complete) { + if (!resource->was_fetched_via_cache) { + network_bytes_ += resource->encoded_body_length; + num_network_resources_++; + } else { + cache_bytes_ += resource->encoded_body_length; + num_cache_resources_++; + } + } network_bytes_including_headers_ += resource->delta_bytes; } }
diff --git a/chrome/browser/page_load_metrics/observers/core_page_load_metrics_observer.h b/chrome/browser/page_load_metrics/observers/core_page_load_metrics_observer.h index bae38aea..6049ba6 100644 --- a/chrome/browser/page_load_metrics/observers/core_page_load_metrics_observer.h +++ b/chrome/browser/page_load_metrics/observers/core_page_load_metrics_observer.h
@@ -210,8 +210,6 @@ const page_load_metrics::mojom::PageLoadTiming& timing, const page_load_metrics::PageLoadExtraInfo& info) override; void OnUserInput(const blink::WebInputEvent& event) override; - void OnLoadedResource(const page_load_metrics::ExtraRequestCompleteInfo& - extra_request_complete_info) override; void OnResourceDataUseObserved( const std::vector<page_load_metrics::mojom::ResourceDataUpdatePtr>& resources) override; @@ -243,9 +241,7 @@ ui::PageTransition transition_; bool was_no_store_main_resource_; - // Note: these are only approximations, based on WebContents attribution from - // ResourceRequestInfo objects while this is the currently committed load in - // the WebContents. + // Number of complete resources loaded by the page. int num_cache_resources_; int num_network_resources_;
diff --git a/chrome/browser/page_load_metrics/observers/core_page_load_metrics_observer_unittest.cc b/chrome/browser/page_load_metrics/observers/core_page_load_metrics_observer_unittest.cc index 9bcd815c..de87e64 100644 --- a/chrome/browser/page_load_metrics/observers/core_page_load_metrics_observer_unittest.cc +++ b/chrome/browser/page_load_metrics/observers/core_page_load_metrics_observer_unittest.cc
@@ -364,40 +364,17 @@ NavigateWithPageTransitionAndCommit(url, ui::PAGE_TRANSITION_RELOAD); SimulateTimingUpdate(timing); - page_load_metrics::ExtraRequestCompleteInfo resources[] = { - // Cached request. - - {GURL(kResourceUrl), - net::HostPortPair(), - -1 /* frame_tree_node_id */, - true /*was_cached*/, - 1024 * 20 /* raw_body_bytes */, - 0 /* original_network_content_length */, - nullptr /* data_reduction_proxy_data */, - content::ResourceType::RESOURCE_TYPE_SCRIPT, - 0, - {} /* load_timing_info */}, - // Uncached non-proxied request. - {GURL(kResourceUrl), - net::HostPortPair(), - -1 /* frame_tree_node_id */, - false /*was_cached*/, - 1024 * 40 /* raw_body_bytes */, - 1024 * 40 /* original_network_content_length */, - nullptr /* data_reduction_proxy_data */, - content::ResourceType::RESOURCE_TYPE_SCRIPT, - 0, - {} /* load_timing_info */}, - }; - + auto resources = + GetSampleResourceDataUpdateForTesting(10 * 1024 /* resource_size */); + SimulateResourceDataUseUpdate(resources); int64_t network_bytes = 0; int64_t cache_bytes = 0; - for (const auto& request : resources) { - SimulateLoadedResource(request); - if (!request.was_cached) { - network_bytes += request.raw_body_bytes; - } else { - cache_bytes += request.raw_body_bytes; + for (const auto& resource : resources) { + if (resource->is_complete) { + if (!resource->was_fetched_via_cache) + network_bytes += resource->encoded_body_length; + else + cache_bytes += resource->encoded_body_length; } } @@ -466,39 +443,17 @@ ui::PAGE_TRANSITION_FORWARD_BACK)); SimulateTimingUpdate(timing); - page_load_metrics::ExtraRequestCompleteInfo resources[] = { - // Cached request. - {GURL(kResourceUrl), - net::HostPortPair(), - -1 /* frame_tree_node_id */, - true /*was_cached*/, - 1024 * 20 /* raw_body_bytes */, - 0 /* original_network_content_length */, - nullptr /* data_reduction_proxy_data */, - content::ResourceType::RESOURCE_TYPE_SCRIPT, - 0, - {} /* load_timing_info */}, - // Uncached non-proxied request. - {GURL(kResourceUrl), - net::HostPortPair(), - -1 /* frame_tree_node_id */, - false /*was_cached*/, - 1024 * 40 /* raw_body_bytes */, - 1024 * 40 /* original_network_content_length */, - nullptr /* data_reduction_proxy_data */, - content::ResourceType::RESOURCE_TYPE_SCRIPT, - 0, - {} /* load_timing_info */}, - }; - + auto resources = + GetSampleResourceDataUpdateForTesting(10 * 1024 /* resource_size */); + SimulateResourceDataUseUpdate(resources); int64_t network_bytes = 0; int64_t cache_bytes = 0; - for (const auto& request : resources) { - SimulateLoadedResource(request); - if (!request.was_cached) { - network_bytes += request.raw_body_bytes; - } else { - cache_bytes += request.raw_body_bytes; + for (const auto& resource : resources) { + if (resource->is_complete) { + if (!resource->was_fetched_via_cache) + network_bytes += resource->encoded_body_length; + else + cache_bytes += resource->encoded_body_length; } } @@ -561,39 +516,17 @@ NavigateWithPageTransitionAndCommit(url, ui::PAGE_TRANSITION_LINK); SimulateTimingUpdate(timing); - page_load_metrics::ExtraRequestCompleteInfo resources[] = { - // Cached request. - {GURL(kResourceUrl), - net::HostPortPair(), - -1 /* frame_tree_node_id */, - true /*was_cached*/, - 1024 * 20 /* raw_body_bytes */, - 0 /* original_network_content_length */, - nullptr /* data_reduction_proxy_data */, - content::ResourceType::RESOURCE_TYPE_SCRIPT, - 0, - {} /* load_timing_info */}, - // Uncached non-proxied request. - {GURL(kResourceUrl), - net::HostPortPair(), - -1 /* frame_tree_node_id */, - false /*was_cached*/, - 1024 * 40 /* raw_body_bytes */, - 1024 * 40 /* original_network_content_length */, - nullptr /* data_reduction_proxy_data */, - content::ResourceType::RESOURCE_TYPE_SCRIPT, - 0, - {} /* load_timing_info */}, - }; - + auto resources = + GetSampleResourceDataUpdateForTesting(10 * 1024 /* resource_size */); + SimulateResourceDataUseUpdate(resources); int64_t network_bytes = 0; int64_t cache_bytes = 0; - for (const auto& request : resources) { - SimulateLoadedResource(request); - if (!request.was_cached) { - network_bytes += request.raw_body_bytes; - } else { - cache_bytes += request.raw_body_bytes; + for (const auto& resource : resources) { + if (resource->is_complete) { + if (!resource->was_fetched_via_cache) + network_bytes += resource->encoded_body_length; + else + cache_bytes += resource->encoded_body_length; } } @@ -653,6 +586,8 @@ histogram_tester().ExpectTotalCount(internal::kHistogramPageLoadCacheBytes, 1); histogram_tester().ExpectTotalCount( + internal::kHistogramPageLoadNetworkBytesIncludingHeaders, 1); + histogram_tester().ExpectTotalCount( internal::kHistogramTotalCompletedResources, 1); histogram_tester().ExpectTotalCount( internal::kHistogramNetworkCompletedResources, 1);
diff --git a/chrome/browser/page_load_metrics/observers/media_page_load_metrics_observer.cc b/chrome/browser/page_load_metrics/observers/media_page_load_metrics_observer.cc index 399cf51..f2d519f3 100644 --- a/chrome/browser/page_load_metrics/observers/media_page_load_metrics_observer.cc +++ b/chrome/browser/page_load_metrics/observers/media_page_load_metrics_observer.cc
@@ -23,13 +23,16 @@ MediaPageLoadMetricsObserver::~MediaPageLoadMetricsObserver() = default; -void MediaPageLoadMetricsObserver::OnLoadedResource( - const page_load_metrics::ExtraRequestCompleteInfo& - extra_request_complete_info) { - if (extra_request_complete_info.was_cached) { - cache_bytes_ += extra_request_complete_info.raw_body_bytes; - } else { - network_bytes_ += extra_request_complete_info.raw_body_bytes; +void MediaPageLoadMetricsObserver::OnResourceDataUseObserved( + const std::vector<page_load_metrics::mojom::ResourceDataUpdatePtr>& + resources) { + for (auto const& resource : resources) { + if (resource->is_complete) { + if (!resource->was_fetched_via_cache) + network_bytes_ += resource->encoded_body_length; + else + cache_bytes_ += resource->encoded_body_length; + } } }
diff --git a/chrome/browser/page_load_metrics/observers/media_page_load_metrics_observer.h b/chrome/browser/page_load_metrics/observers/media_page_load_metrics_observer.h index 8e40af5f..9f6b4d5 100644 --- a/chrome/browser/page_load_metrics/observers/media_page_load_metrics_observer.h +++ b/chrome/browser/page_load_metrics/observers/media_page_load_metrics_observer.h
@@ -26,8 +26,9 @@ FlushMetricsOnAppEnterBackground( const page_load_metrics::mojom::PageLoadTiming& timing, const page_load_metrics::PageLoadExtraInfo& info) override; - void OnLoadedResource(const page_load_metrics::ExtraRequestCompleteInfo& - extra_request_complete_info) override; + void OnResourceDataUseObserved( + const std::vector<page_load_metrics::mojom::ResourceDataUpdatePtr>& + resources) override; void MediaStartedPlaying( const content::WebContentsObserver::MediaPlayerInfo& video_type, bool is_in_main_frame) override;
diff --git a/chrome/browser/page_load_metrics/observers/media_page_load_metrics_observer_unittest.cc b/chrome/browser/page_load_metrics/observers/media_page_load_metrics_observer_unittest.cc index 7080036..4bf8bda 100644 --- a/chrome/browser/page_load_metrics/observers/media_page_load_metrics_observer_unittest.cc +++ b/chrome/browser/page_load_metrics/observers/media_page_load_metrics_observer_unittest.cc
@@ -12,6 +12,7 @@ #include "chrome/browser/page_load_metrics/observers/page_load_metrics_observer_test_harness.h" #include "chrome/browser/page_load_metrics/page_load_metrics_observer.h" #include "chrome/browser/page_load_metrics/page_load_tracker.h" +#include "chrome/common/page_load_metrics/page_load_metrics.mojom.h" #include "chrome/common/page_load_metrics/page_load_timing.h" #include "chrome/common/page_load_metrics/test/page_load_metrics_test_util.h" #include "third_party/blink/public/platform/web_loading_behavior_flag.h" @@ -54,44 +55,15 @@ SimulateTimingUpdate(timing_); - // Prepare 4 resources of varying size and configurations. - page_load_metrics::ExtraRequestCompleteInfo resources[] = { - // Cached request. - {GURL(kResourceUrl), net::HostPortPair(), -1 /* frame_tree_node_id */, - true /*was_cached*/, 1024 * 40 /* raw_body_bytes */, - 0 /* original_network_content_length */, - nullptr /* data_reduction_proxy_data */, - content::ResourceType::RESOURCE_TYPE_SCRIPT, 0, - nullptr /* load_timing_info */}, - // Uncached non-proxied request. - {GURL(kResourceUrl), net::HostPortPair(), -1 /* frame_tree_node_id */, - false /*was_cached*/, 1024 * 40 /* raw_body_bytes */, - 1024 * 40 /* original_network_content_length */, - nullptr /* data_reduction_proxy_data */, - content::ResourceType::RESOURCE_TYPE_SCRIPT, 0, - nullptr /* load_timing_info */}, - // Uncached proxied request with .1 compression ratio. - {GURL(kResourceUrl), net::HostPortPair(), -1 /* frame_tree_node_id */, - false /*was_cached*/, 1024 * 40 /* raw_body_bytes */, - 1024 * 40 /* original_network_content_length */, - nullptr /* data_reduction_proxy_data */, - content::ResourceType::RESOURCE_TYPE_SCRIPT, 0, - nullptr /* load_timing_info */}, - // Uncached proxied request with .5 compression ratio. - {GURL(kResourceUrl), net::HostPortPair(), -1 /* frame_tree_node_id */, - false /*was_cached*/, 1024 * 40 /* raw_body_bytes */, - 1024 * 40 /* original_network_content_length */, - nullptr /* data_reduction_proxy_data */, - content::ResourceType::RESOURCE_TYPE_SCRIPT, 0, - nullptr /* load_timing_info */}, - }; - - for (const auto& request : resources) { - SimulateLoadedResource(request); - if (!request.was_cached) { - network_bytes_ += request.raw_body_bytes; - } else { - cache_bytes_ += request.raw_body_bytes; + auto resources = + GetSampleResourceDataUpdateForTesting(10 * 1024 /* resource_size */); + SimulateResourceDataUseUpdate(resources); + for (const auto& resource : resources) { + if (resource->is_complete) { + if (!resource->was_fetched_via_cache) + network_bytes_ += resource->encoded_body_length; + else + cache_bytes_ += resource->encoded_body_length; } }
diff --git a/chrome/browser/page_load_metrics/observers/previews_page_load_metrics_observer.cc b/chrome/browser/page_load_metrics/observers/previews_page_load_metrics_observer.cc index 79c607a..3281df9 100644 --- a/chrome/browser/page_load_metrics/observers/previews_page_load_metrics_observer.cc +++ b/chrome/browser/page_load_metrics/observers/previews_page_load_metrics_observer.cc
@@ -56,7 +56,8 @@ num_network_resources); // Match PAGE_BYTES_HISTOGRAM params: base::UmaHistogramCustomCounts( - GetHistogramNamePrefix(previews_type) + "Experimental.Bytes.Network", + GetHistogramNamePrefix(previews_type) + + "Experimental.Bytes.NetworkIncludingHeaders", static_cast<int>((network_bytes) / 1024), 1, 500 * 1024, 50); } @@ -173,16 +174,6 @@ WriteToSavings(info.url, total_saved_bytes); } -void PreviewsPageLoadMetricsObserver::OnLoadedResource( - const page_load_metrics::ExtraRequestCompleteInfo& - extra_request_complete_info) { - if (extra_request_complete_info.was_cached) - return; - - num_network_resources_++; - network_bytes_ += extra_request_complete_info.raw_body_bytes; -} - void PreviewsPageLoadMetricsObserver::OnComplete( const page_load_metrics::mojom::PageLoadTiming& timing, const page_load_metrics::PageLoadExtraInfo& info) { @@ -192,7 +183,7 @@ void PreviewsPageLoadMetricsObserver::RecordPageSizeUMA() const { RecordPageSizeHistograms(previews_type_, num_network_resources_, - network_bytes_); + total_network_bytes_); } void PreviewsPageLoadMetricsObserver::RecordTimingMetrics( @@ -232,6 +223,9 @@ const std::vector<page_load_metrics::mojom::ResourceDataUpdatePtr>& resources) { for (auto const& resource : resources) { + if (!resource->was_fetched_via_cache && resource->is_complete) { + num_network_resources_++; + } total_network_bytes_ += resource->delta_bytes; } }
diff --git a/chrome/browser/page_load_metrics/observers/previews_page_load_metrics_observer.h b/chrome/browser/page_load_metrics/observers/previews_page_load_metrics_observer.h index b02dca7..02470b7 100644 --- a/chrome/browser/page_load_metrics/observers/previews_page_load_metrics_observer.h +++ b/chrome/browser/page_load_metrics/observers/previews_page_load_metrics_observer.h
@@ -34,8 +34,6 @@ ObservePolicy FlushMetricsOnAppEnterBackground( const page_load_metrics::mojom::PageLoadTiming& timing, const page_load_metrics::PageLoadExtraInfo& info) override; - void OnLoadedResource(const page_load_metrics::ExtraRequestCompleteInfo& - extra_request_complete_info) override; void OnComplete(const page_load_metrics::mojom::PageLoadTiming& timing, const page_load_metrics::PageLoadExtraInfo& info) override; void OnLoadEventStart( @@ -71,7 +69,6 @@ int data_savings_inflation_percent_ = 0; int64_t num_network_resources_ = 0; - int64_t network_bytes_ = 0; DISALLOW_COPY_AND_ASSIGN(PreviewsPageLoadMetricsObserver); };
diff --git a/chrome/browser/page_load_metrics/observers/previews_page_load_metrics_observer_unittest.cc b/chrome/browser/page_load_metrics/observers/previews_page_load_metrics_observer_unittest.cc index 1bc238e..00e0405 100644 --- a/chrome/browser/page_load_metrics/observers/previews_page_load_metrics_observer_unittest.cc +++ b/chrome/browser/page_load_metrics/observers/previews_page_load_metrics_observer_unittest.cc
@@ -146,17 +146,17 @@ network_resources, 1); histogram_tester().ExpectUniqueSample( "PageLoad.Clients." + preview_type_name + - ".Experimental.Bytes.Network", + ".Experimental.Bytes.NetworkIncludingHeaders", static_cast<int>(network_bytes / 1024), 1); } else { histogram_tester().ExpectTotalCount( "PageLoad.Clients." + preview_type_name + ".Experimental.CompletedResources.Network", 0); - histogram_tester().ExpectTotalCount("PageLoad.Clients." + - preview_type_name + - ".Experimental.Bytes.Network", - 0); + histogram_tester().ExpectTotalCount( + "PageLoad.Clients." + preview_type_name + + ".Experimental.Bytes.NetworkIncludingHeaders", + 0); } } @@ -192,26 +192,11 @@ previews::features::kNoScriptPreviews); ResetTest(); - content::GlobalRequestID request_id = - NavigateAndCommitWithPreviewsState(content::PREVIEWS_OFF); + NavigateAndCommitWithPreviewsState(content::PREVIEWS_OFF); - page_load_metrics::ExtraRequestCompleteInfo main_frame_info( - GURL(kResourceUrl), net::HostPortPair(), -1 /* frame_tree_node_id */, - false, /* cached */ - 5 * 1024 /* size */, 0 /* original_network_content_length */, - nullptr - /* data_reduction_proxy_data */, - content::RESOURCE_TYPE_MAIN_FRAME, 0, nullptr /* load_timing_info */); - SimulateLoadedResource(main_frame_info, request_id); - - page_load_metrics::ExtraRequestCompleteInfo network_resource_info( - GURL(kResourceUrl), net::HostPortPair(), -1 /* frame_tree_node_id */, - false, /* cached */ - 20 * 1024 /* size */, 0 /* original_network_content_length */, - nullptr - /* data_reduction_proxy_data */, - content::RESOURCE_TYPE_IMAGE, 0, nullptr /* load_timing_info */); - SimulateLoadedResource(network_resource_info); + auto resources = + GetSampleResourceDataUpdateForTesting(10 * 1024 /* resource_size */); + SimulateResourceDataUseUpdate(resources); SimulateTimingUpdate(timing_); NavigateToUntrackedUrl(); @@ -231,42 +216,18 @@ previews::features::kNoScriptPreviews); ResetTest(); - content::GlobalRequestID request_id = - NavigateAndCommitWithPreviewsState(content::NOSCRIPT_ON); + NavigateAndCommitWithPreviewsState(content::NOSCRIPT_ON); - page_load_metrics::ExtraRequestCompleteInfo main_frame_info( - GURL(kResourceUrl), net::HostPortPair(), -1 /* frame_tree_node_id */, - false, /* cached */ - 5 * 1024 /* size */, 0 /* original_network_content_length */, - nullptr - /* data_reduction_proxy_data */, - content::RESOURCE_TYPE_MAIN_FRAME, 0, nullptr /* load_timing_info */); - SimulateLoadedResource(main_frame_info, request_id); - - page_load_metrics::ExtraRequestCompleteInfo cached_resource_info( - GURL(kResourceUrl), net::HostPortPair(), -1 /* frame_tree_node_id */, - true, /* cached */ - 13 * 1024 /* size */, 0 /* original_network_content_length */, - nullptr - /* data_reduction_proxy_data */, - content::RESOURCE_TYPE_IMAGE, 0, nullptr /* load_timing_info */); - SimulateLoadedResource(cached_resource_info); - - page_load_metrics::ExtraRequestCompleteInfo network_resource_info( - GURL(kResourceUrl), net::HostPortPair(), -1 /* frame_tree_node_id */, - false, /* cached */ - 20 * 1024 /* size */, 0 /* original_network_content_length */, - nullptr - /* data_reduction_proxy_data */, - content::RESOURCE_TYPE_IMAGE, 0, nullptr /* load_timing_info */); - SimulateLoadedResource(network_resource_info); + auto resources = + GetSampleResourceDataUpdateForTesting(10 * 1024 /* resource_size */); + SimulateResourceDataUseUpdate(resources); SimulateTimingUpdate(timing_); NavigateToUntrackedUrl(); ValidateTimingHistograms("NoScriptPreview", true /* preview_was_active */); - ValidateDataHistograms("NoScriptPreview", 2 /* network_resources */, - 25 * 1024 /* network_bytes */); + ValidateDataHistograms("NoScriptPreview", 1 /* network_resources */, + 20 * 1024 /* network_bytes */); } TEST_F(PreviewsPageLoadMetricsObserverTest, ResourceLoadingHintsPreviewActive) { @@ -275,35 +236,11 @@ previews::features::kResourceLoadingHints); ResetTest(); - content::GlobalRequestID request_id = - NavigateAndCommitWithPreviewsState(content::RESOURCE_LOADING_HINTS_ON); + NavigateAndCommitWithPreviewsState(content::RESOURCE_LOADING_HINTS_ON); - page_load_metrics::ExtraRequestCompleteInfo main_frame_info( - GURL(kResourceUrl), net::HostPortPair(), -1 /* frame_tree_node_id */, - false, /* cached */ - 5 * 1024 /* size */, 0 /* original_network_content_length */, - nullptr - /* data_reduction_proxy_data */, - content::RESOURCE_TYPE_MAIN_FRAME, 0, nullptr /* load_timing_info */); - SimulateLoadedResource(main_frame_info, request_id); - - page_load_metrics::ExtraRequestCompleteInfo cached_resource_info( - GURL(kResourceUrl), net::HostPortPair(), -1 /* frame_tree_node_id */, - true, /* cached */ - 13 * 1024 /* size */, 0 /* original_network_content_length */, - nullptr - /* data_reduction_proxy_data */, - content::RESOURCE_TYPE_IMAGE, 0, nullptr /* load_timing_info */); - SimulateLoadedResource(cached_resource_info); - - page_load_metrics::ExtraRequestCompleteInfo network_resource_info( - GURL(kResourceUrl), net::HostPortPair(), -1 /* frame_tree_node_id */, - false, /* cached */ - 20 * 1024 /* size */, 0 /* original_network_content_length */, - nullptr - /* data_reduction_proxy_data */, - content::RESOURCE_TYPE_IMAGE, 0, nullptr /* load_timing_info */); - SimulateLoadedResource(network_resource_info); + auto resources = + GetSampleResourceDataUpdateForTesting(10 * 1024 /* resource_size */); + SimulateResourceDataUseUpdate(resources); SimulateTimingUpdate(timing_); NavigateToUntrackedUrl(); @@ -311,8 +248,8 @@ ValidateTimingHistograms("ResourceLoadingHintsPreview", true /* preview_was_active */); ValidateDataHistograms("ResourceLoadingHintsPreview", - 2 /* network_resources */, - 25 * 1024 /* network_bytes */); + 1 /* network_resources */, + 20 * 1024 /* network_bytes */); } TEST_F(PreviewsPageLoadMetricsObserverTest, NoScriptDataSavings) {
diff --git a/chrome/browser/page_load_metrics/observers/tab_restore_page_load_metrics_observer.cc b/chrome/browser/page_load_metrics/observers/tab_restore_page_load_metrics_observer.cc index aab1a6a..9d32311c 100644 --- a/chrome/browser/page_load_metrics/observers/tab_restore_page_load_metrics_observer.cc +++ b/chrome/browser/page_load_metrics/observers/tab_restore_page_load_metrics_observer.cc
@@ -39,13 +39,16 @@ return IsTabRestore(navigation_handle) ? CONTINUE_OBSERVING : STOP_OBSERVING; } -void TabRestorePageLoadMetricsObserver::OnLoadedResource( - const page_load_metrics::ExtraRequestCompleteInfo& - extra_request_complete_info) { - if (extra_request_complete_info.was_cached) { - cache_bytes_ += extra_request_complete_info.raw_body_bytes; - } else { - network_bytes_ += extra_request_complete_info.raw_body_bytes; +void TabRestorePageLoadMetricsObserver::OnResourceDataUseObserved( + const std::vector<page_load_metrics::mojom::ResourceDataUpdatePtr>& + resources) { + for (auto const& resource : resources) { + if (resource->is_complete) { + if (!resource->was_fetched_via_cache) + network_bytes_ += resource->encoded_body_length; + else + cache_bytes_ += resource->encoded_body_length; + } } }
diff --git a/chrome/browser/page_load_metrics/observers/tab_restore_page_load_metrics_observer.h b/chrome/browser/page_load_metrics/observers/tab_restore_page_load_metrics_observer.h index 2955117..90e5186 100644 --- a/chrome/browser/page_load_metrics/observers/tab_restore_page_load_metrics_observer.h +++ b/chrome/browser/page_load_metrics/observers/tab_restore_page_load_metrics_observer.h
@@ -29,8 +29,9 @@ content::NavigationHandle* navigation_handle, const GURL& currently_committed_url, bool started_in_foreground) override; - void OnLoadedResource(const page_load_metrics::ExtraRequestCompleteInfo& - extra_request_complete_info) override; + void OnResourceDataUseObserved( + const std::vector<page_load_metrics::mojom::ResourceDataUpdatePtr>& + resources) override; page_load_metrics::PageLoadMetricsObserver::ObservePolicy FlushMetricsOnAppEnterBackground( const page_load_metrics::mojom::PageLoadTiming& timing,
diff --git a/chrome/browser/page_load_metrics/observers/tab_restore_page_load_metrics_observer_unittest.cc b/chrome/browser/page_load_metrics/observers/tab_restore_page_load_metrics_observer_unittest.cc index 0b66d51..03c6830c 100644 --- a/chrome/browser/page_load_metrics/observers/tab_restore_page_load_metrics_observer_unittest.cc +++ b/chrome/browser/page_load_metrics/observers/tab_restore_page_load_metrics_observer_unittest.cc
@@ -15,6 +15,7 @@ #include "chrome/browser/page_load_metrics/observers/page_load_metrics_observer_test_harness.h" #include "chrome/browser/page_load_metrics/page_load_metrics_observer.h" #include "chrome/browser/page_load_metrics/page_load_tracker.h" +#include "chrome/common/page_load_metrics/page_load_metrics.mojom.h" #include "chrome/common/page_load_metrics/page_load_timing.h" #include "chrome/common/page_load_metrics/test/page_load_metrics_test_util.h" #include "content/public/browser/restore_type.h" @@ -70,44 +71,14 @@ NavigateAndCommit(GURL(kDefaultTestUrl)); SimulateTimingUpdate(timing_); - // Prepare 4 resources of varying size and configurations. - page_load_metrics::ExtraRequestCompleteInfo resources[] = { - // Cached request. - {GURL(kResourceUrl), net::HostPortPair(), -1 /* frame_tree_node_id */, - true /*was_cached*/, 1024 * 40 /* raw_body_bytes */, - 0 /* original_network_content_length */, - nullptr /* data_reduction_proxy_data */, - content::ResourceType::RESOURCE_TYPE_SCRIPT, 0, - nullptr /* load_timing_info */}, - // Uncached non-proxied request. - {GURL(kResourceUrl), net::HostPortPair(), -1 /* frame_tree_node_id */, - false /*was_cached*/, 1024 * 40 /* raw_body_bytes */, - 1024 * 40 /* original_network_content_length */, - nullptr /* data_reduction_proxy_data */, - content::ResourceType::RESOURCE_TYPE_SCRIPT, 0, - nullptr /* load_timing_info */}, - // Uncached proxied request with .1 compression ratio. - {GURL(kResourceUrl), net::HostPortPair(), -1 /* frame_tree_node_id */, - false /*was_cached*/, 1024 * 40 /* raw_body_bytes */, - 1024 * 40 /* original_network_content_length */, - nullptr /* data_reduction_proxy_data */, - content::ResourceType::RESOURCE_TYPE_SCRIPT, 0, - nullptr /* load_timing_info */}, - // Uncached proxied request with .5 compression ratio. - {GURL(kResourceUrl), net::HostPortPair(), -1 /* frame_tree_node_id */, - false /*was_cached*/, 1024 * 40 /* raw_body_bytes */, - 1024 * 40 /* original_network_content_length */, - nullptr /* data_reduction_proxy_data */, - content::ResourceType::RESOURCE_TYPE_SCRIPT, 0, - nullptr /* load_timing_info */}, - }; - - for (const auto& request : resources) { - SimulateLoadedResource(request); - if (!request.was_cached) { - network_bytes_ += request.raw_body_bytes; - } else { - cache_bytes_ += request.raw_body_bytes; + auto resources = GetSampleResourceDataUpdateForTesting(10 * 1024); + SimulateResourceDataUseUpdate(resources); + for (const auto& resource : resources) { + if (resource->is_complete) { + if (!resource->was_fetched_via_cache) + network_bytes_ += resource->encoded_body_length; + else + cache_bytes_ += resource->encoded_body_length; } }
diff --git a/chrome/browser/prerender/prerender_manager.cc b/chrome/browser/prerender/prerender_manager.cc index 0bdf0a7..3e563a4 100644 --- a/chrome/browser/prerender/prerender_manager.cc +++ b/chrome/browser/prerender/prerender_manager.cc
@@ -45,7 +45,6 @@ #include "chrome/browser/tab_contents/tab_util.h" #include "chrome/browser/ui/browser_navigator_params.h" #include "chrome/browser/ui/tab_contents/core_tab_helper.h" -#include "chrome/browser/ui/tab_contents/core_tab_helper_delegate.h" #include "chrome/common/prerender_types.h" #include "components/content_settings/core/common/pref_names.h" #include "components/prefs/pref_service.h" @@ -351,10 +350,10 @@ DCHECK_CURRENTLY_ON(BrowserThread::UI); DCHECK(!IsWebContentsPrerendering(web_contents, nullptr)); - // Only swap if the target WebContents has a CoreTabHelper delegate to swap - // out of it. For a normal WebContents, this is if it is in a TabStripModel. + // Only swap if the target WebContents has a CoreTabHelper to swap out of it. + // For a normal WebContents, this is if it is in a TabStripModel. CoreTabHelper* core_tab_helper = CoreTabHelper::FromWebContents(web_contents); - if (!core_tab_helper || !core_tab_helper->delegate()) + if (!core_tab_helper) return nullptr; PrerenderTabHelper* target_tab_helper =
diff --git a/chrome/browser/renderer_context_menu/render_view_context_menu.cc b/chrome/browser/renderer_context_menu/render_view_context_menu.cc index 6482e62..b7ba32e 100644 --- a/chrome/browser/renderer_context_menu/render_view_context_menu.cc +++ b/chrome/browser/renderer_context_menu/render_view_context_menu.cc
@@ -56,6 +56,7 @@ #include "chrome/browser/translate/chrome_translate_client.h" #include "chrome/browser/translate/translate_service.h" #include "chrome/browser/ui/autofill/chrome_autofill_client.h" +#include "chrome/browser/ui/browser.h" #include "chrome/browser/ui/browser_commands.h" #include "chrome/browser/ui/browser_finder.h" #include "chrome/browser/ui/browser_navigator_params.h" @@ -2155,9 +2156,8 @@ if (!core_tab_helper) return false; - CoreTabHelperDelegate* core_delegate = core_tab_helper->delegate(); - return !core_delegate || - core_delegate->CanReloadContents(embedder_web_contents_); + Browser* browser = GetBrowser(); + return !browser || browser->CanReloadContents(embedder_web_contents_); } bool RenderViewContextMenu::IsViewSourceEnabled() const { @@ -2260,9 +2260,8 @@ if (!core_tab_helper) return false; - CoreTabHelperDelegate* core_delegate = core_tab_helper->delegate(); - if (core_delegate && - !core_delegate->CanSaveContents(embedder_web_contents_)) + Browser* browser = GetBrowser(); + if (browser && !browser->CanSaveContents(embedder_web_contents_)) return false; PrefService* local_state = g_browser_process->local_state();
diff --git a/chrome/browser/resource_coordinator/tab_load_tracker.h b/chrome/browser/resource_coordinator/tab_load_tracker.h index 659f203f..66c9f45 100644 --- a/chrome/browser/resource_coordinator/tab_load_tracker.h +++ b/chrome/browser/resource_coordinator/tab_load_tracker.h
@@ -111,7 +111,7 @@ void TransitionStateForTesting(content::WebContents* web_contents, LoadingState loading_state); - // Called from CoreTabHelperDelegates when |new_contents| is replacing + // Called from WebContentsDelegates when |new_contents| is replacing // |old_contents| in a tab. void SwapTabContents(content::WebContents* old_contents, content::WebContents* new_contents);
diff --git a/chrome/browser/resources/settings/about_page/detailed_build_info.html b/chrome/browser/resources/settings/about_page/detailed_build_info.html index c604d6d..dd300b5 100644 --- a/chrome/browser/resources/settings/about_page/detailed_build_info.html +++ b/chrome/browser/resources/settings/about_page/detailed_build_info.html
@@ -63,10 +63,6 @@ <div class="secondary" id="arcVersion">[[versionInfo_.arcVersion]]</div> </div> <div class="settings-box two-line single-column"> - <div>Blink</div><!-- No need to localize. --> - <div class="secondary">$i18n{aboutBlinkVersion}</div> - </div> - <div class="settings-box two-line single-column"> <div>V8</div> <div class="secondary">$i18n{aboutJsEngineVersion}</div> </div>
diff --git a/chrome/browser/resources/settings/autofill_page/payments_section.js b/chrome/browser/resources/settings/autofill_page/payments_section.js index 97c0897..068da8f 100644 --- a/chrome/browser/resources/settings/autofill_page/payments_section.js +++ b/chrome/browser/resources/settings/autofill_page/payments_section.js
@@ -46,6 +46,11 @@ * Migrate the local credit cards. */ migrateCreditCards() {} + + /** + * Logs that the server cards edit link was clicked. + */ + logServerCardLinkClicked() {} } /** @typedef {chrome.autofillPrivate.CreditCardEntry} */ @@ -90,6 +95,11 @@ migrateCreditCards() { chrome.autofillPrivate.migrateCreditCards(); } + + /** @override */ + logServerCardLinkClicked() { + chrome.autofillPrivate.logServerCardLinkClicked(); + } } cr.addSingletonGetter(PaymentsManagerImpl); @@ -343,6 +353,7 @@ /** @private */ onRemoteEditCreditCardTap_: function() { + this.paymentsManager_.logServerCardLinkClicked(); window.open(loadTimeData.getString('manageCreditCardsUrl')); },
diff --git a/chrome/browser/resources/settings/chrome_cleanup_page/chrome_cleanup_page.html b/chrome/browser/resources/settings/chrome_cleanup_page/chrome_cleanup_page.html index d29e40df3..58c03b7 100644 --- a/chrome/browser/resources/settings/chrome_cleanup_page/chrome_cleanup_page.html +++ b/chrome/browser/resources/settings/chrome_cleanup_page/chrome_cleanup_page.html
@@ -37,6 +37,7 @@ /* Used by |chromeCleanupPoweredByHTML| */ #powered-by-logo { + content: url(chrome://settings/partner-logo.svg); height: 22px; }
diff --git a/chrome/browser/ui/BUILD.gn b/chrome/browser/ui/BUILD.gn index b2813cb..98ce2928 100644 --- a/chrome/browser/ui/BUILD.gn +++ b/chrome/browser/ui/BUILD.gn
@@ -135,8 +135,6 @@ "login/login_interstitial_delegate.h", "navigation_correction_tab_observer.cc", "navigation_correction_tab_observer.h", - "omnibox/query_in_omnibox_factory.cc", - "omnibox/query_in_omnibox_factory.h", "page_info/page_info.cc", "page_info/page_info.h", "page_info/page_info_ui.cc", @@ -197,8 +195,6 @@ "tab_contents/chrome_web_contents_view_delegate.h", "tab_contents/core_tab_helper.cc", "tab_contents/core_tab_helper.h", - "tab_contents/core_tab_helper_delegate.cc", - "tab_contents/core_tab_helper_delegate.h", "tab_dialogs.cc", "tab_dialogs.h", "tab_helpers.cc",
diff --git a/chrome/browser/ui/android/autofill/card_name_fix_flow_view_android.cc b/chrome/browser/ui/android/autofill/card_name_fix_flow_view_android.cc index bb23ab8..ec29ba7 100644 --- a/chrome/browser/ui/android/autofill/card_name_fix_flow_view_android.cc +++ b/chrome/browser/ui/android/autofill/card_name_fix_flow_view_android.cc
@@ -47,6 +47,7 @@ Java_AutofillNameFixFlowBridge_show( env, java_object_, view_android->GetWindowAndroid()->GetJavaObject()); + delegate_->Shown(); } void CardNameFixFlowViewAndroid::OnUserAccept( @@ -60,6 +61,7 @@ void CardNameFixFlowViewAndroid::PromptDismissed( JNIEnv* env, const JavaParamRef<jobject>& obj) { + delegate_->Dismissed(); delete this; }
diff --git a/chrome/browser/ui/android/toolbar/location_bar_model_android.cc b/chrome/browser/ui/android/toolbar/location_bar_model_android.cc index 26d0559..e7300c12 100644 --- a/chrome/browser/ui/android/toolbar/location_bar_model_android.cc +++ b/chrome/browser/ui/android/toolbar/location_bar_model_android.cc
@@ -44,10 +44,14 @@ env, location_bar_model_->GetURLForDisplay()); } -jboolean LocationBarModelAndroid::IsSecurityInfoInitialized( +ScopedJavaLocalRef<jstring> LocationBarModelAndroid::GetDisplaySearchTerms( JNIEnv* env, - const base::android::JavaParamRef<jobject>& obj) { - return location_bar_model_->IsSecurityInfoInitialized(); + const JavaParamRef<jobject>& obj) { + base::string16 result; + if (!location_bar_model_->GetDisplaySearchTerms(&result)) + return nullptr; + + return base::android::ConvertUTF16ToJavaString(env, result); } content::WebContents* LocationBarModelAndroid::GetActiveWebContents() const {
diff --git a/chrome/browser/ui/android/toolbar/location_bar_model_android.h b/chrome/browser/ui/android/toolbar/location_bar_model_android.h index 096d813..bc7f538 100644 --- a/chrome/browser/ui/android/toolbar/location_bar_model_android.h +++ b/chrome/browser/ui/android/toolbar/location_bar_model_android.h
@@ -31,7 +31,7 @@ base::android::ScopedJavaLocalRef<jstring> GetURLForDisplay( JNIEnv* env, const base::android::JavaParamRef<jobject>& obj); - jboolean IsSecurityInfoInitialized( + base::android::ScopedJavaLocalRef<jstring> GetDisplaySearchTerms( JNIEnv* env, const base::android::JavaParamRef<jobject>& obj);
diff --git a/chrome/browser/ui/app_list/internal_app/internal_app_metadata.cc b/chrome/browser/ui/app_list/internal_app/internal_app_metadata.cc index 71ca4259..c6593bd6 100644 --- a/chrome/browser/ui/app_list/internal_app/internal_app_metadata.cc +++ b/chrome/browser/ui/app_list/internal_app/internal_app_metadata.cc
@@ -296,14 +296,16 @@ gfx::Size(resource_size_in_dip, resource_size_in_dip)); } -bool HasRecommendableForeignTab(Profile* profile, - base::string16* title, - GURL* url) { +bool HasRecommendableForeignTab( + Profile* profile, + base::string16* title, + GURL* url, + sync_sessions::OpenTabsUIDelegate* test_delegate) { sync_sessions::SessionSyncService* service = SessionSyncServiceFactory::GetForProfile(profile); std::vector<const sync_sessions::SyncedSession*> foreign_sessions; sync_sessions::OpenTabsUIDelegate* delegate = - service->GetOpenTabsUIDelegate(); + test_delegate ? test_delegate : service->GetOpenTabsUIDelegate(); if (delegate != nullptr) delegate->GetAllForeignSessions(&foreign_sessions);
diff --git a/chrome/browser/ui/app_list/internal_app/internal_app_metadata.h b/chrome/browser/ui/app_list/internal_app/internal_app_metadata.h index d537717..f866356 100644 --- a/chrome/browser/ui/app_list/internal_app/internal_app_metadata.h +++ b/chrome/browser/ui/app_list/internal_app/internal_app_metadata.h
@@ -13,6 +13,10 @@ class Profile; class GURL; +namespace sync_sessions { +class OpenTabsUIDelegate; +} // namespace sync_sessions + namespace app_list { // The internal app's histogram name of the chrome search result. This is used @@ -86,9 +90,12 @@ // tab's last navigation. // If |url| is not nullptr, it will be replaced with the url of the foreign // tab's last navigation. -bool HasRecommendableForeignTab(Profile* profile, - base::string16* title, - GURL* url); +// |test_delegate| is used to mock OpenTabsUIDelegate in test. +bool HasRecommendableForeignTab( + Profile* profile, + base::string16* title, + GURL* url, + sync_sessions::OpenTabsUIDelegate* test_delegate); // Returns the InternalAppName of an internal app. InternalAppName GetInternalAppNameByAppId(
diff --git a/chrome/browser/ui/app_list/search/app_search_provider.cc b/chrome/browser/ui/app_list/search/app_search_provider.cc index 1b684b4..b4a1756 100644 --- a/chrome/browser/ui/app_list/search/app_search_provider.cc +++ b/chrome/browser/ui/app_list/search/app_search_provider.cc
@@ -480,7 +480,8 @@ sync_sessions::SessionSyncService* service = SessionSyncServiceFactory::GetInstance()->GetForProfile(profile()); - if (!service || !service->GetOpenTabsUIDelegate()) { + if (!service || (!service->GetOpenTabsUIDelegate() && + !owner()->open_tabs_ui_delegate_for_testing())) { continue; } } else if (just_continue_reading_) { @@ -681,10 +682,12 @@ base::string16 title = app->name(); if (app->id() == kInternalAppIdContinueReading) { - if (HasRecommendableForeignTab(profile_, &title, nullptr)) + if (HasRecommendableForeignTab(profile_, &title, /*url=*/nullptr, + open_tabs_ui_delegate_for_testing())) { app->AddSearchableText(title); - else + } else { continue; + } } std::unique_ptr<AppResult> result =
diff --git a/chrome/browser/ui/app_list/search/app_search_provider.h b/chrome/browser/ui/app_list/search/app_search_provider.h index 224ff959..975da27 100644 --- a/chrome/browser/ui/app_list/search/app_search_provider.h +++ b/chrome/browser/ui/app_list/search/app_search_provider.h
@@ -23,6 +23,10 @@ class Clock; } +namespace sync_sessions { +class OpenTabsUIDelegate; +} // namespace sync_sessions + namespace app_list { class AppSearchResultRanker; @@ -55,6 +59,14 @@ // detected. void RefreshAppsAndUpdateResultsDeferred(); + void set_open_tabs_ui_delegate_for_testing( + sync_sessions::OpenTabsUIDelegate* delegate) { + open_tabs_ui_delegate_for_testing_ = delegate; + } + sync_sessions::OpenTabsUIDelegate* open_tabs_ui_delegate_for_testing() { + return open_tabs_ui_delegate_for_testing_; + } + private: void UpdateResults(); void UpdateRecommendedResults( @@ -69,6 +81,8 @@ base::Clock* clock_; std::vector<std::unique_ptr<DataSource>> data_sources_; std::unique_ptr<AppSearchResultRanker> ranker_; + sync_sessions::OpenTabsUIDelegate* open_tabs_ui_delegate_for_testing_ = + nullptr; base::WeakPtrFactory<AppSearchProvider> refresh_apps_factory_; base::WeakPtrFactory<AppSearchProvider> update_results_factory_;
diff --git a/chrome/browser/ui/app_list/search/internal_app_result.cc b/chrome/browser/ui/app_list/search/internal_app_result.cc index 9d4adfb..66ea2aa 100644 --- a/chrome/browser/ui/app_list/search/internal_app_result.cc +++ b/chrome/browser/ui/app_list/search/internal_app_result.cc
@@ -92,7 +92,8 @@ bool continue_to_google_server) { base::string16 title; GURL url; - if (HasRecommendableForeignTab(profile(), &title, &url)) { + if (HasRecommendableForeignTab(profile(), &title, &url, + /*test_delegate=*/nullptr)) { url_for_continuous_reading_ = url; // Foreign tab could be updated since the title was set the last time.
diff --git a/chrome/browser/ui/app_list/search/tests/app_search_provider_unittest.cc b/chrome/browser/ui/app_list/search/tests/app_search_provider_unittest.cc index 51b07588..373a6e54 100644 --- a/chrome/browser/ui/app_list/search/tests/app_search_provider_unittest.cc +++ b/chrome/browser/ui/app_list/search/tests/app_search_provider_unittest.cc
@@ -17,8 +17,10 @@ #include "base/strings/utf_string_conversions.h" #include "base/test/scoped_feature_list.h" #include "base/test/simple_test_clock.h" +#include "base/time/time.h" #include "chrome/browser/chromeos/crostini/crostini_test_helper.h" #include "chrome/browser/extensions/extension_service.h" +#include "chrome/browser/sync/session_sync_service_factory.h" #include "chrome/browser/ui/app_list/app_list_test_util.h" #include "chrome/browser/ui/app_list/arc/arc_app_item.h" #include "chrome/browser/ui/app_list/arc/arc_app_list_prefs.h" @@ -33,11 +35,20 @@ #include "chrome/test/base/testing_profile.h" #include "components/arc/test/fake_app_instance.h" #include "components/crx_file/id_util.h" +#include "components/sessions/core/serialized_navigation_entry_test_helper.h" +#include "components/sessions/core/session_id.h" #include "components/sync/model/string_ordinal.h" +#include "components/sync/protocol/sync_enums.pb.h" +#include "components/sync_sessions/mock_sync_sessions_client.h" +#include "components/sync_sessions/open_tabs_ui_delegate_impl.h" +#include "components/sync_sessions/session_sync_service.h" +#include "components/sync_sessions/synced_session.h" +#include "components/sync_sessions/synced_session_tracker.h" #include "extensions/browser/extension_prefs.h" #include "extensions/browser/uninstall_reason.h" #include "extensions/common/extension_builder.h" #include "extensions/common/extension_set.h" +#include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" namespace app_list { @@ -103,6 +114,21 @@ profile_.get(), nullptr, &clock_, model_updater_.get()); } + void CreateSearchWithContinueReading() { + clock_.SetNow(kTestCurrentTime); + app_search_ = std::make_unique<AppSearchProvider>( + profile_.get(), nullptr, &clock_, model_updater_.get()); + + session_tracker_ = std::make_unique<sync_sessions::SyncedSessionTracker>( + &mock_sync_sessions_client_); + open_tabs_ui_delegate_ = + std::make_unique<sync_sessions::OpenTabsUIDelegateImpl>( + &mock_sync_sessions_client_, session_tracker_.get(), + /*favicon_cache=*/nullptr, base::DoNothing()); + app_search_->set_open_tabs_ui_delegate_for_testing( + open_tabs_ui_delegate_.get()); + } + std::string RunQuery(const std::string& query) { app_search_->Start(base::UTF8ToUTF16(query)); @@ -180,6 +206,10 @@ // Train the |app_search| provider with id. void Train(const std::string& id) { app_search_->Train(id); } + sync_sessions::SyncedSessionTracker* session_tracker() { + return session_tracker_.get(); + } + private: base::SimpleTestClock clock_; std::unique_ptr<FakeAppListModelUpdater> model_updater_; @@ -187,6 +217,12 @@ std::unique_ptr<::test::TestAppListControllerDelegate> controller_; ArcAppTest arc_test_; + // For continue reading. + testing::NiceMock<sync_sessions::MockSyncSessionsClient> + mock_sync_sessions_client_; + std::unique_ptr<sync_sessions::SyncedSessionTracker> session_tracker_; + std::unique_ptr<sync_sessions::OpenTabsUIDelegateImpl> open_tabs_ui_delegate_; + DISALLOW_COPY_AND_ASSIGN(AppSearchProviderTest); }; @@ -319,6 +355,240 @@ RunQuery("")); } +TEST_F(AppSearchProviderTest, FetchRecommendationsWithContinueReading) { + base::test::ScopedFeatureList features; + features.InitAndEnableFeature(app_list_features::kEnableContinueReading); + + constexpr char kLocalSessionTag[] = "local"; + constexpr char kLocalSessionName[] = "LocalSessionName"; + constexpr char kForeignSessionTag1[] = "foreign1"; + constexpr char kForeignSessionTag2[] = "foreign2"; + constexpr char kForeignSessionTag3[] = "foreign3"; + constexpr SessionID kWindowId1 = SessionID::FromSerializedValue(1); + constexpr SessionID kWindowId2 = SessionID::FromSerializedValue(2); + constexpr SessionID kWindowId3 = SessionID::FromSerializedValue(3); + constexpr SessionID kTabId1 = SessionID::FromSerializedValue(111); + constexpr SessionID kTabId2 = SessionID::FromSerializedValue(222); + constexpr SessionID kTabId3 = SessionID::FromSerializedValue(333); + + // Case 1: test that ContinueReading is recommended for the latest foreign + // tab. + { + CreateSearchWithContinueReading(); + session_tracker()->InitLocalSession(kLocalSessionTag, kLocalSessionName, + sync_pb::SyncEnums::TYPE_CROS); + const base::Time kTimestamp1 = + base::Time::Now() - base::TimeDelta::FromMinutes(2); + const base::Time kTimestamp2 = + base::Time::Now() - base::TimeDelta::FromMinutes(1); + const base::Time kTimestamp3 = + base::Time::Now() - base::TimeDelta::FromMinutes(3); + + session_tracker()->PutWindowInSession(kForeignSessionTag1, kWindowId1); + session_tracker()->PutTabInWindow(kForeignSessionTag1, kWindowId1, kTabId1); + session_tracker() + ->GetTab(kForeignSessionTag1, kTabId1) + ->navigations.push_back( + sessions::SerializedNavigationEntryTestHelper::CreateNavigation( + "http://url1", "title1")); + session_tracker()->GetTab(kForeignSessionTag1, kTabId1)->timestamp = + kTimestamp1; + session_tracker()->GetSession(kForeignSessionTag1)->modified_time = + kTimestamp1; + session_tracker()->GetSession(kForeignSessionTag1)->device_type = + sync_pb::SyncEnums::TYPE_PHONE; + + session_tracker()->PutWindowInSession(kForeignSessionTag2, kWindowId2); + session_tracker()->PutTabInWindow(kForeignSessionTag2, kWindowId2, kTabId2); + session_tracker() + ->GetTab(kForeignSessionTag2, kTabId2) + ->navigations.push_back( + sessions::SerializedNavigationEntryTestHelper::CreateNavigation( + "http://url2", "title2")); + session_tracker()->GetTab(kForeignSessionTag2, kTabId2)->timestamp = + kTimestamp2; + session_tracker()->GetSession(kForeignSessionTag2)->modified_time = + kTimestamp2; + session_tracker()->GetSession(kForeignSessionTag2)->device_type = + sync_pb::SyncEnums::TYPE_PHONE; + + session_tracker()->PutWindowInSession(kForeignSessionTag3, kWindowId3); + session_tracker()->PutTabInWindow(kForeignSessionTag3, kWindowId3, kTabId3); + session_tracker() + ->GetTab(kForeignSessionTag3, kTabId3) + ->navigations.push_back( + sessions::SerializedNavigationEntryTestHelper::CreateNavigation( + "http://url3", "title3")); + session_tracker()->GetTab(kForeignSessionTag3, kTabId3)->timestamp = + kTimestamp3; + session_tracker()->GetSession(kForeignSessionTag3)->modified_time = + kTimestamp3; + session_tracker()->GetSession(kForeignSessionTag3)->device_type = + sync_pb::SyncEnums::TYPE_PHONE; + + EXPECT_EQ("title2,Hosted App,Packaged App 1,Packaged App 2,Settings,Camera", + RunQuery("")); + } + + // Case 2: test that ContinueReading is not recommended for local session. + { + CreateSearchWithContinueReading(); + session_tracker()->InitLocalSession(kLocalSessionTag, kLocalSessionName, + sync_pb::SyncEnums::TYPE_CROS); + const base::Time kTimestamp1 = + base::Time::Now() - base::TimeDelta::FromMinutes(1); + + session_tracker()->PutWindowInSession(kLocalSessionTag, kWindowId1); + session_tracker()->PutTabInWindow(kLocalSessionTag, kWindowId1, kTabId1); + session_tracker() + ->GetTab(kLocalSessionTag, kTabId1) + ->navigations.push_back( + sessions::SerializedNavigationEntryTestHelper::CreateNavigation( + "http://url1", "title1")); + session_tracker()->GetTab(kLocalSessionTag, kTabId1)->timestamp = + kTimestamp1; + session_tracker()->GetSession(kLocalSessionTag)->modified_time = + kTimestamp1; + session_tracker()->GetSession(kLocalSessionTag)->device_type = + sync_pb::SyncEnums::TYPE_PHONE; + + EXPECT_EQ("Hosted App,Packaged App 1,Packaged App 2,Settings,Camera", + RunQuery("")); + } + + // Case 3: test that ContinueReading is not recommended for foreign tab more + // than 120 minutes ago. + { + CreateSearchWithContinueReading(); + session_tracker()->InitLocalSession(kLocalSessionTag, kLocalSessionName, + sync_pb::SyncEnums::TYPE_CROS); + const base::Time kTimestamp1 = + base::Time::Now() - base::TimeDelta::FromMinutes(121); + + session_tracker()->PutWindowInSession(kForeignSessionTag1, kWindowId1); + session_tracker()->PutTabInWindow(kForeignSessionTag1, kWindowId1, kTabId1); + session_tracker() + ->GetTab(kForeignSessionTag1, kTabId1) + ->navigations.push_back( + sessions::SerializedNavigationEntryTestHelper::CreateNavigation( + "http://url1", "title1")); + session_tracker()->GetTab(kForeignSessionTag1, kTabId1)->timestamp = + kTimestamp1; + session_tracker()->GetSession(kForeignSessionTag1)->modified_time = + kTimestamp1; + session_tracker()->GetSession(kForeignSessionTag1)->device_type = + sync_pb::SyncEnums::TYPE_PHONE; + + EXPECT_EQ("Hosted App,Packaged App 1,Packaged App 2,Settings,Camera", + RunQuery("")); + } + + // Case 4: test that ContinueReading is recommended for foreign tab with + // TYPE_TABLET. + { + CreateSearchWithContinueReading(); + session_tracker()->InitLocalSession(kLocalSessionTag, kLocalSessionName, + sync_pb::SyncEnums::TYPE_CROS); + const base::Time kTimestamp1 = + base::Time::Now() - base::TimeDelta::FromMinutes(1); + + session_tracker()->PutWindowInSession(kForeignSessionTag1, kWindowId1); + session_tracker()->PutTabInWindow(kForeignSessionTag1, kWindowId1, kTabId1); + session_tracker() + ->GetTab(kForeignSessionTag1, kTabId1) + ->navigations.push_back( + sessions::SerializedNavigationEntryTestHelper::CreateNavigation( + "http://url1", "title1")); + session_tracker()->GetTab(kForeignSessionTag1, kTabId1)->timestamp = + kTimestamp1; + session_tracker()->GetSession(kForeignSessionTag1)->modified_time = + kTimestamp1; + session_tracker()->GetSession(kForeignSessionTag1)->device_type = + sync_pb::SyncEnums::TYPE_TABLET; + + EXPECT_EQ("title1,Hosted App,Packaged App 1,Packaged App 2,Settings,Camera", + RunQuery("")); + } + + // Case 5: test that ContinueReading is not recommended for foreign tab with + // TYPE_CROS. + { + CreateSearchWithContinueReading(); + session_tracker()->InitLocalSession(kLocalSessionTag, kLocalSessionName, + sync_pb::SyncEnums::TYPE_CROS); + const base::Time kTimestamp1 = + base::Time::Now() - base::TimeDelta::FromMinutes(1); + + session_tracker()->PutWindowInSession(kForeignSessionTag1, kWindowId1); + session_tracker()->PutTabInWindow(kForeignSessionTag1, kWindowId1, kTabId1); + session_tracker() + ->GetTab(kForeignSessionTag1, kTabId1) + ->navigations.push_back( + sessions::SerializedNavigationEntryTestHelper::CreateNavigation( + "http://url1", "title1")); + session_tracker()->GetTab(kForeignSessionTag1, kTabId1)->timestamp = + kTimestamp1; + session_tracker()->GetSession(kForeignSessionTag1)->modified_time = + kTimestamp1; + session_tracker()->GetSession(kForeignSessionTag1)->device_type = + sync_pb::SyncEnums::TYPE_CROS; + + EXPECT_EQ("Hosted App,Packaged App 1,Packaged App 2,Settings,Camera", + RunQuery("")); + } + + // Case 6: test that ContinueReading is not recommended for foreign tab which + // is not SchemeIsHTTPOrHTTPS. + { + CreateSearchWithContinueReading(); + session_tracker()->InitLocalSession(kLocalSessionTag, kLocalSessionName, + sync_pb::SyncEnums::TYPE_CROS); + const base::Time kTimestamp1 = + base::Time::Now() - base::TimeDelta::FromMinutes(1); + + session_tracker()->PutWindowInSession(kForeignSessionTag1, kWindowId1); + session_tracker()->PutTabInWindow(kForeignSessionTag1, kWindowId1, kTabId1); + session_tracker() + ->GetTab(kForeignSessionTag1, kTabId1) + ->navigations.push_back( + sessions::SerializedNavigationEntryTestHelper::CreateNavigation( + "data://url1", "title1")); + session_tracker()->GetTab(kForeignSessionTag1, kTabId1)->timestamp = + kTimestamp1; + session_tracker()->GetSession(kForeignSessionTag1)->modified_time = + kTimestamp1; + session_tracker()->GetSession(kForeignSessionTag1)->device_type = + sync_pb::SyncEnums::TYPE_CROS; + + EXPECT_EQ("Hosted App,Packaged App 1,Packaged App 2,Settings,Camera", + RunQuery("")); + } + + // Case 7: test that ContinueReading is not recommended when searching. + { + CreateSearchWithContinueReading(); + session_tracker()->InitLocalSession(kLocalSessionTag, kLocalSessionName, + sync_pb::SyncEnums::TYPE_CROS); + const base::Time kTimestamp1 = + base::Time::Now() - base::TimeDelta::FromMinutes(1); + + session_tracker()->PutWindowInSession(kForeignSessionTag1, kWindowId1); + session_tracker()->PutTabInWindow(kForeignSessionTag1, kWindowId1, kTabId1); + session_tracker() + ->GetTab(kForeignSessionTag1, kTabId1) + ->navigations.push_back( + sessions::SerializedNavigationEntryTestHelper::CreateNavigation( + "http://url1", "title1")); + session_tracker()->GetTab(kForeignSessionTag1, kTabId1)->timestamp = + kTimestamp1; + session_tracker()->GetSession(kForeignSessionTag1)->modified_time = + kTimestamp1; + session_tracker()->GetSession(kForeignSessionTag1)->device_type = + sync_pb::SyncEnums::TYPE_PHONE; + EXPECT_EQ("Settings", RunQuery("ti")); + } +} + TEST_F(AppSearchProviderTest, FetchUnlaunchedRecommendations) { CreateSearch();
diff --git a/chrome/browser/ui/autofill/local_card_migration_dialog_controller_impl.cc b/chrome/browser/ui/autofill/local_card_migration_dialog_controller_impl.cc index 8e2958a..ea53a563 100644 --- a/chrome/browser/ui/autofill/local_card_migration_dialog_controller_impl.cc +++ b/chrome/browser/ui/autofill/local_card_migration_dialog_controller_impl.cc
@@ -25,6 +25,7 @@ #include "components/autofill/core/browser/payments/payments_service_url.h" #include "components/autofill/core/browser/validation.h" #include "components/autofill/core/common/autofill_clock.h" +#include "components/autofill/core/common/autofill_features.h" #include "components/autofill/core/common/autofill_prefs.h" #include "components/prefs/pref_service.h" #include "components/user_prefs/user_prefs.h" @@ -143,7 +144,11 @@ AutofillMetrics::LOCAL_CARD_MIGRATION_DIALOG_CLOSED_SAVE_BUTTON_CLICKED); std::move(start_migrating_cards_callback_).Run(selected_cards_guids); - NotifyMigrationStarted(); + // If flag is disabled, we don't show the credit card icon animation. + base::FeatureList::IsEnabled( + features::kAutofillLocalCardMigrationShowFeedback) + ? NotifyMigrationStarted() + : NotifyMigrationNoLongerAvailable(); } void LocalCardMigrationDialogControllerImpl::OnCancelButtonClicked() {
diff --git a/chrome/browser/ui/browser.cc b/chrome/browser/ui/browser.cc index 1f3c2ce..9f32d6a05 100644 --- a/chrome/browser/ui/browser.cc +++ b/chrome/browser/ui/browser.cc
@@ -955,6 +955,14 @@ GetStatusBubble()->UpdateDownloadShelfVisibility(visible); } +bool Browser::CanReloadContents(content::WebContents* web_contents) const { + return chrome::CanReload(this); +} + +bool Browser::CanSaveContents(content::WebContents* web_contents) const { + return chrome::CanSavePage(this); +} + /////////////////////////////////////////////////////////////////////////////// void Browser::UpdateUIForNavigationInTab(WebContents* contents, @@ -1897,17 +1905,6 @@ #endif /////////////////////////////////////////////////////////////////////////////// -// Browser, CoreTabHelperDelegate implementation: - -bool Browser::CanReloadContents(content::WebContents* web_contents) const { - return chrome::CanReload(this); -} - -bool Browser::CanSaveContents(content::WebContents* web_contents) const { - return chrome::CanSavePage(this); -} - -/////////////////////////////////////////////////////////////////////////////// // Browser, web_modal::WebContentsModalDialogManagerDelegate implementation: void Browser::SetWebContentsBlocked(content::WebContents* web_contents, @@ -2497,7 +2494,6 @@ // ...and all the helpers. WebContentsModalDialogManager::FromWebContents(web_contents)-> SetDelegate(delegate); - CoreTabHelper::FromWebContents(web_contents)->set_delegate(delegate); translate::ContentTranslateDriver& content_translate_driver = ChromeTranslateClient::FromWebContents(web_contents)->translate_driver(); if (delegate) {
diff --git a/chrome/browser/ui/browser.h b/chrome/browser/ui/browser.h index 9769a792..70d32c5f 100644 --- a/chrome/browser/ui/browser.h +++ b/chrome/browser/ui/browser.h
@@ -29,7 +29,6 @@ #include "chrome/browser/ui/exclusive_access/exclusive_access_manager.h" #include "chrome/browser/ui/profile_chooser_constants.h" #include "chrome/browser/ui/signin_view_controller.h" -#include "chrome/browser/ui/tab_contents/core_tab_helper_delegate.h" #include "chrome/browser/ui/tabs/tab_strip_model_observer.h" #include "components/content_settings/core/common/content_settings.h" #include "components/content_settings/core/common/content_settings_types.h" @@ -107,7 +106,6 @@ class Browser : public TabStripModelObserver, public content::WebContentsDelegate, - public CoreTabHelperDelegate, public ChromeWebModalDialogManagerDelegate, public BookmarkTabHelperObserver, #if !defined(OS_ANDROID) @@ -431,6 +429,14 @@ void UpdateDownloadShelfVisibility(bool visible); + // Whether the specified WebContents can be reloaded. + // Reloading can be disabled e.g. for the DevTools window. + bool CanReloadContents(content::WebContents* web_contents) const; + + // Whether the specified WebContents can be saved. + // Saving can be disabled e.g. for the DevTools window. + bool CanSaveContents(content::WebContents* web_contents) const; + ///////////////////////////////////////////////////////////////////////////// // Called by Navigate() when a navigation has occurred in a tab in @@ -720,10 +726,6 @@ content::RenderFrameHost* subframe_host) const override; #endif - // Overridden from CoreTabHelperDelegate: - bool CanReloadContents(content::WebContents* web_contents) const override; - bool CanSaveContents(content::WebContents* web_contents) const override; - // Overridden from WebContentsModalDialogManagerDelegate: void SetWebContentsBlocked(content::WebContents* web_contents, bool blocked) override;
diff --git a/chrome/browser/ui/libgtkui/native_theme_gtk.cc b/chrome/browser/ui/libgtkui/native_theme_gtk.cc index 14ca0b6e..06e48ac 100644 --- a/chrome/browser/ui/libgtkui/native_theme_gtk.cc +++ b/chrome/browser/ui/libgtkui/native_theme_gtk.cc
@@ -198,6 +198,7 @@ // ProminentButton case ui::NativeTheme::kColorId_ProminentButtonColor: + case ui::NativeTheme::kColorId_ProminentButtonFocusedColor: return GetBgColor( "GtkTreeView#treeview.view " "GtkTreeView#treeview.view.cell:selected:focus");
diff --git a/chrome/browser/ui/omnibox/chrome_omnibox_client.cc b/chrome/browser/ui/omnibox/chrome_omnibox_client.cc index a7d718e..5d7db03 100644 --- a/chrome/browser/ui/omnibox/chrome_omnibox_client.cc +++ b/chrome/browser/ui/omnibox/chrome_omnibox_client.cc
@@ -47,7 +47,6 @@ #include "chrome/browser/ui/layout_constants.h" #include "chrome/browser/ui/omnibox/chrome_omnibox_edit_controller.h" #include "chrome/browser/ui/omnibox/chrome_omnibox_navigation_observer.h" -#include "chrome/browser/ui/omnibox/query_in_omnibox_factory.h" #include "chrome/browser/ui/search/search_tab_helper.h" #include "chrome/common/pref_names.h" #include "chrome/common/search/instant_types.h" @@ -232,10 +231,6 @@ return AutocompleteClassifierFactory::GetForProfile(profile_); } -QueryInOmnibox* ChromeOmniboxClient::GetQueryInOmnibox() { - return QueryInOmniboxFactory::GetForProfile(profile_); -} - gfx::Image ChromeOmniboxClient::GetIconIfExtensionMatch( const AutocompleteMatch& match) const { TemplateURLService* service =
diff --git a/chrome/browser/ui/omnibox/chrome_omnibox_client.h b/chrome/browser/ui/omnibox/chrome_omnibox_client.h index 726bdfef..96cf00a 100644 --- a/chrome/browser/ui/omnibox/chrome_omnibox_client.h +++ b/chrome/browser/ui/omnibox/chrome_omnibox_client.h
@@ -49,7 +49,6 @@ TemplateURLService* GetTemplateURLService() override; const AutocompleteSchemeClassifier& GetSchemeClassifier() const override; AutocompleteClassifier* GetAutocompleteClassifier() override; - QueryInOmnibox* GetQueryInOmnibox() override; gfx::Image GetIconIfExtensionMatch( const AutocompleteMatch& match) const override; gfx::Image GetSizedIcon(const gfx::VectorIcon& vector_icon_type,
diff --git a/chrome/browser/ui/omnibox/query_in_omnibox_factory.cc b/chrome/browser/ui/omnibox/query_in_omnibox_factory.cc deleted file mode 100644 index d0516ef..0000000 --- a/chrome/browser/ui/omnibox/query_in_omnibox_factory.cc +++ /dev/null
@@ -1,56 +0,0 @@ -// Copyright 2018 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "chrome/browser/ui/omnibox/query_in_omnibox_factory.h" - -#include "chrome/browser/autocomplete/autocomplete_classifier_factory.h" -#include "chrome/browser/profiles/incognito_helpers.h" -#include "chrome/browser/profiles/profile.h" -#include "chrome/browser/search_engines/template_url_service_factory.h" -#include "components/keyed_service/content/browser_context_dependency_manager.h" -#include "components/omnibox/browser/query_in_omnibox.h" - -// static -QueryInOmnibox* QueryInOmniboxFactory::GetForProfile(Profile* profile) { - return static_cast<QueryInOmnibox*>( - GetInstance()->GetServiceForBrowserContext(profile, true)); -} - -// static -QueryInOmniboxFactory* QueryInOmniboxFactory::GetInstance() { - return base::Singleton<QueryInOmniboxFactory>::get(); -} - -// static -std::unique_ptr<KeyedService> QueryInOmniboxFactory::BuildInstanceFor( - content::BrowserContext* context) { - Profile* profile = static_cast<Profile*>(context); - return std::make_unique<QueryInOmnibox>( - AutocompleteClassifierFactory::GetForProfile(profile), - TemplateURLServiceFactory::GetForProfile(profile)); -} - -QueryInOmniboxFactory::QueryInOmniboxFactory() - : BrowserContextKeyedServiceFactory( - "QueryInOmnibox", - BrowserContextDependencyManager::GetInstance()) { - DependsOn(AutocompleteClassifierFactory::GetInstance()); - DependsOn(TemplateURLServiceFactory::GetInstance()); -} - -QueryInOmniboxFactory::~QueryInOmniboxFactory() {} - -content::BrowserContext* QueryInOmniboxFactory::GetBrowserContextToUse( - content::BrowserContext* context) const { - return chrome::GetBrowserContextRedirectedInIncognito(context); -} - -bool QueryInOmniboxFactory::ServiceIsNULLWhileTesting() const { - return true; -} - -KeyedService* QueryInOmniboxFactory::BuildServiceInstanceFor( - content::BrowserContext* profile) const { - return BuildInstanceFor(static_cast<Profile*>(profile)).release(); -}
diff --git a/chrome/browser/ui/omnibox/query_in_omnibox_factory.h b/chrome/browser/ui/omnibox/query_in_omnibox_factory.h deleted file mode 100644 index 9bc67e3..0000000 --- a/chrome/browser/ui/omnibox/query_in_omnibox_factory.h +++ /dev/null
@@ -1,45 +0,0 @@ -// Copyright 2018 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef CHROME_BROWSER_UI_OMNIBOX_QUERY_IN_OMNIBOX_FACTORY_H_ -#define CHROME_BROWSER_UI_OMNIBOX_QUERY_IN_OMNIBOX_FACTORY_H_ - -#include <memory> - -#include "base/macros.h" -#include "base/memory/singleton.h" -#include "components/keyed_service/content/browser_context_keyed_service_factory.h" - -class QueryInOmnibox; -class Profile; - -// Singleton that owns all QueryInOmnibox instances and associates them with -// Profiles. -class QueryInOmniboxFactory : public BrowserContextKeyedServiceFactory { - public: - // Returns the QueryInOmnibox for |profile|. - static QueryInOmnibox* GetForProfile(Profile* profile); - - static QueryInOmniboxFactory* GetInstance(); - - static std::unique_ptr<KeyedService> BuildInstanceFor( - content::BrowserContext* context); - - private: - friend struct base::DefaultSingletonTraits<QueryInOmniboxFactory>; - - QueryInOmniboxFactory(); - ~QueryInOmniboxFactory() override; - - // BrowserContextKeyedServiceFactory: - content::BrowserContext* GetBrowserContextToUse( - content::BrowserContext* context) const override; - bool ServiceIsNULLWhileTesting() const override; - KeyedService* BuildServiceInstanceFor( - content::BrowserContext* profile) const override; - - DISALLOW_COPY_AND_ASSIGN(QueryInOmniboxFactory); -}; - -#endif // CHROME_BROWSER_UI_OMNIBOX_QUERY_IN_OMNIBOX_FACTORY_H_
diff --git a/chrome/browser/ui/tab_contents/core_tab_helper.cc b/chrome/browser/ui/tab_contents/core_tab_helper.cc index 940df79c..be039ce 100644 --- a/chrome/browser/ui/tab_contents/core_tab_helper.cc +++ b/chrome/browser/ui/tab_contents/core_tab_helper.cc
@@ -58,7 +58,6 @@ CoreTabHelper::CoreTabHelper(WebContents* web_contents) : content::WebContentsObserver(web_contents), - delegate_(NULL), content_restrictions_(0), weak_factory_(this) {}
diff --git a/chrome/browser/ui/tab_contents/core_tab_helper.h b/chrome/browser/ui/tab_contents/core_tab_helper.h index 9670b324..0a4d3210 100644 --- a/chrome/browser/ui/tab_contents/core_tab_helper.h +++ b/chrome/browser/ui/tab_contents/core_tab_helper.h
@@ -17,8 +17,6 @@ #include "ui/gfx/geometry/size.h" #include "url/gurl.h" -class CoreTabHelperDelegate; - // Per-tab class to handle functionality that is core to the operation of tabs. class CoreTabHelper : public content::WebContentsObserver, public content::WebContentsUserData<CoreTabHelper> { @@ -55,9 +53,6 @@ void SearchByImageInNewTab(content::RenderFrameHost* render_frame_host, const GURL& src_url); - CoreTabHelperDelegate* delegate() const { return delegate_; } - void set_delegate(CoreTabHelperDelegate* d) { delegate_ = d; } - void set_new_tab_start_time(const base::TimeTicks& time) { new_tab_start_time_ = time; } @@ -87,9 +82,6 @@ const std::vector<uint8_t>& thumbnail_data, const gfx::Size& original_size); - // Delegate for notifying our owner about stuff. Not owned by us. - CoreTabHelperDelegate* delegate_; - // The time when we started to create the new tab page. This time is from // before we created this WebContents. base::TimeTicks new_tab_start_time_;
diff --git a/chrome/browser/ui/tab_contents/core_tab_helper_delegate.cc b/chrome/browser/ui/tab_contents/core_tab_helper_delegate.cc deleted file mode 100644 index c7f6017..0000000 --- a/chrome/browser/ui/tab_contents/core_tab_helper_delegate.cc +++ /dev/null
@@ -1,20 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "chrome/browser/ui/tab_contents/core_tab_helper_delegate.h" - -#include "content/public/browser/web_contents.h" - -CoreTabHelperDelegate::~CoreTabHelperDelegate() { -} - -bool CoreTabHelperDelegate::CanReloadContents( - content::WebContents* web_contents) const { - return true; -} - -bool CoreTabHelperDelegate::CanSaveContents( - content::WebContents* web_contents) const { - return true; -}
diff --git a/chrome/browser/ui/tab_contents/core_tab_helper_delegate.h b/chrome/browser/ui/tab_contents/core_tab_helper_delegate.h deleted file mode 100644 index a873508..0000000 --- a/chrome/browser/ui/tab_contents/core_tab_helper_delegate.h +++ /dev/null
@@ -1,34 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef CHROME_BROWSER_UI_TAB_CONTENTS_CORE_TAB_HELPER_DELEGATE_H_ -#define CHROME_BROWSER_UI_TAB_CONTENTS_CORE_TAB_HELPER_DELEGATE_H_ - -#include <memory> - -namespace content { -class WebContents; -} - -// Objects implement this interface to get notified about changes in a -// WebContents and to provide necessary functionality. -// -// This is the catch-all interface for holding additions to WebContents that are -// needed when a WebContents is promoted to being a tab contents, but that -// don't cleanly fit elsewhere. -class CoreTabHelperDelegate { - public: - // Whether the specified WebContents can be reloaded. - // Reloading can be disabled e.g. for the DevTools window. - virtual bool CanReloadContents(content::WebContents* web_contents) const; - - // Whether the specified WebContents can be saved. - // Saving can be disabled e.g. for the DevTools window. - virtual bool CanSaveContents(content::WebContents* web_contents) const; - - protected: - virtual ~CoreTabHelperDelegate(); -}; - -#endif // CHROME_BROWSER_UI_TAB_CONTENTS_CORE_TAB_HELPER_DELEGATE_H_
diff --git a/chrome/browser/ui/tabs/tab_strip_model.cc b/chrome/browser/ui/tabs/tab_strip_model.cc index e260e94..0705907 100644 --- a/chrome/browser/ui/tabs/tab_strip_model.cc +++ b/chrome/browser/ui/tabs/tab_strip_model.cc
@@ -21,8 +21,9 @@ #include "chrome/browser/extensions/tab_helper.h" #include "chrome/browser/lifetime/browser_shutdown.h" #include "chrome/browser/profiles/profile.h" +#include "chrome/browser/ui/browser.h" +#include "chrome/browser/ui/browser_finder.h" #include "chrome/browser/ui/tab_contents/core_tab_helper.h" -#include "chrome/browser/ui/tab_contents/core_tab_helper_delegate.h" #include "chrome/browser/ui/tabs/tab_strip_model_delegate.h" #include "chrome/browser/ui/tabs/tab_strip_model_order_controller.h" #include "chrome/browser/ui/tabs/tab_utils.h" @@ -919,9 +920,8 @@ for (size_t i = 0; i < indices.size(); ++i) { WebContents* tab = GetWebContentsAt(indices[i]); if (tab) { - CoreTabHelperDelegate* core_delegate = - CoreTabHelper::FromWebContents(tab)->delegate(); - if (!core_delegate || core_delegate->CanReloadContents(tab)) + Browser* browser = chrome::FindBrowserWithWebContents(tab); + if (!browser || browser->CanReloadContents(tab)) return true; } } @@ -994,9 +994,8 @@ for (size_t i = 0; i < indices.size(); ++i) { WebContents* tab = GetWebContentsAt(indices[i]); if (tab) { - CoreTabHelperDelegate* core_delegate = - CoreTabHelper::FromWebContents(tab)->delegate(); - if (!core_delegate || core_delegate->CanReloadContents(tab)) + Browser* browser = chrome::FindBrowserWithWebContents(tab); + if (!browser || browser->CanReloadContents(tab)) tab->GetController().Reload(content::ReloadType::NORMAL, true); } }
diff --git a/chrome/browser/ui/toolbar/chrome_location_bar_model_delegate.cc b/chrome/browser/ui/toolbar/chrome_location_bar_model_delegate.cc index 932b63e..74b77f1 100644 --- a/chrome/browser/ui/toolbar/chrome_location_bar_model_delegate.cc +++ b/chrome/browser/ui/toolbar/chrome_location_bar_model_delegate.cc
@@ -6,9 +6,11 @@ #include "base/logging.h" #include "build/build_config.h" +#include "chrome/browser/autocomplete/autocomplete_classifier_factory.h" #include "chrome/browser/autocomplete/chrome_autocomplete_scheme_classifier.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/search/search.h" +#include "chrome/browser/search_engines/template_url_service_factory.h" #include "chrome/browser/ssl/security_state_tab_helper.h" #include "chrome/common/pref_names.h" #include "chrome/common/url_constants.h" @@ -181,3 +183,15 @@ ? Profile::FromBrowserContext(controller->GetBrowserContext()) : nullptr; } + +AutocompleteClassifier* +ChromeLocationBarModelDelegate::GetAutocompleteClassifier() { + Profile* const profile = GetProfile(); + return profile ? AutocompleteClassifierFactory::GetForProfile(profile) + : nullptr; +} + +TemplateURLService* ChromeLocationBarModelDelegate::GetTemplateURLService() { + Profile* const profile = GetProfile(); + return profile ? TemplateURLServiceFactory::GetForProfile(profile) : nullptr; +}
diff --git a/chrome/browser/ui/toolbar/chrome_location_bar_model_delegate.h b/chrome/browser/ui/toolbar/chrome_location_bar_model_delegate.h index 8fb7b28..7254de3 100644 --- a/chrome/browser/ui/toolbar/chrome_location_bar_model_delegate.h +++ b/chrome/browser/ui/toolbar/chrome_location_bar_model_delegate.h
@@ -44,6 +44,8 @@ bool FailsMalwareCheck() const override; const gfx::VectorIcon* GetVectorIconOverride() const override; bool IsOfflinePage() const override; + AutocompleteClassifier* GetAutocompleteClassifier() override; + TemplateURLService* GetTemplateURLService() override; // Returns the navigation controller used to retrieve the navigation entry // from which the states are retrieved. If this returns null, default values
diff --git a/chrome/browser/ui/views/autofill/autofill_popup_base_view.cc b/chrome/browser/ui/views/autofill/autofill_popup_base_view.cc index 9b47e55..18bb9c9 100644 --- a/chrome/browser/ui/views/autofill/autofill_popup_base_view.cc +++ b/chrome/browser/ui/views/autofill/autofill_popup_base_view.cc
@@ -26,22 +26,36 @@ namespace autofill { -// TODO(crbug.com/831603): Determine how colors should be shared with menus -// and/or omnibox, and how these should interact (if at all) with native -// theme colors. -const SkColor AutofillPopupBaseView::kBackgroundColor = SK_ColorWHITE; -const SkColor AutofillPopupBaseView::kSelectedBackgroundColor = - gfx::kGoogleGrey200; -const SkColor AutofillPopupBaseView::kFooterBackgroundColor = - gfx::kGoogleGrey050; -const SkColor AutofillPopupBaseView::kSeparatorColor = gfx::kGoogleGrey200; -const SkColor AutofillPopupBaseView::kWarningColor = gfx::kGoogleRed600; - int AutofillPopupBaseView::GetCornerRadius() { return ChromeLayoutProvider::Get()->GetCornerRadiusMetric( views::EMPHASIS_MEDIUM); } +SkColor AutofillPopupBaseView::GetBackgroundColor() { + return GetNativeTheme()->GetSystemColor( + ui::NativeTheme::kColorId_MenuBackgroundColor); +} + +SkColor AutofillPopupBaseView::GetSelectedBackgroundColor() { + return GetNativeTheme()->GetSystemColor( + ui::NativeTheme::kColorId_FocusedHighlightedMenuItemBackgroundColor); +} + +SkColor AutofillPopupBaseView::GetFooterBackgroundColor() { + return GetNativeTheme()->GetSystemColor( + ui::NativeTheme::kColorId_HighlightedMenuItemBackgroundColor); +} + +SkColor AutofillPopupBaseView::GetSeparatorColor() { + return GetNativeTheme()->GetSystemColor( + ui::NativeTheme::kColorId_MenuSeparatorColor); +} + +SkColor AutofillPopupBaseView::GetWarningColor() { + return GetNativeTheme()->GetSystemColor( + ui::NativeTheme::kColorId_AlertSeverityHigh); +} + AutofillPopupBaseView::AutofillPopupBaseView( AutofillPopupViewDelegate* delegate, views::Widget* parent_widget)
diff --git a/chrome/browser/ui/views/autofill/autofill_popup_base_view.h b/chrome/browser/ui/views/autofill/autofill_popup_base_view.h index 846573c2..227bcf4 100644 --- a/chrome/browser/ui/views/autofill/autofill_popup_base_view.h +++ b/chrome/browser/ui/views/autofill/autofill_popup_base_view.h
@@ -27,12 +27,6 @@ public views::WidgetFocusChangeListener, public views::WidgetObserver { public: - static const SkColor kBackgroundColor; - static const SkColor kSelectedBackgroundColor; - static const SkColor kFooterBackgroundColor; - static const SkColor kSeparatorColor; - static const SkColor kWarningColor; - // Consider the input element is |kElementBorderPadding| pixels larger at the // top and at the bottom in order to reposition the dropdown, so that it // doesn't look too close to the element. @@ -44,6 +38,14 @@ static int GetCornerRadius(); + // Get colors used throughout various popup UIs, based on the current native + // theme. + SkColor GetBackgroundColor(); + SkColor GetSelectedBackgroundColor(); + SkColor GetFooterBackgroundColor(); + SkColor GetSeparatorColor(); + SkColor GetWarningColor(); + protected: explicit AutofillPopupBaseView(AutofillPopupViewDelegate* delegate, views::Widget* parent_widget);
diff --git a/chrome/browser/ui/views/autofill/autofill_popup_view_native_views.cc b/chrome/browser/ui/views/autofill/autofill_popup_view_native_views.cc index 5ebae227..1f0520a 100644 --- a/chrome/browser/ui/views/autofill/autofill_popup_view_native_views.cc +++ b/chrome/browser/ui/views/autofill/autofill_popup_view_native_views.cc
@@ -528,8 +528,8 @@ std::unique_ptr<views::Background> AutofillPopupSuggestionView::CreateBackground() { return views::CreateSolidBackground( - is_selected_ ? AutofillPopupBaseView::kSelectedBackgroundColor - : AutofillPopupBaseView::kBackgroundColor); + is_selected_ ? popup_view_->GetSelectedBackgroundColor() + : popup_view_->GetBackgroundColor()); } // By default, this returns kLeadingIcon for passwords and kTrailingIcon for all @@ -701,14 +701,14 @@ /*left=*/0, /*bottom=*/0, /*right=*/0, - /*color=*/AutofillPopupBaseView::kSeparatorColor)); + /*color=*/popup_view_->GetSeparatorColor())); AutofillPopupItemView::CreateContent(); } std::unique_ptr<views::Background> AutofillPopupFooterView::CreateBackground() { return views::CreateSolidBackground( - is_selected_ ? AutofillPopupBaseView::kSelectedBackgroundColor - : AutofillPopupBaseView::kFooterBackgroundColor); + is_selected_ ? popup_view_->GetSelectedBackgroundColor() + : popup_view_->GetFooterBackgroundColor()); } int AutofillPopupFooterView::GetPrimaryTextStyle() { @@ -753,7 +753,7 @@ SetLayoutManager(std::make_unique<views::FillLayout>()); views::Separator* separator = new views::Separator(); - separator->SetColor(AutofillPopupBaseView::kSeparatorColor); + separator->SetColor(popup_view_->GetSeparatorColor()); // Add some spacing between the the previous item and the separator. separator->SetPreferredHeight( views::MenuConfig::instance().separator_thickness); @@ -773,7 +773,7 @@ std::unique_ptr<views::Background> AutofillPopupSeparatorView::CreateBackground() { - return views::CreateSolidBackground(SK_ColorWHITE); + return views::CreateSolidBackground(popup_view_->GetBackgroundColor()); } AutofillPopupSeparatorView::AutofillPopupSeparatorView( @@ -818,7 +818,7 @@ views::Label* text_label = CreateLabelWithColorReadabilityDisabled( controller->GetElidedValueAt(line_number_), ChromeTextContext::CONTEXT_BODY_TEXT_LARGE, ChromeTextStyle::STYLE_RED); - text_label->SetEnabledColor(AutofillPopupBaseView::kWarningColor); + text_label->SetEnabledColor(popup_view_->GetWarningColor()); text_label->SetMultiLine(true); int max_width = std::min(kAutofillPopupMaxWidth, @@ -834,7 +834,7 @@ std::unique_ptr<views::Background> AutofillPopupWarningView::CreateBackground() { - return views::CreateSolidBackground(SK_ColorWHITE); + return views::CreateSolidBackground(popup_view_->GetBackgroundColor()); } } // namespace @@ -882,7 +882,7 @@ layout_->set_main_axis_alignment(views::BoxLayout::MAIN_AXIS_ALIGNMENT_START); CreateChildViews(); - SetBackground(views::CreateSolidBackground(kBackgroundColor)); + SetBackground(views::CreateSolidBackground(GetBackgroundColor())); } AutofillPopupViewNativeViews::~AutofillPopupViewNativeViews() {} @@ -1001,7 +1001,7 @@ if (has_footer) { views::View* footer_container = new views::View(); footer_container->SetBackground( - views::CreateSolidBackground(kFooterBackgroundColor)); + views::CreateSolidBackground(GetFooterBackgroundColor())); views::BoxLayout* footer_layout = footer_container->SetLayoutManager( std::make_unique<views::BoxLayout>(views::BoxLayout::kVertical));
diff --git a/chrome/browser/ui/views/media_router/cast_dialog_sink_button.cc b/chrome/browser/ui/views/media_router/cast_dialog_sink_button.cc index 2957722..e10db6dd 100644 --- a/chrome/browser/ui/views/media_router/cast_dialog_sink_button.cc +++ b/chrome/browser/ui/views/media_router/cast_dialog_sink_button.cc
@@ -227,6 +227,9 @@ void CastDialogSinkButton::OnEnabledChanged() { HoverButton::OnEnabledChanged(); + // Prevent a DCHECK failure seen at https://crbug.com/912687 by not having an + // InkDrop if the button is disabled. + SetInkDropMode(enabled() ? InkDropMode::ON : InkDropMode::OFF); // If the button has a state other than AVAILABLE (e.g. CONNECTED), there is // no need to change the status or the icon. if (sink_.state != UIMediaSinkState::AVAILABLE)
diff --git a/chrome/browser/ui/views/omnibox/omnibox_view_views.cc b/chrome/browser/ui/views/omnibox/omnibox_view_views.cc index e415cb7..ecbb5930 100644 --- a/chrome/browser/ui/views/omnibox/omnibox_view_views.cc +++ b/chrome/browser/ui/views/omnibox/omnibox_view_views.cc
@@ -727,7 +727,8 @@ // Don't unelide if we are currently displaying Query in Omnibox search terms, // as otherwise, it would be impossible to refine query terms. - if (model()->GetQueryInOmniboxSearchTerms(nullptr /* search_terms */)) + LocationBarModel* location_bar_model = controller()->GetLocationBarModel(); + if (location_bar_model->GetDisplaySearchTerms(nullptr /* search_terms */)) return false; // If everything is selected, the user likely does not intend to edit the URL. @@ -736,8 +737,7 @@ if (IsSelectAll() && gesture != UnelisionGesture::HOME_KEY_PRESSED) return false; - base::string16 full_url = - controller()->GetLocationBarModel()->GetFormattedFullURL(); + base::string16 full_url = location_bar_model->GetFormattedFullURL(); size_t start, end; GetSelectionBounds(&start, &end);
diff --git a/chrome/browser/ui/views/omnibox/omnibox_view_views_unittest.cc b/chrome/browser/ui/views/omnibox/omnibox_view_views_unittest.cc index c19d844..ef47e07 100644 --- a/chrome/browser/ui/views/omnibox/omnibox_view_views_unittest.cc +++ b/chrome/browser/ui/views/omnibox/omnibox_view_views_unittest.cc
@@ -22,7 +22,6 @@ #include "chrome/browser/search_engines/template_url_service_factory_test_util.h" #include "chrome/browser/ui/omnibox/chrome_omnibox_client.h" #include "chrome/browser/ui/omnibox/chrome_omnibox_edit_controller.h" -#include "chrome/browser/ui/omnibox/query_in_omnibox_factory.h" #include "chrome/test/base/testing_profile.h" #include "chrome/test/views/chrome_views_test_base.h" #include "components/omnibox/browser/omnibox_edit_model.h" @@ -292,8 +291,6 @@ AutocompleteClassifierFactory::GetInstance()->SetTestingFactoryAndUse( &profile_, base::BindRepeating(&AutocompleteClassifierFactory::BuildInstanceFor)); - QueryInOmniboxFactory::GetInstance()->SetTestingFactoryAndUse( - &profile_, base::BindRepeating(&QueryInOmniboxFactory::BuildInstanceFor)); omnibox_view_ = new TestingOmniboxView( &omnibox_edit_controller_, std::make_unique<ChromeOmniboxClient>( &omnibox_edit_controller_, &profile_)); @@ -967,6 +964,8 @@ location_bar_model()->set_url(kValidSearchResultsPage); location_bar_model()->set_security_level( security_state::SecurityLevel::SECURE); + location_bar_model()->set_display_search_terms( + base::ASCIIToUTF16("foo query")); omnibox_view()->model()->ResetDisplayTexts(); omnibox_view()->RevertAll();
diff --git a/chrome/browser/ui/views/passwords/password_generation_popup_view_views.cc b/chrome/browser/ui/views/passwords/password_generation_popup_view_views.cc index 87691ca4..9832faf 100644 --- a/chrome/browser/ui/views/passwords/password_generation_popup_view_views.cc +++ b/chrome/browser/ui/views/passwords/password_generation_popup_view_views.cc
@@ -136,8 +136,8 @@ NotifyAccessibilityEvent(ax::mojom::Event::kSelection, true); password_view_->SetBackground(views::CreateSolidBackground( - controller_->password_selected() ? kSelectedBackgroundColor - : kBackgroundColor)); + controller_->password_selected() ? GetSelectedBackgroundColor() + : GetBackgroundColor())); SchedulePaint(); } @@ -179,7 +179,7 @@ help_label->SetTextContext(ChromeTextContext::CONTEXT_BODY_TEXT_LARGE); help_label->SetDefaultTextStyle(STYLE_SECONDARY); help_label->SetBackground( - views::CreateSolidBackground(kFooterBackgroundColor)); + views::CreateSolidBackground(GetFooterBackgroundColor())); help_label->SetBorder( views::CreateEmptyBorder(kVerticalPadding, kHorizontalMargin, kVerticalPadding, kHorizontalMargin)); @@ -198,7 +198,7 @@ if (password_view_) { gfx::Rect divider_bounds(0, password_view_->bounds().bottom(), password_view_->width(), 1); - canvas->FillRect(divider_bounds, kSeparatorColor); + canvas->FillRect(divider_bounds, GetSeparatorColor()); } }
diff --git a/chrome/browser/ui/webui/extensions/extensions_internals_source.cc b/chrome/browser/ui/webui/extensions/extensions_internals_source.cc index f1768b4..ce8548e 100644 --- a/chrome/browser/ui/webui/extensions/extensions_internals_source.cc +++ b/chrome/browser/ui/webui/extensions/extensions_internals_source.cc
@@ -82,9 +82,41 @@ return ""; } +base::Value CreationFlagsToList(int creation_flags) { + base::Value flags_value(base::Value::Type::LIST); + if (creation_flags & extensions::Extension::NO_FLAGS) + flags_value.GetList().emplace_back("NO_FLAGS"); + if (creation_flags & extensions::Extension::REQUIRE_KEY) + flags_value.GetList().emplace_back("REQUIRE_KEY"); + if (creation_flags & extensions::Extension::REQUIRE_MODERN_MANIFEST_VERSION) + flags_value.GetList().emplace_back("REQUIRE_MODERN_MANIFEST_VERSION"); + if (creation_flags & extensions::Extension::ALLOW_FILE_ACCESS) + flags_value.GetList().emplace_back("ALLOW_FILE_ACCESS"); + if (creation_flags & extensions::Extension::FROM_WEBSTORE) + flags_value.GetList().emplace_back("FROM_WEBSTORE"); + if (creation_flags & extensions::Extension::FROM_BOOKMARK) + flags_value.GetList().emplace_back("FROM_BOOKMARK"); + if (creation_flags & extensions::Extension::FOLLOW_SYMLINKS_ANYWHERE) + flags_value.GetList().emplace_back("FOLLOW_SYMLINKS_ANYWHERE"); + if (creation_flags & extensions::Extension::ERROR_ON_PRIVATE_KEY) + flags_value.GetList().emplace_back("ERROR_ON_PRIVATE_KEY"); + if (creation_flags & extensions::Extension::WAS_INSTALLED_BY_DEFAULT) + flags_value.GetList().emplace_back("WAS_INSTALLED_BY_DEFAULT"); + if (creation_flags & extensions::Extension::REQUIRE_PERMISSIONS_CONSENT) + flags_value.GetList().emplace_back("REQUIRE_PERMISSIONS_CONSENT"); + if (creation_flags & extensions::Extension::IS_EPHEMERAL) + flags_value.GetList().emplace_back("IS_EPHEMERAL"); + if (creation_flags & extensions::Extension::WAS_INSTALLED_BY_OEM) + flags_value.GetList().emplace_back("WAS_INSTALLED_BY_OEM"); + if (creation_flags & extensions::Extension::MAY_BE_UNTRUSTED) + flags_value.GetList().emplace_back("MAY_BE_UNTRUSTED"); + return flags_value; +} + // The JSON we generate looks like this: // // [ { +// "creation_flags": [ "ALLOW_FILE_ACCESS", "FROM_WEBSTORE" ], // "event_listeners": { // "count": 2, // "events": [ { @@ -113,6 +145,8 @@ // // LIST // DICT +// "creation_flags": LIST +// STRING // "event_listeners": DICT // "count": INT // "listeners": LIST @@ -142,6 +176,7 @@ constexpr base::StringPiece kEventsListenersKey = "event_listeners"; constexpr base::StringPiece kExtraDataKey = "extra_data"; constexpr base::StringPiece kFilterKey = "filter"; +constexpr base::StringPiece kInternalsCreationFlagsKey = "creation_flags"; constexpr base::StringPiece kInternalsIdKey = "id"; constexpr base::StringPiece kInternalsNameKey = "name"; constexpr base::StringPiece kInternalsVersionKey = "version"; @@ -268,6 +303,8 @@ for (const auto& extension : *extensions) { base::Value extension_data(base::Value::Type::DICTIONARY); extension_data.SetKey(kInternalsIdKey, base::Value(extension->id())); + extension_data.SetKey(kInternalsCreationFlagsKey, + CreationFlagsToList(extension->creation_flags())); extension_data.SetKey( kKeepaliveKey, FormatKeepaliveData(process_manager, extension.get())); extension_data.SetKey(kLocationKey,
diff --git a/chrome/browser/ui/webui/md_downloads/OWNERS b/chrome/browser/ui/webui/md_downloads/OWNERS index 3b414582..e7f7501 100644 --- a/chrome/browser/ui/webui/md_downloads/OWNERS +++ b/chrome/browser/ui/webui/md_downloads/OWNERS
@@ -1,3 +1,5 @@ +file://components/download/OWNERS + asanka@chromium.org dbeam@chromium.org
diff --git a/chrome/browser/ui/webui/settings/about_handler.cc b/chrome/browser/ui/webui/settings/about_handler.cc index 8816039..f89e7f1 100644 --- a/chrome/browser/ui/webui/settings/about_handler.cc +++ b/chrome/browser/ui/webui/settings/about_handler.cc
@@ -47,7 +47,6 @@ #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/common/user_agent.h" #include "ui/base/l10n/l10n_util.h" #include "v8/include/v8-version-string.h" @@ -354,7 +353,6 @@ html_source->AddString("aboutUserAgent", GetUserAgent()); html_source->AddString("aboutJsEngineVersion", V8_VERSION_STRING); - html_source->AddString("aboutBlinkVersion", content::GetWebKitVersion()); html_source->AddString("endOfLifeMessage", l10n_util::GetStringUTF16(IDS_EOL_NOTIFICATION_EOL)); html_source->AddString("endOfLifeLearnMoreURL",
diff --git a/chrome/browser/ui/webui/settings/md_settings_localized_strings_provider.cc b/chrome/browser/ui/webui/settings/md_settings_localized_strings_provider.cc index 64210f2..faef870 100644 --- a/chrome/browser/ui/webui/settings/md_settings_localized_strings_provider.cc +++ b/chrome/browser/ui/webui/settings/md_settings_localized_strings_provider.cc
@@ -991,13 +991,9 @@ .spec(); html_source->AddString("chromeCleanupLearnMoreUrl", cleanup_learn_more_url); - // The "powered by" footer contains an HTML fragment with the SVG logo of the partner. The logo - // is added to the DOM using <embed>, rather than as an <img> src, to make sure that screen - // readers can find accessibility tags inside the svg. - const base::string16 powered_by_html = l10n_util::GetStringFUTF16( - IDS_SETTINGS_RESET_CLEANUP_FOOTER_POWERED_BY, - L"<embed type='image/svg+xml' id='powered-by-logo' " - L"src='chrome://settings/partner-logo.svg'></embed>"); + const base::string16 powered_by_html = + l10n_util::GetStringFUTF16(IDS_SETTINGS_RESET_CLEANUP_FOOTER_POWERED_BY, + L"<span id='powered-by-logo'></span>"); html_source->AddString("chromeCleanupPoweredByHtml", powered_by_html); const base::string16 cleanup_details_explanation =
diff --git a/chrome/browser/ui/webui/settings/md_settings_ui.cc b/chrome/browser/ui/webui/settings/md_settings_ui.cc index b5ad8df..cb42389 100644 --- a/chrome/browser/ui/webui/settings/md_settings_ui.cc +++ b/chrome/browser/ui/webui/settings/md_settings_ui.cc
@@ -251,12 +251,6 @@ #if defined(GOOGLE_CHROME_BUILD) html_source->AddResourcePath("partner-logo.svg", IDR_CHROME_CLEANUP_PARTNER); - - // partner-logo.svg is loaded with <embed>, which needs to relax several - // security policies. - html_source->OverrideContentSecurityPolicyObjectSrc("object-src chrome:;"); - html_source->OverrideContentSecurityPolicyChildSrc("child-src chrome:;"); - html_source->DisableDenyXFrameOptions(); #if BUILDFLAG(OPTIMIZE_WEBUI) exclude_from_gzip.push_back("partner-logo.svg"); #endif
diff --git a/chrome/chrome_cleaner/constants/BUILD.gn b/chrome/chrome_cleaner/constants/BUILD.gn index 256b02e..b825dec9 100644 --- a/chrome/chrome_cleaner/constants/BUILD.gn +++ b/chrome/chrome_cleaner/constants/BUILD.gn
@@ -9,7 +9,6 @@ process_version("version_header") { sources = [ cleaner_branding_path, - lastchange_path, version_path, ]
diff --git a/chrome/chrome_cleaner/constants/args.gni b/chrome/chrome_cleaner/constants/args.gni index 06fdb05..93ec012d 100644 --- a/chrome/chrome_cleaner/constants/args.gni +++ b/chrome/chrome_cleaner/constants/args.gni
@@ -2,11 +2,8 @@ # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. -import("//build/util/lastchange.gni") - declare_args() { reporter_branding_path = "//chrome/chrome_cleaner/constants/REPORTER_BRANDING" cleaner_branding_path = "//chrome/chrome_cleaner/constants/CLEANER_BRANDING" version_path = "//chrome/chrome_cleaner/constants/VERSION" - lastchange_path = lastchange_file }
diff --git a/chrome/chrome_cleaner/constants/version.h.in b/chrome/chrome_cleaner/constants/version.h.in index a4943f7..38a85cbd 100644 --- a/chrome/chrome_cleaner/constants/version.h.in +++ b/chrome/chrome_cleaner/constants/version.h.in
@@ -19,7 +19,3 @@ #define COMPANY_SHORTNAME_STRING L"@COMPANY_SHORTNAME@" #define COPYRIGHT_STRING L"@COPYRIGHT@" #define OFFICIAL_BUILD_STRING L"@OFFICIAL_BUILD@" - -// Changelist Information - -#define LASTCHANGE_STRING L"@LASTCHANGE@"
diff --git a/chrome/chrome_cleaner/logging/BUILD.gn b/chrome/chrome_cleaner/logging/BUILD.gn index c832a5f3..06746fd 100644 --- a/chrome/chrome_cleaner/logging/BUILD.gn +++ b/chrome/chrome_cleaner/logging/BUILD.gn
@@ -163,7 +163,6 @@ deps = [ "//base:base", - "//chrome/chrome_cleaner/constants:version_header", "//chrome/chrome_cleaner/os:common_os", ]
diff --git a/chrome/chrome_cleaner/logging/interface_log_service.cc b/chrome/chrome_cleaner/logging/interface_log_service.cc index fa4377e8..3705fcb 100644 --- a/chrome/chrome_cleaner/logging/interface_log_service.cc +++ b/chrome/chrome_cleaner/logging/interface_log_service.cc
@@ -19,7 +19,6 @@ #include "base/strings/string_util.h" #include "base/strings/utf_string_conversions.h" #include "base/time/time.h" -#include "chrome/chrome_cleaner/constants/version.h" #include "chrome/chrome_cleaner/logging/proto/interface_logger.pb.h" #include "chrome/chrome_cleaner/os/disk_util.h" @@ -27,7 +26,7 @@ namespace { -base::FilePath GetPathForLogFile(const base::string16& log_file_name) { +base::FilePath GetPathForLogFile(const base::StringPiece16 log_file_name) { base::FilePath app_data_path; GetAppDataProductDirectory(&app_data_path); base::FilePath log_file_path = app_data_path.Append(log_file_name); @@ -45,7 +44,8 @@ // static std::unique_ptr<InterfaceLogService> InterfaceLogService::Create( - const base::string16& file_name) { + const base::StringPiece16 file_name, + const base::StringPiece16 build_version) { if (file_name.empty()) return nullptr; @@ -66,7 +66,7 @@ } return base::WrapUnique<InterfaceLogService>( - new InterfaceLogService(file_name, std::move(stream))); + new InterfaceLogService(file_name, build_version, std::move(stream))); } InterfaceLogService::~InterfaceLogService() = default; @@ -117,17 +117,13 @@ return GetPathForLogFile(log_file_name_); } -InterfaceLogService::InterfaceLogService(const base::string16& file_name, - std::ofstream csv_stream) +InterfaceLogService::InterfaceLogService( + const base::StringPiece16 file_name, + const base::StringPiece16 build_version, + std::ofstream csv_stream) : log_file_name_(file_name), csv_stream_(std::move(csv_stream)) { DETACH_FROM_SEQUENCE(sequence_check_); - base::string16 build_version_utf16 = LASTCHANGE_STRING; - std::string build_version_utf8; - if (!base::UTF16ToUTF8(build_version_utf16.c_str(), - build_version_utf16.size(), &build_version_utf8)) { - LOG(ERROR) << "Cannot convert build version to utf8"; - build_version_utf8 = "UNKNOWN"; - } + std::string build_version_utf8 = base::UTF16ToUTF8(build_version); call_record_.set_build_version(build_version_utf8); // Write build version and column headers.
diff --git a/chrome/chrome_cleaner/logging/interface_log_service.h b/chrome/chrome_cleaner/logging/interface_log_service.h index b413d3d3..0406d6b8 100644 --- a/chrome/chrome_cleaner/logging/interface_log_service.h +++ b/chrome/chrome_cleaner/logging/interface_log_service.h
@@ -14,6 +14,7 @@ #include "base/files/file_path.h" #include "base/sequence_checker.h" #include "base/strings/string16.h" +#include "base/strings/string_piece.h" #include "chrome/chrome_cleaner/logging/proto/interface_logger.pb.h" namespace chrome_cleaner { @@ -27,7 +28,8 @@ class InterfaceLogService { public: static std::unique_ptr<InterfaceLogService> Create( - const base::string16& file_name); + const base::StringPiece16 file_name, + const base::StringPiece16 build_version); ~InterfaceLogService(); @@ -49,14 +51,15 @@ base::FilePath GetLogFilePath() const; private: - InterfaceLogService(const base::string16& file_name, + InterfaceLogService(const base::StringPiece16 file_name, + const base::StringPiece16 build_version, std::ofstream csv_stream); // TODO(joenotcharles): Currently the CallHistory is only used in the unit // test. Decide whether it's worth keeping. CallHistory call_record_; - base::string16 log_file_name_; + const base::string16 log_file_name_; SEQUENCE_CHECKER(sequence_check_); // Stream to output CSV records to.
diff --git a/chrome/chrome_cleaner/logging/interface_log_service_unittest.cc b/chrome/chrome_cleaner/logging/interface_log_service_unittest.cc index 705afc0..e8edb64 100644 --- a/chrome/chrome_cleaner/logging/interface_log_service_unittest.cc +++ b/chrome/chrome_cleaner/logging/interface_log_service_unittest.cc
@@ -16,16 +16,22 @@ #include "base/strings/string_number_conversions.h" #include "base/strings/string_split.h" #include "base/strings/utf_string_conversions.h" -#include "chrome/chrome_cleaner/constants/version.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" namespace chrome_cleaner { +namespace { + +constexpr char kDummyBuildVersion[] = "DUMMY_BUILD_VERSION"; + +} // namespace + class InterfaceLogServiceTest : public testing::Test { public: void SetUp() override { - log_service_ = InterfaceLogService::Create(kLogFileName); + log_service_ = InterfaceLogService::Create( + kLogFileName, base::UTF8ToUTF16(kDummyBuildVersion)); expected_file_size_ = 0LL; } @@ -78,7 +84,6 @@ std::unique_ptr<InterfaceLogService> log_service_; const base::string16 kLogFileName = L"interface_log_service_test"; const std::string kFileName = __FILE__; - base::string16 build_version_ = LASTCHANGE_STRING; }; class TestClass1 { @@ -210,11 +215,8 @@ EXPECT_EQ(state, kReadingCalls); // Make sure the file contents and the data held in log_service_ are equal. - std::string build_version_utf8; - ASSERT_TRUE(base::UTF16ToUTF8(build_version_.c_str(), build_version_.size(), - &build_version_utf8)); - EXPECT_EQ(log_service_->GetBuildVersion(), build_version_utf8); - EXPECT_EQ(call_history_from_file.build_version(), build_version_utf8); + EXPECT_EQ(log_service_->GetBuildVersion(), kDummyBuildVersion); + EXPECT_EQ(call_history_from_file.build_version(), kDummyBuildVersion); std::vector<APICall> call_record = log_service_->GetCallHistory(); EXPECT_EQ(call_record.size(), 5UL); @@ -282,7 +284,8 @@ } TEST_F(InterfaceLogServiceTest, EmptyLogFileTest) { - EXPECT_FALSE(InterfaceLogService::Create(L"")); + EXPECT_FALSE( + InterfaceLogService::Create(L"", base::UTF8ToUTF16(kDummyBuildVersion))); } } // namespace chrome_cleaner
diff --git a/chrome/common/BUILD.gn b/chrome/common/BUILD.gn index 18c352b..88283b7 100644 --- a/chrome/common/BUILD.gn +++ b/chrome/common/BUILD.gn
@@ -3,7 +3,6 @@ # found in the LICENSE file. import("//build/buildflag_header.gni") -import("//build/util/lastchange.gni") import("//build/util/process_version.gni") import("//chrome/common/features.gni") import("//chrome/process_version_rc_template.gni") # For branding_file_path. @@ -518,7 +517,6 @@ sources = [ "//chrome/VERSION", branding_file_path, - lastchange_file, ] template_file = "chrome_version.h.in"
diff --git a/chrome/common/chrome_version.h.in b/chrome/common/chrome_version.h.in index f0a0bcd..54c1b1d 100644 --- a/chrome/common/chrome_version.h.in +++ b/chrome/common/chrome_version.h.in
@@ -18,7 +18,3 @@ #define PRODUCT_SHORTNAME_STRING "@PRODUCT_SHORTNAME@" #define COPYRIGHT_STRING "@COPYRIGHT@" #define OFFICIAL_BUILD_STRING "@OFFICIAL_BUILD@" - -// Changelist Information - -#define LASTCHANGE_STRING "@LASTCHANGE@"
diff --git a/chrome/common/extensions/api/autofill_private.idl b/chrome/common/extensions/api/autofill_private.idl index 166ea49..b41477f7 100644 --- a/chrome/common/extensions/api/autofill_private.idl +++ b/chrome/common/extensions/api/autofill_private.idl
@@ -236,6 +236,9 @@ // Triggers local credit cards migration. static void migrateCreditCards(); + + // Logs that the server cards edit link was clicked. + static void logServerCardLinkClicked(); }; interface Events {
diff --git a/chrome/common/extensions/permissions/permissions_data_unittest.cc b/chrome/common/extensions/permissions/permissions_data_unittest.cc index 1791c46..702296a 100644 --- a/chrome/common/extensions/permissions/permissions_data_unittest.cc +++ b/chrome/common/extensions/permissions/permissions_data_unittest.cc
@@ -391,7 +391,8 @@ int tab_id) { bool allowed_script = IsAllowedScript(extension, url, tab_id); bool allowed_capture = extension->permissions_data()->CanCaptureVisiblePage( - url, tab_id, nullptr); + url, tab_id, nullptr, + extensions::CaptureRequirement::kActiveTabOrAllUrls); if (allowed_script && allowed_capture) return ALLOWED_SCRIPT_AND_CAPTURE; @@ -1067,12 +1068,14 @@ CaptureVisiblePageTest() = default; ~CaptureVisiblePageTest() override = default; - bool CanCapture(const Extension& extension, const GURL& url) { + bool CanCapture(const Extension& extension, + const GURL& url, + extensions::CaptureRequirement capture_requirement) { return extension.permissions_data()->CanCaptureVisiblePage( - url, kTabId, nullptr /*error*/); + url, kTabId, nullptr /*error*/, capture_requirement); } - void GrantActiveTab(const GURL& url) { + void GrantActiveTab(const Extension& extension, const GURL& url) { APIPermissionSet tab_api_permissions; tab_api_permissions.insert(APIPermission::kTab); URLPatternSet tab_hosts; @@ -1081,18 +1084,20 @@ PermissionSet tab_permissions(std::move(tab_api_permissions), ManifestPermissionSet(), tab_hosts, tab_hosts); - active_tab_->permissions_data()->UpdateTabSpecificPermissions( - kTabId, tab_permissions); + extension.permissions_data()->UpdateTabSpecificPermissions(kTabId, + tab_permissions); } - void ClearActiveTab() { - active_tab_->permissions_data()->ClearTabSpecificPermissions(kTabId); + void ClearActiveTab(const Extension& extension) { + extension.permissions_data()->ClearTabSpecificPermissions(kTabId); } const Extension& all_urls() { return *all_urls_; } const Extension& active_tab() { return *active_tab_; } + const Extension& page_capture() { return *page_capture_; } + static constexpr int kTabId = 42; private: @@ -1105,15 +1110,22 @@ .AddPermission("activeTab") .SetID(std::string(32, 'b')) .Build(); + page_capture_ = ExtensionBuilder("page capture") + .AddPermission("pageCapture") + .AddPermission("activeTab") + .SetID(std::string(32, 'd')) + .Build(); } void TearDown() override { all_urls_ = nullptr; active_tab_ = nullptr; + page_capture_ = nullptr; } scoped_refptr<const Extension> all_urls_; scoped_refptr<const Extension> active_tab_; + scoped_refptr<const Extension> page_capture_; DISALLOW_COPY_AND_ASSIGN(CaptureVisiblePageTest); }; @@ -1138,13 +1150,26 @@ for (const GURL& url : test_urls) { SCOPED_TRACE(url.spec()); - EXPECT_TRUE(CanCapture(all_urls(), url)); + EXPECT_TRUE(CanCapture( + all_urls(), url, extensions::CaptureRequirement::kActiveTabOrAllUrls)); - EXPECT_FALSE(CanCapture(active_tab(), url)); - GrantActiveTab(url); - EXPECT_TRUE(CanCapture(active_tab(), url)); - ClearActiveTab(); - EXPECT_FALSE(CanCapture(active_tab(), url)); + EXPECT_FALSE( + CanCapture(active_tab(), url, + extensions::CaptureRequirement::kActiveTabOrAllUrls)); + GrantActiveTab(active_tab(), url); + EXPECT_TRUE( + CanCapture(active_tab(), url, + extensions::CaptureRequirement::kActiveTabOrAllUrls)); + ClearActiveTab(active_tab()); + EXPECT_FALSE( + CanCapture(active_tab(), url, + extensions::CaptureRequirement::kActiveTabOrAllUrls)); + + EXPECT_TRUE(CanCapture(page_capture(), url, + extensions::CaptureRequirement::kPageCapture)); + GrantActiveTab(page_capture(), url); + EXPECT_TRUE(CanCapture(page_capture(), url, + extensions::CaptureRequirement::kPageCapture)); } } @@ -1180,13 +1205,29 @@ for (const GURL& url : test_urls) { SCOPED_TRACE(url.spec()); - EXPECT_FALSE(CanCapture(all_urls(), url)); + EXPECT_FALSE(CanCapture( + all_urls(), url, extensions::CaptureRequirement::kActiveTabOrAllUrls)); - EXPECT_FALSE(CanCapture(active_tab(), url)); - GrantActiveTab(url); - EXPECT_TRUE(CanCapture(active_tab(), url)); - ClearActiveTab(); - EXPECT_FALSE(CanCapture(active_tab(), url)); + EXPECT_FALSE( + CanCapture(active_tab(), url, + extensions::CaptureRequirement::kActiveTabOrAllUrls)); + GrantActiveTab(active_tab(), url); + EXPECT_TRUE( + CanCapture(active_tab(), url, + extensions::CaptureRequirement::kActiveTabOrAllUrls)); + ClearActiveTab(active_tab()); + EXPECT_FALSE( + CanCapture(active_tab(), url, + extensions::CaptureRequirement::kActiveTabOrAllUrls)); + + EXPECT_FALSE(CanCapture(page_capture(), url, + extensions::CaptureRequirement::kPageCapture)); + GrantActiveTab(page_capture(), url); + EXPECT_TRUE(CanCapture(page_capture(), url, + extensions::CaptureRequirement::kPageCapture)); + ClearActiveTab(page_capture()); + EXPECT_FALSE(CanCapture(page_capture(), url, + extensions::CaptureRequirement::kPageCapture)); } } @@ -1206,10 +1247,24 @@ // access. { - EXPECT_TRUE(CanCapture(all_urls(), all_urls().GetResourceURL("foo.html"))); EXPECT_TRUE( - CanCapture(all_urls(), get_filesystem_url_for_extension(all_urls()))); - EXPECT_TRUE(CanCapture(all_urls(), get_blob_url_for_extension(all_urls()))); + CanCapture(all_urls(), all_urls().GetResourceURL("foo.html"), + extensions::CaptureRequirement::kActiveTabOrAllUrls)); + EXPECT_TRUE( + CanCapture(all_urls(), get_filesystem_url_for_extension(all_urls()), + extensions::CaptureRequirement::kActiveTabOrAllUrls)); + EXPECT_TRUE( + CanCapture(all_urls(), get_blob_url_for_extension(all_urls()), + extensions::CaptureRequirement::kActiveTabOrAllUrls)); + EXPECT_TRUE(CanCapture(page_capture(), + page_capture().GetResourceURL("foo.html"), + extensions::CaptureRequirement::kPageCapture)); + EXPECT_TRUE(CanCapture(page_capture(), + get_filesystem_url_for_extension(page_capture()), + extensions::CaptureRequirement::kPageCapture)); + EXPECT_TRUE(CanCapture(page_capture(), + get_blob_url_for_extension(page_capture()), + extensions::CaptureRequirement::kPageCapture)); } const GURL active_tab_extension_urls[] = { @@ -1223,11 +1278,27 @@ for (const GURL& url : active_tab_extension_urls) { SCOPED_TRACE(url); - EXPECT_FALSE(CanCapture(active_tab(), url)); - GrantActiveTab(url); - EXPECT_TRUE(CanCapture(active_tab(), url)); - ClearActiveTab(); - EXPECT_FALSE(CanCapture(active_tab(), url)); + EXPECT_FALSE( + CanCapture(active_tab(), url, + extensions::CaptureRequirement::kActiveTabOrAllUrls)); + GrantActiveTab(active_tab(), url); + EXPECT_TRUE( + CanCapture(active_tab(), url, + extensions::CaptureRequirement::kActiveTabOrAllUrls)); + ClearActiveTab(active_tab()); + EXPECT_FALSE( + CanCapture(active_tab(), url, + extensions::CaptureRequirement::kActiveTabOrAllUrls)); + } + const GURL page_capture_extension_urls[] = { + page_capture().GetResourceURL("foo.html"), + }; + + for (const GURL& url : page_capture_extension_urls) { + SCOPED_TRACE(url); + + EXPECT_TRUE(CanCapture(page_capture(), url, + extensions::CaptureRequirement::kPageCapture)); } } @@ -1246,13 +1317,29 @@ for (const GURL& url : test_urls) { SCOPED_TRACE(url); - EXPECT_FALSE(CanCapture(all_urls(), url)); + EXPECT_FALSE(CanCapture( + all_urls(), url, extensions::CaptureRequirement::kActiveTabOrAllUrls)); - EXPECT_FALSE(CanCapture(active_tab(), url)); - GrantActiveTab(url); - EXPECT_FALSE(CanCapture(active_tab(), url)); - ClearActiveTab(); - EXPECT_FALSE(CanCapture(active_tab(), url)); + EXPECT_FALSE( + CanCapture(active_tab(), url, + extensions::CaptureRequirement::kActiveTabOrAllUrls)); + GrantActiveTab(active_tab(), url); + EXPECT_FALSE( + CanCapture(active_tab(), url, + extensions::CaptureRequirement::kActiveTabOrAllUrls)); + ClearActiveTab(active_tab()); + EXPECT_FALSE( + CanCapture(active_tab(), url, + extensions::CaptureRequirement::kActiveTabOrAllUrls)); + + EXPECT_FALSE(CanCapture(page_capture(), url, + extensions::CaptureRequirement::kPageCapture)); + GrantActiveTab(page_capture(), url); + EXPECT_FALSE(CanCapture(page_capture(), url, + extensions::CaptureRequirement::kPageCapture)); + ClearActiveTab(page_capture()); + EXPECT_FALSE(CanCapture(page_capture(), url, + extensions::CaptureRequirement::kPageCapture)); } }
diff --git a/chrome/common/page_load_metrics/test/page_load_metrics_test_util.cc b/chrome/common/page_load_metrics/test/page_load_metrics_test_util.cc index ac9dada..87f961d 100644 --- a/chrome/common/page_load_metrics/test/page_load_metrics_test_util.cc +++ b/chrome/common/page_load_metrics/test/page_load_metrics_test_util.cc
@@ -4,7 +4,6 @@ #include "chrome/common/page_load_metrics/test/page_load_metrics_test_util.h" -#include "chrome/common/page_load_metrics/page_load_metrics.mojom.h" #include "chrome/common/page_load_metrics/page_load_metrics_util.h" using page_load_metrics::OptionalMin; @@ -85,3 +84,39 @@ } } } + +page_load_metrics::mojom::ResourceDataUpdatePtr CreateResource( + bool was_cached, + int64_t delta_bytes, + int64_t delta_body_bytes, + int64_t encoded_body_length, + bool is_complete) { + auto resource_data_update = + page_load_metrics::mojom::ResourceDataUpdate::New(); + resource_data_update->was_fetched_via_cache = was_cached; + resource_data_update->delta_bytes = delta_bytes; + resource_data_update->encoded_body_length = encoded_body_length; + resource_data_update->is_complete = is_complete; + return resource_data_update; +} + +std::vector<page_load_metrics::mojom::ResourceDataUpdatePtr> +GetSampleResourceDataUpdateForTesting(int64_t resource_size) { + // Prepare 3 resources of varying configurations. + std::vector<page_load_metrics::mojom::ResourceDataUpdatePtr> resources; + // Cached resource. + resources.push_back(CreateResource( + true /* was_cached */, 0 /* delta_bytes */, 0 /* delta_body_bytes */, + resource_size /* encoded_body_length */, true /* is_complete */)); + // Uncached resource. + resources.push_back(CreateResource( + false /* was_cached */, resource_size /* delta_bytes */, + resource_size /* delta_body_bytes */, + resource_size /* encoded_body_length */, true /* is_complete */)); + // Uncached, unfinished, resource. + resources.push_back( + CreateResource(false /* was_cached */, resource_size /* delta_bytes */, + resource_size /* delta_body_bytes */, + 0 /* encoded_body_length */, false /* is_complete */)); + return resources; +}
diff --git a/chrome/common/page_load_metrics/test/page_load_metrics_test_util.h b/chrome/common/page_load_metrics/test/page_load_metrics_test_util.h index cd0d9c1a..6ff84fe 100644 --- a/chrome/common/page_load_metrics/test/page_load_metrics_test_util.h +++ b/chrome/common/page_load_metrics/test/page_load_metrics_test_util.h
@@ -5,15 +5,27 @@ #ifndef CHROME_COMMON_PAGE_LOAD_METRICS_TEST_PAGE_LOAD_METRICS_TEST_UTIL_H_ #define CHROME_COMMON_PAGE_LOAD_METRICS_TEST_PAGE_LOAD_METRICS_TEST_UTIL_H_ -namespace page_load_metrics { -namespace mojom { -class PageLoadTiming; -} // namespace mojom -} // namespace page_load_metrics +#include <stdint.h> + +#include <vector> + +#include "chrome/common/page_load_metrics/page_load_metrics.mojom.h" // Helper that fills in any timing fields that page load metrics requires but // that are currently missing. void PopulateRequiredTimingFields( page_load_metrics::mojom::PageLoadTiming* inout_timing); +// Helper that create a resource update mojo. +page_load_metrics::mojom::ResourceDataUpdatePtr CreateResource( + bool was_cached, + int64_t delta_bytes, + int64_t encoded_body_length, + bool is_complete); + +// Helper that returns a sample resource data update using a variety of +// configurations. +std::vector<page_load_metrics::mojom::ResourceDataUpdatePtr> +GetSampleResourceDataUpdateForTesting(int64_t resource_size); + #endif // CHROME_COMMON_PAGE_LOAD_METRICS_TEST_PAGE_LOAD_METRICS_TEST_UTIL_H_
diff --git a/chrome/common/safe_browsing/BUILD.gn b/chrome/common/safe_browsing/BUILD.gn index ff231da..d96e5f17c 100644 --- a/chrome/common/safe_browsing/BUILD.gn +++ b/chrome/common/safe_browsing/BUILD.gn
@@ -76,6 +76,7 @@ ":file_type_policies", "//base", "//base:i18n", + "//components/safe_browsing:features", "//third_party/unrar:unrar", ]
diff --git a/chrome/common/safe_browsing/rar_analyzer.cc b/chrome/common/safe_browsing/rar_analyzer.cc index 996c0164..1d352338 100644 --- a/chrome/common/safe_browsing/rar_analyzer.cc +++ b/chrome/common/safe_browsing/rar_analyzer.cc
@@ -6,6 +6,7 @@ #include <memory> #include <string> +#include "base/feature_list.h" #include "base/files/file_path.h" #include "base/i18n/streaming_utf8_validator.h" #include "base/metrics/histogram_macros.h" @@ -13,20 +14,26 @@ #include "chrome/common/safe_browsing/archive_analyzer_results.h" #include "chrome/common/safe_browsing/download_type_util.h" #include "chrome/common/safe_browsing/file_type_policies.h" +#include "components/safe_browsing/features.h" #include "third_party/unrar/src/unrar_wrapper.h" namespace safe_browsing { namespace rar_analyzer { void AnalyzeRarFile(base::File rar_file, + base::File temp_file, ArchiveAnalyzerResults* results) { + results->success = false; auto archive = std::make_unique<third_party_unrar::Archive>(); archive->SetFileHandle(rar_file.GetPlatformFile()); + if (base::FeatureList::IsEnabled(kInspectRarContentFeature)) { + archive->SetTempFileHandle(temp_file.GetPlatformFile()); + } + bool open_success = archive->Open(L"dummy.rar"); UMA_HISTOGRAM_BOOLEAN("SBClientDownload.RarOpenSuccess", open_success); if (!open_success) { - results->success = false; DLOG(ERROR) << __FUNCTION__ << ": Unable to open rar_file: " << rar_file.GetPlatformFile(); return; @@ -35,60 +42,94 @@ bool is_valid_archive = archive->IsArchive(/*EnableBroken=*/true); UMA_HISTOGRAM_BOOLEAN("SBClientDownload.RarValidArchive", is_valid_archive); if (!is_valid_archive) { - results->success = false; DLOG(ERROR) << __FUNCTION__ << ": !IsArchive: rar_file: " << rar_file.GetPlatformFile(); return; } - results->success = true; - std::set<base::FilePath> archived_archive_filenames; - for (archive->ViewComment(); - archive->ReadHeader() > 0 && - archive->GetHeaderType() != third_party_unrar::kUnrarEndarcHead; - archive->SeekToNext()) { - std::wstring wide_filename(archive->FileHead.FileName); + if (base::FeatureList::IsEnabled(kInspectRarContentFeature)) { + auto command = std::make_unique<third_party_unrar::CommandData>(); + command->ParseArg(const_cast<wchar_t*>(L"-p")); + command->ParseArg(const_cast<wchar_t*>(L"x")); + command->ParseDone(); + + third_party_unrar::CmdExtract extractor(command.get()); + extractor.ExtractArchiveInit(*archive); + bool failed = false, repeat = true; + while (!failed || repeat) { + // Clear the |temp_file| between extractions. + temp_file.Seek(base::File::Whence::FROM_BEGIN, 0); + temp_file.SetLength(0); + size_t header_size = archive->ReadHeader(); + repeat = false; + failed = !extractor.ExtractCurrentFile( + *archive, header_size, repeat); // |repeat| is passed by reference + + if (archive->GetHeaderType() == third_party_unrar::kUnrarFileHead) { + std::wstring wide_filename(archive->FileHead.FileName); #if defined(OS_WIN) - base::FilePath file_path(wide_filename); + base::FilePath file_path(wide_filename); #else - std::string filename(wide_filename.begin(), wide_filename.end()); - base::FilePath file_path(filename); + std::string filename(wide_filename.begin(), wide_filename.end()); + base::FilePath file_path(filename); #endif // OS_WIN - bool is_executable = - FileTypePolicies::GetInstance()->IsCheckedBinaryFile(file_path); - bool is_archive = FileTypePolicies::GetInstance()->IsArchiveFile(file_path); - int64 unpacked_size = - archive->FileHead.UnpSize; // Read from header, may not be accurate. - // TODO(vakh): Log UMA if |unpacked_size| < 0. - - base::FilePath basename = file_path.BaseName(); - std::string basename_utf8(basename.AsUTF8Unsafe()); - bool is_utf8_valid_basename = - base::StreamingUtf8Validator::Validate(basename_utf8); - - if (is_archive) { - results->has_archive = true; - archived_archive_filenames.insert(basename); - ClientDownloadRequest::ArchivedBinary* archived_archive = - results->archived_binary.Add(); - if (is_utf8_valid_basename) - archived_archive->set_file_basename(basename_utf8); - archived_archive->set_download_type(ClientDownloadRequest::ARCHIVE); - archived_archive->set_length(unpacked_size); - } else if (is_executable) { - results->has_executable = true; - ClientDownloadRequest::ArchivedBinary* archived_binary = - results->archived_binary.Add(); - if (is_utf8_valid_basename) - archived_binary->set_file_basename(basename_utf8); - archived_binary->set_download_type( - download_type_util::GetDownloadType(file_path)); - archived_binary->set_length(unpacked_size); + UpdateArchiveAnalyzerResultsWithFile( + file_path, &temp_file, archive->FileHead.Encrypted, results); + } } - results->archived_archive_filenames.assign( - archived_archive_filenames.begin(), archived_archive_filenames.end()); + } else { + std::set<base::FilePath> archived_archive_filenames; + for (archive->ViewComment(); + archive->ReadHeader() > 0 && + archive->GetHeaderType() != third_party_unrar::kUnrarEndarcHead; + archive->SeekToNext()) { + std::wstring wide_filename(archive->FileHead.FileName); +#if defined(OS_WIN) + base::FilePath file_path(wide_filename); +#else + std::string filename(wide_filename.begin(), wide_filename.end()); + base::FilePath file_path(filename); +#endif // OS_WIN + + bool is_executable = + FileTypePolicies::GetInstance()->IsCheckedBinaryFile(file_path); + bool is_archive = + FileTypePolicies::GetInstance()->IsArchiveFile(file_path); + int64 unpacked_size = + archive->FileHead.UnpSize; // Read from header, may not be accurate. + // TODO(vakh): Log UMA if |unpacked_size| < 0. + + base::FilePath basename = file_path.BaseName(); + std::string basename_utf8(basename.AsUTF8Unsafe()); + bool is_utf8_valid_basename = + base::StreamingUtf8Validator::Validate(basename_utf8); + + if (is_archive) { + results->has_archive = true; + archived_archive_filenames.insert(basename); + ClientDownloadRequest::ArchivedBinary* archived_archive = + results->archived_binary.Add(); + if (is_utf8_valid_basename) + archived_archive->set_file_basename(basename_utf8); + archived_archive->set_download_type(ClientDownloadRequest::ARCHIVE); + archived_archive->set_length(unpacked_size); + } else if (is_executable) { + results->has_executable = true; + ClientDownloadRequest::ArchivedBinary* archived_binary = + results->archived_binary.Add(); + if (is_utf8_valid_basename) + archived_binary->set_file_basename(basename_utf8); + archived_binary->set_download_type( + download_type_util::GetDownloadType(file_path)); + archived_binary->set_length(unpacked_size); + } + results->archived_archive_filenames.assign( + archived_archive_filenames.begin(), archived_archive_filenames.end()); + } } + + results->success = true; } } // namespace rar_analyzer
diff --git a/chrome/common/safe_browsing/rar_analyzer.h b/chrome/common/safe_browsing/rar_analyzer.h index c1a3b49..0952cca 100644 --- a/chrome/common/safe_browsing/rar_analyzer.h +++ b/chrome/common/safe_browsing/rar_analyzer.h
@@ -29,14 +29,16 @@ namespace rar_analyzer { -// |rar_file| is a platform-agnostic handle to the file. Since |AnalyzeRarFile| -// runs inside a sandbox, it isn't allowed to open file handles. So the file is -// opened in |SandboxedRarAnalyzer|, which runs in the browser process, and the -// handle is passed here. The function populates the various fields in |results| -// based on the results of parsing the rar file. -// If the parsing fails for any reason, including crashing the sandbox process, -// the browser process considers the file safe. +// |rar_file| is a platform-agnostic handle to the file, and |temp_file| is a +// handle for a temporary file the sandbox can write to. Since |AnalyzeRarFile| +// runs inside a sandbox, it isn't allowed to open file handles. So both files +// are opened in |SandboxedRarAnalyzer|, which runs in the browser process, and +// the handles are passed here. The function populates the various fields in +// |results| based on the results of parsing the rar file. If the parsing fails +// for any reason, including crashing the sandbox process, the browser process +// considers the file safe. void AnalyzeRarFile(base::File rar_file, + base::File temp_file, ArchiveAnalyzerResults* results); } // namespace rar_analyzer
diff --git a/chrome/services/file_util/DEPS b/chrome/services/file_util/DEPS index e480585..32919248 100644 --- a/chrome/services/file_util/DEPS +++ b/chrome/services/file_util/DEPS
@@ -1,5 +1,6 @@ include_rules = [ "+components/services/filesystem", "+chrome/utility/safe_browsing", + "+components/safe_browsing", "+third_party/zlib/google", ]
diff --git a/chrome/services/file_util/public/cpp/sandboxed_rar_analyzer.cc b/chrome/services/file_util/public/cpp/sandboxed_rar_analyzer.cc index 2dd8820..9cad8757 100644 --- a/chrome/services/file_util/public/cpp/sandboxed_rar_analyzer.cc +++ b/chrome/services/file_util/public/cpp/sandboxed_rar_analyzer.cc
@@ -39,7 +39,7 @@ SandboxedRarAnalyzer::~SandboxedRarAnalyzer() = default; -void SandboxedRarAnalyzer::AnalyzeFile(base::File file) { +void SandboxedRarAnalyzer::AnalyzeFile(base::File file, base::File temp_file) { DCHECK_CURRENTLY_ON(content::BrowserThread::UI); DCHECK(!analyzer_ptr_); DCHECK(!file_path_.value().empty()); @@ -50,7 +50,7 @@ &SandboxedRarAnalyzer::AnalyzeFileDone, base::Unretained(this), safe_browsing::ArchiveAnalyzerResults())); analyzer_ptr_->AnalyzeRarFile( - std::move(file), + std::move(file), std::move(temp_file), base::BindOnce(&SandboxedRarAnalyzer::AnalyzeFileDone, this)); } @@ -77,9 +77,25 @@ return; } - base::PostTaskWithTraits(FROM_HERE, {content::BrowserThread::UI}, - base::BindOnce(&SandboxedRarAnalyzer::AnalyzeFile, - this, std::move(file))); + base::FilePath temp_path; + base::File temp_file; + if (base::CreateTemporaryFile(&temp_path)) { + temp_file.Initialize( + temp_path, (base::File::FLAG_CREATE_ALWAYS | base::File::FLAG_READ | + base::File::FLAG_WRITE | base::File::FLAG_TEMPORARY | + base::File::FLAG_DELETE_ON_CLOSE)); + } + + if (!temp_file.IsValid()) { + DLOG(ERROR) << "Could not open temp file: " << temp_path.value(); + ReportFileFailure(); + return; + } + + base::PostTaskWithTraits( + FROM_HERE, {content::BrowserThread::UI}, + base::BindOnce(&SandboxedRarAnalyzer::AnalyzeFile, this, std::move(file), + std::move(temp_file))); } void SandboxedRarAnalyzer::ReportFileFailure() {
diff --git a/chrome/services/file_util/public/cpp/sandboxed_rar_analyzer.h b/chrome/services/file_util/public/cpp/sandboxed_rar_analyzer.h index 295347b2f..fb10f7ab 100644 --- a/chrome/services/file_util/public/cpp/sandboxed_rar_analyzer.h +++ b/chrome/services/file_util/public/cpp/sandboxed_rar_analyzer.h
@@ -49,8 +49,9 @@ // If file preparation failed, analysis has failed: report failure. void ReportFileFailure(); - // Starts the utility process and sends it a file analyze request. - void AnalyzeFile(base::File file); + // Starts the utility process and sends it a request to analyze the file + // |file|, given a handle for |temp_file|, where it can extract files. + void AnalyzeFile(base::File file, base::File temp_file); // The response containing the file analyze results. void AnalyzeFileDone(const safe_browsing::ArchiveAnalyzerResults& results);
diff --git a/chrome/services/file_util/public/cpp/sandboxed_rar_analyzer_unittest.cc b/chrome/services/file_util/public/cpp/sandboxed_rar_analyzer_unittest.cc index 55dd9c6..6e98bcd 100644 --- a/chrome/services/file_util/public/cpp/sandboxed_rar_analyzer_unittest.cc +++ b/chrome/services/file_util/public/cpp/sandboxed_rar_analyzer_unittest.cc
@@ -12,15 +12,19 @@ #include "base/path_service.h" #include "base/run_loop.h" #include "base/strings/utf_string_conversions.h" +#include "base/test/scoped_feature_list.h" +#include "build/build_config.h" #include "chrome/common/chrome_paths.h" #include "chrome/common/safe_browsing/archive_analyzer_results.h" #include "chrome/services/file_util/file_util_service.h" #include "chrome/services/file_util/public/mojom/constants.mojom.h" +#include "components/safe_browsing/features.h" #include "content/public/test/test_browser_thread_bundle.h" #include "content/public/test/test_utils.h" #include "services/service_manager/public/cpp/test/test_connector_factory.h" #include "testing/gtest/include/gtest/gtest.h" +namespace safe_browsing { namespace { #define CDRDT(x) safe_browsing::ClientDownloadRequest_DownloadType_##x @@ -31,6 +35,8 @@ struct BinaryData { const char* file_basename; safe_browsing::ClientDownloadRequest_DownloadType download_type; + bool has_signature; + bool has_image_headers; int64_t length; }; @@ -69,6 +75,7 @@ ASSERT_FALSE(binary.has_digests()); ASSERT_TRUE(binary.has_length()); EXPECT_EQ(data.length, binary.length()); + ASSERT_FALSE(binary.has_signature()); ASSERT_FALSE(binary.has_image_headers()); } @@ -110,17 +117,23 @@ const SandboxedRarAnalyzerTest::BinaryData SandboxedRarAnalyzerTest::kEmptyZip = { - "empty.zip", CDRDT(ARCHIVE), 22, + "empty.zip", CDRDT(ARCHIVE), false, false, 22, }; const SandboxedRarAnalyzerTest::BinaryData SandboxedRarAnalyzerTest::kNotARar = { - "not_a_rar.rar", CDRDT(ARCHIVE), 18, + "not_a_rar.rar", CDRDT(ARCHIVE), false, false, 18, }; const SandboxedRarAnalyzerTest::BinaryData SandboxedRarAnalyzerTest::kSignedExe = { - "signed.exe", CDRDT(WIN_EXECUTABLE), 37768, + "signed.exe", CDRDT(WIN_EXECUTABLE), +#if defined(OS_WIN) + true, true, +#else + false, false, +#endif + 37768, }; TEST_F(SandboxedRarAnalyzerTest, AnalyzeBenignRar) { @@ -220,4 +233,44 @@ results.archived_archive_filenames[1].value()); } +TEST_F(SandboxedRarAnalyzerTest, + AnalyzeRarContainingExecutableWithContentInspection) { + base::test::ScopedFeatureList feature_list; + feature_list.InitAndEnableFeature(kInspectRarContentFeature); + + // Can detect when .rar contains executable files. + // has_exe.rar contains 1 file: signed.exe + base::FilePath path; + ASSERT_NO_FATAL_FAILURE(path = GetFilePath("has_exe.rar")); + + safe_browsing::ArchiveAnalyzerResults results; + AnalyzeFile(path, &results); + + ASSERT_TRUE(results.success); + EXPECT_TRUE(results.has_executable); + EXPECT_EQ(1, results.archived_binary.size()); + EXPECT_TRUE(results.archived_archive_filenames.empty()); + + const safe_browsing::ClientDownloadRequest_ArchivedBinary& binary = + results.archived_binary.Get(0); + ASSERT_TRUE(binary.has_file_basename()); + EXPECT_EQ(kSignedExe.file_basename, binary.file_basename()); + ASSERT_TRUE(binary.has_download_type()); + EXPECT_EQ(kSignedExe.download_type, binary.download_type()); + // If we're doing content inspection, we expect to have digests. + ASSERT_TRUE(binary.has_digests()); + ASSERT_TRUE(binary.has_length()); + EXPECT_EQ(kSignedExe.length, binary.length()); + +#if defined(OS_WIN) + // On windows, we should also have a signature and image header + ASSERT_TRUE(binary.has_signature()); + ASSERT_TRUE(binary.has_image_headers()); +#else + ASSERT_FALSE(binary.has_signature()); + ASSERT_FALSE(binary.has_image_headers()); +#endif +} + } // namespace +} // namespace safe_browsing
diff --git a/chrome/services/file_util/public/mojom/safe_archive_analyzer.mojom b/chrome/services/file_util/public/mojom/safe_archive_analyzer.mojom index 6983f7b..2661603 100644 --- a/chrome/services/file_util/public/mojom/safe_archive_analyzer.mojom +++ b/chrome/services/file_util/public/mojom/safe_archive_analyzer.mojom
@@ -24,8 +24,10 @@ => (SafeArchiveAnalyzerResults results); // Build flag FULL_SAFE_BROWSING: Analyze the |rar_file| for malicious - // download protection. - AnalyzeRarFile(mojo_base.mojom.File rar_file) + // download protection. Uses the |temporary_file| to extract files from the + // |rar_file| archive. + AnalyzeRarFile(mojo_base.mojom.File rar_file, + mojo_base.mojom.File temporary_file) => (SafeArchiveAnalyzerResults results); };
diff --git a/chrome/services/file_util/safe_archive_analyzer.cc b/chrome/services/file_util/safe_archive_analyzer.cc index a13b42b1..a58249e8 100644 --- a/chrome/services/file_util/safe_archive_analyzer.cc +++ b/chrome/services/file_util/safe_archive_analyzer.cc
@@ -46,10 +46,12 @@ } void SafeArchiveAnalyzer::AnalyzeRarFile(base::File rar_file, + base::File temporary_file, AnalyzeRarFileCallback callback) { DCHECK(rar_file.IsValid()); safe_browsing::ArchiveAnalyzerResults results; - safe_browsing::rar_analyzer::AnalyzeRarFile(std::move(rar_file), &results); + safe_browsing::rar_analyzer::AnalyzeRarFile( + std::move(rar_file), std::move(temporary_file), &results); std::move(callback).Run(results); }
diff --git a/chrome/services/file_util/safe_archive_analyzer.h b/chrome/services/file_util/safe_archive_analyzer.h index f21efa6..94d6ec0e 100644 --- a/chrome/services/file_util/safe_archive_analyzer.h +++ b/chrome/services/file_util/safe_archive_analyzer.h
@@ -26,6 +26,7 @@ void AnalyzeDmgFile(base::File dmg_file, AnalyzeDmgFileCallback callback) override; void AnalyzeRarFile(base::File rar_file, + base::File temporary_file, AnalyzeRarFileCallback callback) override; const std::unique_ptr<service_manager::ServiceContextRef> service_ref_;
diff --git a/chrome/test/chromedriver/VERSION b/chrome/test/chromedriver/VERSION index f454b81..85750d2 100644 --- a/chrome/test/chromedriver/VERSION +++ b/chrome/test/chromedriver/VERSION
@@ -1 +1 @@ -2.44 +2.45
diff --git a/chrome/test/data/extensions/api_test/page_capture/test.js b/chrome/test/data/extensions/api_test/page_capture/test.js index bc911eb..afdf427 100644 --- a/chrome/test/data/extensions/api_test/page_capture/test.js +++ b/chrome/test/data/extensions/api_test/page_capture/test.js
@@ -7,20 +7,48 @@ const assertEq = chrome.test.assertEq; const assertTrue = chrome.test.assertTrue; +const fail = chrome.test.callbackFail; +const pass = chrome.test.callbackPass; var testUrl = 'http://www.a.com:PORT' + '/extensions/api_test/page_capture/google.html'; function waitForCurrentTabLoaded(callback) { chrome.tabs.getSelected(null, function(tab) { - if (tab.status == "complete" && tab.url == testUrl) { + if (tab.status == 'complete') { callback(); return; } - window.setTimeout(function() { waitForCurrentTabLoaded(callback); }, 100); + window.setTimeout(function() { + waitForCurrentTabLoaded(callback); + }, 100); }); } +function testPageCapture(data, isFile) { + assertEq(undefined, chrome.runtime.lastError); + assertTrue(data != null); + // It should contain few KBs of data. + assertTrue(data.size > 100); + var reader = new FileReader(); + // Let's make sure it contains some well known strings. + reader.onload = function(e) { + if (!isFile) { + var text = e.target.result; + assertTrue(text.indexOf(testUrl) != -1); + assertTrue(text.indexOf('logo.png') != -1); + } + // Run the GC so the blob is deleted. + window.setTimeout(function() { + window.gc(); + }); + window.setTimeout(function() { + chrome.test.notifyPass(); + }, 0); + }; + reader.readAsText(data); +} + chrome.test.getConfig(function(config) { testUrl = testUrl.replace(/PORT/, config.testServer.port); @@ -28,33 +56,50 @@ function saveAsMHTML() { chrome.tabs.getSelected(null, function(tab) { chrome.tabs.update(null, { "url": testUrl }); + waitForCurrentTabLoaded(pass(function() { + chrome.pageCapture.saveAsMHTML( + {'tabId': tab.id}, pass(function(data) { + if (config.customArg == 'REQUEST_DENIED') { + chrome.test.assertLastError('User denied request.'); + chrome.test.notifyPass(); + return; + } + testPageCapture(data, false /* isFile */); + })); + })); + }); + }, + + function saveAsMHTMLFile() { + chrome.tabs.getSelected(null, function(tab) { + chrome.tabs.update(null, {'url': config.testDataDirectory}); waitForCurrentTabLoaded(function() { - chrome.pageCapture.saveAsMHTML({ "tabId": tab.id }, - function(data) { - if (config.customArg == "REQUEST_DENIED") { - chrome.test.assertLastError("User denied request."); - chrome.test.notifyPass(); - return; - } - assertEq(undefined, chrome.runtime.lastError); - assertTrue(data != null); - // It should contain few KBs of data. - assertTrue(data.size > 100); - // Let's make sure it contains some well known strings. - var reader = new FileReader(); - reader.onload = function(e) { - var text = e.target.result; - assertTrue(text.indexOf(testUrl) != -1); - assertTrue(text.indexOf("logo.png") != -1); - // Run the GC so the blob is deleted. - window.setTimeout(function() { window.gc(); }); - window.setTimeout(function() { chrome.test.notifyPass(); }, 0); - }; - reader.readAsText(data); - }); + if (config.customArg == 'REQUEST_DENIED') { + chrome.pageCapture.saveAsMHTML( + {'tabId': tab.id}, fail('User denied request.', function(data) { + chrome.test.assertLastError('User denied request.'); + chrome.test.notifyPass(); + return; + })); + } else if (config.customArg == 'ONLY_PAGE_CAPTURE_PERMISSION') { + chrome.pageCapture.saveAsMHTML( + {'tabId': tab.id}, + fail( + 'Don\'t have permissions required to capture this page.', + function(data) { + chrome.test.assertLastError( + 'Don\'t have permissions required to capture this ' + + 'page.'); + return; + })); + } else { + chrome.pageCapture.saveAsMHTML( + {'tabId': tab.id}, pass(function(data) { + testPageCapture(data, true /* isFile */); + })); + } }); }); } ]); }); -
diff --git a/chrome/test/data/webrtc/munge_sdp.js b/chrome/test/data/webrtc/munge_sdp.js index d0781a7..bd3cc72 100644 --- a/chrome/test/data/webrtc/munge_sdp.js +++ b/chrome/test/data/webrtc/munge_sdp.js
@@ -8,14 +8,15 @@ * See |setSdpDefaultCodec|. */ function setSdpDefaultAudioCodec(sdp, codec) { - return setSdpDefaultCodec(sdp, 'audio', codec, false /* preferHwCodec */); + return setSdpDefaultCodec( + sdp, 'audio', codec, false /* preferHwCodec */, null /* profile */); } /** * See |setSdpDefaultCodec|. */ -function setSdpDefaultVideoCodec(sdp, codec, preferHwCodec) { - return setSdpDefaultCodec(sdp, 'video', codec, preferHwCodec); +function setSdpDefaultVideoCodec(sdp, codec, preferHwCodec, profile) { + return setSdpDefaultCodec(sdp, 'video', codec, preferHwCodec, profile); } /** @@ -53,22 +54,24 @@ } /** - * Returns a modified version of |sdp| where the |codec| has been promoted to be - * the default codec, i.e. the codec whose ID is first in the list of codecs on - * the 'm=|type|' line, where |type| is 'audio' or 'video'. + * Returns a modified version of |sdp| where the |codec| with |profile| has been + * promoted to be the default codec, i.e. the codec whose ID is first in the + * list of codecs on the 'm=|type|' line, where |type| is 'audio' or 'video'. * @private */ -function setSdpDefaultCodec(sdp, type, codec, preferHwCodec) { +function setSdpDefaultCodec(sdp, type, codec, preferHwCodec, profile) { var sdpLines = splitSdpLines(sdp); // Find codec ID, e.g. 100 for 'VP8' if 'a=rtpmap:100 VP8/9000'. // TODO(magjed): We need a more stable order of the video codecs, e.g. that HW // codecs are always listed before SW codecs. var useLastInstance = !preferHwCodec; - var codecId = findRtpmapId(sdpLines, codec, useLastInstance); + var codecId = findRtpmapId(sdpLines, codec, useLastInstance, profile); if (codecId === null) { - failure('setSdpDefaultCodec', - 'Unknown ID for |codec| = \'' + codec + '\'.'); + failure( + 'setSdpDefaultCodec', + 'Unknown ID for |codec| = \'' + codec + '\' and |profile| = \'' + + profile + '\'.'); } // Find 'm=|type|' line, e.g. 'm=video 9 UDP/TLS/RTP/SAVPF 100 101 107 116'. @@ -132,15 +135,15 @@ /** * Searches through all |sdpLines| for the 'a=rtpmap:' line for the codec of * the specified name, returning its ID as an int if found, or null otherwise. - * |codec| is the case-sensitive name of the codec. If |lastInstance| - * is true, it will return the last such ID, and if false, it will return the - * first such ID. + * |codec| is the case-sensitive name of the codec. |profile| is the profile + * specifier for the codec. If |lastInstance| is true, it will return the last + * such ID, and if false, it will return the first such ID. * For example, if |sdpLines| contains 'a=rtpmap:100 VP8/9000' and |codec| is * 'VP8', this function returns 100. * @private */ -function findRtpmapId(sdpLines, codec, lastInstance) { - var lineNo = findRtpmapLine(sdpLines, codec, lastInstance); +function findRtpmapId(sdpLines, codec, lastInstance, profile) { + var lineNo = findRtpmapLine(sdpLines, codec, lastInstance, profile); if (lineNo === null) return null; // Parse <id> from 'a=rtpmap:<id> <codec>/<rate>'. @@ -168,22 +171,23 @@ } /** - * Finds a 'a=rtpmap:' line from |sdpLines| that contains |contains| and returns - * its line index, or null if no such line was found. |contains| may be the - * codec ID, codec name or bitrate. If |lastInstance| is true, it will return - * the last such line index, and if false, it will return the first such line - * index. - * An 'a=rtpmap:' line looks like this: 'a=rtpmap:<id> <codec>/<rate>'. + * Finds a 'a=rtpmap:' line from |sdpLines| that contains |contains| (and + * contains |optionalContains| in the following codec lines when given) and + * returns its line index, or null if no such line was found. |contains| and + * |optionalContains| may be the codec ID, codec name, bitrate or profile. If + * |lastInstance| is true, it will return the last such line index, and if + * false, it will return the first such line index. An 'a=rtpmap:' line looks + * like this: 'a=rtpmap:<id> <codec>/<rate>'. */ -function findRtpmapLine(sdpLines, contains, lastInstance) { +function findRtpmapLine(sdpLines, contains, lastInstance, optionalContains) { if (lastInstance === true) { for (var i = sdpLines.length - 1; i >= 0 ; i--) { - if (isRtpmapLine(sdpLines[i], contains)) + if (isRtpmapLineWithProfile(sdpLines, i, contains, optionalContains)) return i; } } else { for (var i = 0; i < sdpLines.length; i++) { - if (isRtpmapLine(sdpLines[i], contains)) + if (isRtpmapLineWithProfile(sdpLines, i, contains, optionalContains)) return i; } } @@ -191,13 +195,33 @@ } /** + * Returns true if the given |lineIndex| is the start of a codec lines block + * where sdpLines[lineIndex] satisfies the requirements for isRtpmapLine() and + * there is a line following which contains |profileContains| if given. + */ +function isRtpmapLineWithProfile( + sdpLines, lineIndex, contains, profileContains = undefined) { + if (!isRtpmapLine(sdpLines[lineIndex], contains)) + return false; + + if (profileContains === null || profileContains === undefined) + return true; + var j = lineIndex + 1; + while (j < sdpLines.length && sdpLines[j].indexOf('rtpmap:') == -1) { + if (sdpLines[j].indexOf(profileContains) != -1) + return true; + j++; + } + return false; +} + +/** * Returns true if |sdpLine| contains |contains| and is of pattern * 'a=rtpmap:<id> <codec>/<rate>'. */ function isRtpmapLine(sdpLine, contains) { // Is 'a=rtpmap:' line containing |contains| string? - if (sdpLine.startsWith('a=rtpmap:') && - sdpLine.indexOf(contains) != -1) { + if (sdpLine.startsWith('a=rtpmap:') && sdpLine.indexOf(contains) != -1) { // Expecting pattern 'a=rtpmap:<id> <codec>/<rate>'. var pattern = new RegExp('a=rtpmap:(\\d+) \\w+\\/\\d+'); if (!sdpLine.match(pattern))
diff --git a/chrome/test/data/webrtc/peerconnection.js b/chrome/test/data/webrtc/peerconnection.js index 13b7d77..2389198 100644 --- a/chrome/test/data/webrtc/peerconnection.js +++ b/chrome/test/data/webrtc/peerconnection.js
@@ -41,6 +41,12 @@ var gDefaultVideoCodec = null; /** + * The default video codec profile that should be used when creating an offer. + * @private + */ +var gDefaultVideoCodecProfile = null; + +/** * Flag to indicate if HW or SW video codec is preferred. * @private */ @@ -138,14 +144,16 @@ * video codec, e.g. the first one in the list on the 'm=video' SDP offer * line. |videoCodec| is the case-sensitive codec name, e.g. 'VP8' or * 'H264'. + * @param {string} profile promotes the specified codec profile. * @param {bool} preferHwVideoCodec specifies what codec to use from the * 'm=video' line when there are multiple codecs with the name |videoCodec|. * If true, it will return the last codec with that name, and if false, it * will return the first codec with that name. */ -function setDefaultVideoCodec(videoCodec, preferHwVideoCodec) { +function setDefaultVideoCodec(videoCodec, preferHwVideoCodec, profile) { gDefaultVideoCodec = videoCodec; gDefaultPreferHwVideoCodec = preferHwVideoCodec; + gDefaultVideoCodecProfile = profile; returnToTest('ok'); } @@ -176,9 +184,9 @@ gDefaultAudioCodec); } if (gDefaultVideoCodec !== null) { - localOffer.sdp = setSdpDefaultVideoCodec(localOffer.sdp, - gDefaultVideoCodec, - gDefaultPreferHwVideoCodec); + localOffer.sdp = setSdpDefaultVideoCodec( + localOffer.sdp, gDefaultVideoCodec, gDefaultPreferHwVideoCodec, + gDefaultVideoCodecProfile); } if (gOpusDtx) { localOffer.sdp = setOpusDtxEnabled(localOffer.sdp);
diff --git a/chrome/test/data/webui/cr_components/cr_components_browsertest.js b/chrome/test/data/webui/cr_components/cr_components_browsertest.js index 0ba829a1..5a4cf25 100644 --- a/chrome/test/data/webui/cr_components/cr_components_browsertest.js +++ b/chrome/test/data/webui/cr_components/cr_components_browsertest.js
@@ -40,6 +40,29 @@ }, }; +/** + * @constructor + * @extends {CrComponentsBrowserTest} + */ +function CrComponentsManagedFootnoteTest() {} + +CrComponentsManagedFootnoteTest.prototype = { + __proto__: CrComponentsBrowserTest.prototype, + + /** @override */ + browsePreload: + 'chrome://resources/cr_components/managed_footnote/managed_footnote.html', + + /** @override */ + extraLibraries: CrComponentsBrowserTest.prototype.extraLibraries.concat([ + 'managed_footnote_test.js', + ]), +}; + +TEST_F('CrComponentsManagedFootnoteTest', 'All', function() { + mocha.run(); +}); + GEN('#if defined(OS_CHROMEOS)'); /**
diff --git a/chrome/test/data/webui/cr_components/managed_footnote_test.js b/chrome/test/data/webui/cr_components/managed_footnote_test.js new file mode 100644 index 0000000..90c5438f --- /dev/null +++ b/chrome/test/data/webui/cr_components/managed_footnote_test.js
@@ -0,0 +1,60 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +suite('managed-footnote', function() { + suiteSetup(function() { + loadTimeData.data = { + isManaged: false, + managedByOrg: '', + }; + }); + + setup(function() { + PolymerTest.clearBody(); + }); + + /** + * Resets loadTimeData to the parameters, inserts a <managed-footnote> element + * in the DOM, and returns it. + * @param {boolean} isManaged Whether the footnote should be visible. + * @param {string} message String to display inside the element, before href + * substitution. + * @return {HTMLElement} + */ + function setupTestElement(isManaged, message) { + loadTimeData.overrideValues({ + isManaged: isManaged, + managedByOrg: message, + }); + const footnote = document.createElement('managed-footnote'); + document.body.appendChild(footnote); + Polymer.dom.flush(); + return footnote; + } + + test('Hidden When isManaged Is False', function() { + const footnote = setupTestElement(false, ''); + assertEquals('none', getComputedStyle(footnote).display); + }); + + test('Reads Attributes From loadTimeData', function() { + const message = 'the quick brown fox jumps over the lazy dog'; + const footnote = setupTestElement(true, message); + assertNotEquals('none', getComputedStyle(footnote).display); + assertTrue(footnote.shadowRoot.textContent.includes(message)); + }); + + test('Substitutes URL', function() { + const message = + 'Your <a target="_blank" href="$1">browser is managed</a> by your ' + + 'organization'; + const targetMessage = 'Your browser is managed by your organization'; + const supportUrl = 'https://support.google.com/chromebook/answer/1331549'; + + const footnote = setupTestElement(true, message); + assertTrue(footnote.shadowRoot.textContent.includes(targetMessage)); + // The <a> element should have the right link. + assertEquals(supportUrl, footnote.$$('a').href); + }); +});
diff --git a/chrome/utility/importer/ie_importer_win.cc b/chrome/utility/importer/ie_importer_win.cc index 39d81273..6be8496 100644 --- a/chrome/utility/importer/ie_importer_win.cc +++ b/chrome/utility/importer/ie_importer_win.cc
@@ -22,6 +22,7 @@ #include "base/files/file_path.h" #include "base/files/file_util.h" #include "base/macros.h" +#include "base/stl_util.h" #include "base/strings/string16.h" #include "base/strings/string_split.h" #include "base/strings/string_util.h" @@ -487,7 +488,6 @@ void IEImporter::ImportHistory() { const std::string kSchemes[] = {url::kHttpScheme, url::kHttpsScheme, url::kFtpScheme, url::kFileScheme}; - int total_schemes = arraysize(kSchemes); Microsoft::WRL::ComPtr<IUrlHistoryStg2> url_history_stg2; if (FAILED(::CoCreateInstance(CLSID_CUrlHistory, NULL, CLSCTX_INPROC_SERVER, @@ -520,9 +520,7 @@ GURL url(url_string); // Skips the URLs that are invalid or have other schemes. - if (!url.is_valid() || - (std::find(kSchemes, kSchemes + total_schemes, url.scheme()) == - kSchemes + total_schemes)) + if (!url.is_valid() || !base::ContainsValue(kSchemes, url.scheme())) continue; ImporterURLRow row(url);
diff --git a/chromecast/BUILD.gn b/chromecast/BUILD.gn index 2d294ce..ac5b0b84 100644 --- a/chromecast/BUILD.gn +++ b/chromecast/BUILD.gn
@@ -85,6 +85,7 @@ if (is_linux) { tests += [ "//chromecast/crash:cast_crash_unittests", + "//components/exo:exo_unittests", "//sandbox/linux:sandbox_linux_unittests", ] }
diff --git a/chromeos/chromeos_strings.grd b/chromeos/chromeos_strings.grd index 3c46cdc..21a6e66 100644 --- a/chromeos/chromeos_strings.grd +++ b/chromeos/chromeos_strings.grd
@@ -127,18 +127,6 @@ <message name="IDS_ASSISTANT_SCREEN_CONTEXT_QUERY_FALLBACK_CARD" desc="Message shown in Assistant UI when a query for content related to the screen context returns no results."> Nothing found on screen </message> - <message name="IDS_ASSISTANT_TIMER_NOTIFICATION_TITLE" desc="Title for assistant timer notification."> - Time's up - </message> - <message name="IDS_ASSISTANT_TIMER_NOTIFICATION_CONTENT" desc="Content for assistant timer notification."> - 00:00s - </message> - <message name="IDS_ASSISTANT_STOP_TIMER_QUERY" desc="Query for stopping assistant timer."> - Stop timer - </message> - <message name="IDS_ASSISTANT_STOP_BUTTON_TEXT" desc="Text shown on stop button in Assistant timer notification."> - STOP - </message> <!-- The following strings are located here for accessibility from both //ash and //chrome --> <message name="IDS_ENABLE_BLUETOOTH" desc="The message to display in the network list when Tether is enabled but Bluetooth is disabled.">
diff --git a/chromeos/components/multidevice/BUILD.gn b/chromeos/components/multidevice/BUILD.gn index 5d72eb0..3e5dd5c9 100644 --- a/chromeos/components/multidevice/BUILD.gn +++ b/chromeos/components/multidevice/BUILD.gn
@@ -26,8 +26,8 @@ "//base", "//base:i18n", "//chromeos", - "//components/cryptauth/proto", - "//components/cryptauth/proto:util", + "//chromeos/services/device_sync/proto", + "//chromeos/services/device_sync/proto:util", "//components/prefs", ] } @@ -46,7 +46,7 @@ deps = [ "//base", - "//components/cryptauth/proto", + "//chromeos/services/device_sync/proto", ] } @@ -64,7 +64,7 @@ ":test_support", "//base/test:test_support", "//chromeos/components/multidevice/mojom:unit_tests", - "//components/cryptauth/proto", + "//chromeos/services/device_sync/proto", "//testing/gtest", ] }
diff --git a/chromeos/components/multidevice/beacon_seed.h b/chromeos/components/multidevice/beacon_seed.h index 7dfe965..1074c95 100644 --- a/chromeos/components/multidevice/beacon_seed.h +++ b/chromeos/components/multidevice/beacon_seed.h
@@ -10,7 +10,7 @@ #include <vector> #include "base/time/time.h" -#include "components/cryptauth/proto/cryptauth_api.pb.h" +#include "chromeos/services/device_sync/proto/cryptauth_api.pb.h" namespace chromeos {
diff --git a/chromeos/components/multidevice/mojom/multidevice.typemap b/chromeos/components/multidevice/mojom/multidevice.typemap index e22b2d1..51e8a62 100644 --- a/chromeos/components/multidevice/mojom/multidevice.typemap +++ b/chromeos/components/multidevice/mojom/multidevice.typemap
@@ -20,7 +20,7 @@ public_deps = [ "//chromeos/components/multidevice", - "//components/cryptauth/proto", + "//chromeos/services/device_sync/proto", ] type_mappings = [
diff --git a/chromeos/components/multidevice/software_feature.h b/chromeos/components/multidevice/software_feature.h index 469435f..94ca36c 100644 --- a/chromeos/components/multidevice/software_feature.h +++ b/chromeos/components/multidevice/software_feature.h
@@ -7,7 +7,7 @@ #include <ostream> -#include "components/cryptauth/proto/cryptauth_api.pb.h" +#include "chromeos/services/device_sync/proto/cryptauth_api.pb.h" namespace chromeos {
diff --git a/chromeos/components/proximity_auth/proximity_auth_client.h b/chromeos/components/proximity_auth/proximity_auth_client.h index c0fde56..2d9af0e 100644 --- a/chromeos/components/proximity_auth/proximity_auth_client.h +++ b/chromeos/components/proximity_auth/proximity_auth_client.h
@@ -11,7 +11,7 @@ #include "base/callback_forward.h" #include "chromeos/components/proximity_auth/proximity_auth_pref_manager.h" #include "chromeos/components/proximity_auth/screenlock_state.h" -#include "components/cryptauth/proto/cryptauth_api.pb.h" +#include "chromeos/services/device_sync/proto/cryptauth_api.pb.h" namespace cryptauth { class CryptAuthClientFactory;
diff --git a/chromeos/components/proximity_auth/webui/BUILD.gn b/chromeos/components/proximity_auth/webui/BUILD.gn index 067bc0f..7ac6b36 100644 --- a/chromeos/components/proximity_auth/webui/BUILD.gn +++ b/chromeos/components/proximity_auth/webui/BUILD.gn
@@ -21,14 +21,14 @@ "//chromeos/components/proximity_auth", "//chromeos/components/proximity_auth/logging", "//chromeos/resources", + "//chromeos/services/device_sync/proto", + "//chromeos/services/device_sync/proto:util", "//chromeos/services/device_sync/public/cpp", "//chromeos/services/device_sync/public/mojom", "//chromeos/services/multidevice_setup/public/mojom", "//chromeos/services/secure_channel/public/cpp/client", "//chromeos/services/secure_channel/public/mojom", "//components/cryptauth", - "//components/cryptauth/proto", - "//components/cryptauth/proto:util", "//components/prefs", "//components/resources", "//content/public/browser",
diff --git a/chromeos/components/proximity_auth/webui/proximity_auth_webui_handler.cc b/chromeos/components/proximity_auth/webui/proximity_auth_webui_handler.cc index 772e10c..f365fde 100644 --- a/chromeos/components/proximity_auth/webui/proximity_auth_webui_handler.cc +++ b/chromeos/components/proximity_auth/webui/proximity_auth_webui_handler.cc
@@ -22,7 +22,7 @@ #include "chromeos/components/proximity_auth/messenger.h" #include "chromeos/components/proximity_auth/remote_device_life_cycle_impl.h" #include "chromeos/components/proximity_auth/remote_status_update.h" -#include "components/cryptauth/proto/enum_util.h" +#include "chromeos/services/device_sync/proto/enum_util.h" #include "components/prefs/pref_service.h" #include "content/public/browser/browser_thread.h" #include "content/public/browser/web_ui.h"
diff --git a/chromeos/components/tether/BUILD.gn b/chromeos/components/tether/BUILD.gn index 29c3aa2f..9de800d 100644 --- a/chromeos/components/tether/BUILD.gn +++ b/chromeos/components/tether/BUILD.gn
@@ -149,7 +149,7 @@ ] public_deps = [ - "//components/cryptauth/proto", + "//chromeos/services/device_sync/proto", ] }
diff --git a/chromeos/services/assistant/assistant_manager_service_impl.cc b/chromeos/services/assistant/assistant_manager_service_impl.cc index 59f3e2f..aefaf0b 100644 --- a/chromeos/services/assistant/assistant_manager_service_impl.cc +++ b/chromeos/services/assistant/assistant_manager_service_impl.cc
@@ -36,6 +36,15 @@ #include "ui/base/l10n/l10n_util.h" #include "url/gurl.h" +// A macro which ensures we are running on the main thread. +#define ENSURE_MAIN_THREAD(method, ...) \ + if (!service_->main_task_runner()->BelongsToCurrentThread()) { \ + service_->main_task_runner()->PostTask( \ + FROM_HERE, \ + base::BindOnce(method, weak_factory_.GetWeakPtr(), ##__VA_ARGS__)); \ + return; \ + } + using ActionModule = assistant_client::ActionModule; using Resolution = assistant_client::ConversationStateListener::Resolution; @@ -51,12 +60,10 @@ constexpr char kScreenBrightnessDeviceSettingId[] = "BRIGHTNESS_LEVEL"; constexpr char kDoNotDisturbDeviceSettingId[] = "DO_NOT_DISTURB"; constexpr char kNightLightDeviceSettingId[] = "NIGHT_LIGHT_SWITCH"; -constexpr char kTimerFireNotificationGroupId[] = "assistant/timer_fire"; -constexpr char kQueryDeeplinkPrefix[] = "googleassistant://send-query?q="; -constexpr base::Feature kAssistantTimerNotificationFeature{ - "ChromeOSAssistantTimerNotification", base::FEATURE_ENABLED_BY_DEFAULT}; + constexpr base::Feature kChromeOSAssistantDogfood{ "ChromeOSAssistantDogfood", base::FEATURE_DISABLED_BY_DEFAULT}; + constexpr char kServersideDogfoodExperimentId[] = "20347368"; constexpr float kDefaultSliderStep = 0.1f; @@ -803,38 +810,15 @@ } void AssistantManagerServiceImpl::OnTimerSoundingStarted() { - // TODO(llin): Migrate to use the AlarmManager API to better support multiple - // timers when the API is available. - if (!base::FeatureList::IsEnabled(kAssistantTimerNotificationFeature)) - return; - - const std::string notification_title = - l10n_util::GetStringUTF8(IDS_ASSISTANT_TIMER_NOTIFICATION_TITLE); - const std::string notification_content = - l10n_util::GetStringUTF8(IDS_ASSISTANT_TIMER_NOTIFICATION_CONTENT); - const std::string stop_timer_query = - l10n_util::GetStringUTF8(IDS_ASSISTANT_STOP_TIMER_QUERY); - - const std::string action_url = kQueryDeeplinkPrefix + stop_timer_query; - action::Notification notification( - /*title=*/notification_title, - /*text=*/notification_content, - /*action_url=*/action_url, - /*notification_id=*/{}, - /*consistency_token=*/{}, - /*opaque_token=*/{}, - /*grouping_key=*/kTimerFireNotificationGroupId, - /*obfuscated_gaia_id=*/{}, - /*buttons=*/ - {{l10n_util::GetStringUTF8(IDS_ASSISTANT_STOP_BUTTON_TEXT), action_url}}); - OnShowNotification(notification); + ENSURE_MAIN_THREAD(&AssistantManagerServiceImpl::OnTimerSoundingStarted); + if (service_->assistant_alarm_timer_controller()) + service_->assistant_alarm_timer_controller()->OnTimerSoundingStarted(); } void AssistantManagerServiceImpl::OnTimerSoundingFinished() { - if (!base::FeatureList::IsEnabled(kAssistantTimerNotificationFeature)) - return; - - OnNotificationRemoved(kTimerFireNotificationGroupId); + ENSURE_MAIN_THREAD(&AssistantManagerServiceImpl::OnTimerSoundingFinished); + if (service_->assistant_alarm_timer_controller()) + service_->assistant_alarm_timer_controller()->OnTimerSoundingFinished(); } void AssistantManagerServiceImpl::UpdateInternalOptions(
diff --git a/chromeos/services/assistant/public/features.cc b/chromeos/services/assistant/public/features.cc index bfde058..3ebcb11f 100644 --- a/chromeos/services/assistant/public/features.cc +++ b/chromeos/services/assistant/public/features.cc
@@ -25,6 +25,9 @@ const base::Feature kEnableStereoAudioInput{"AssistantEnableStereoAudioInput", base::FEATURE_DISABLED_BY_DEFAULT}; +const base::Feature kTimerNotification{"ChromeOSAssistantTimerNotification", + base::FEATURE_ENABLED_BY_DEFAULT}; + bool IsDspHotwordEnabled() { return base::FeatureList::IsEnabled(kEnableDspHotword); } @@ -33,6 +36,10 @@ return base::FeatureList::IsEnabled(kEnableStereoAudioInput); } +bool IsTimerNotificationEnabled() { + return base::FeatureList::IsEnabled(kTimerNotification); +} + bool IsWarmerWelcomeEnabled() { return base::FeatureList::IsEnabled(kAssistantWarmerWelcomeFeature); }
diff --git a/chromeos/services/assistant/public/features.h b/chromeos/services/assistant/public/features.h index 6a40b1626..146e782 100644 --- a/chromeos/services/assistant/public/features.h +++ b/chromeos/services/assistant/public/features.h
@@ -26,10 +26,15 @@ // Enables stereo audio input. extern const base::Feature kEnableStereoAudioInput; +// Enables timer notifications. +extern const base::Feature kTimerNotification; + bool IsDspHotwordEnabled(); bool IsStereoAudioInputEnabled(); +bool IsTimerNotificationEnabled(); + bool IsWarmerWelcomeEnabled(); } // namespace features
diff --git a/chromeos/services/assistant/service.cc b/chromeos/services/assistant/service.cc index 7f1209b..3d1240c 100644 --- a/chromeos/services/assistant/service.cc +++ b/chromeos/services/assistant/service.cc
@@ -18,6 +18,7 @@ #include "chromeos/dbus/dbus_thread_manager.h" #include "chromeos/services/assistant/assistant_manager_service.h" #include "chromeos/services/assistant/assistant_settings_manager.h" +#include "chromeos/services/assistant/public/features.h" #include "google_apis/gaia/google_service_auth_error.h" #include "google_apis/gaia/oauth2_token_service.h" #include "services/identity/public/mojom/constants.mojom.h" @@ -302,6 +303,12 @@ BindAssistantConnection(mojo::MakeRequest(&ptr)); assistant_controller_->SetAssistant(std::move(ptr)); + if (features::IsTimerNotificationEnabled()) { + // Bind to the AssistantAlarmTimerController in ash. + service_binding_.GetConnector()->BindInterface( + ash::mojom::kServiceName, &assistant_alarm_timer_controller_); + } + // Bind to the AssistantScreenContextController in ash. service_binding_.GetConnector()->BindInterface( ash::mojom::kServiceName, &assistant_screen_context_controller_);
diff --git a/chromeos/services/assistant/service.h b/chromeos/services/assistant/service.h index 8381b59..302040e 100644 --- a/chromeos/services/assistant/service.h +++ b/chromeos/services/assistant/service.h
@@ -66,6 +66,11 @@ return assistant_controller_.get(); } + ash::mojom::AssistantAlarmTimerController* + assistant_alarm_timer_controller() { + return assistant_alarm_timer_controller_.get(); + } + ash::mojom::AssistantScreenContextController* assistant_screen_context_controller() { return assistant_screen_context_controller_.get(); @@ -170,6 +175,8 @@ base::Optional<std::string> access_token_; ash::mojom::AssistantControllerPtr assistant_controller_; + ash::mojom::AssistantAlarmTimerControllerPtr + assistant_alarm_timer_controller_; ash::mojom::AssistantScreenContextControllerPtr assistant_screen_context_controller_; ash::AssistantStateProxy assistant_state_;
diff --git a/chromeos/services/device_sync/device_sync_impl.cc b/chromeos/services/device_sync/device_sync_impl.cc index 07d098f..18bd071 100644 --- a/chromeos/services/device_sync/device_sync_impl.cc +++ b/chromeos/services/device_sync/device_sync_impl.cc
@@ -12,13 +12,13 @@ #include "chromeos/components/proximity_auth/logging/logging.h" #include "chromeos/services/device_sync/cryptauth_enroller_factory_impl.h" #include "chromeos/services/device_sync/device_sync_type_converters.h" +#include "chromeos/services/device_sync/proto/cryptauth_api.pb.h" #include "components/cryptauth/cryptauth_client_impl.h" #include "components/cryptauth/cryptauth_device_manager_impl.h" #include "components/cryptauth/cryptauth_enrollment_manager_impl.h" #include "components/cryptauth/cryptauth_gcm_manager_impl.h" #include "components/cryptauth/device_classifier_util.h" #include "components/cryptauth/gcm_device_info_provider.h" -#include "components/cryptauth/proto/cryptauth_api.pb.h" #include "components/cryptauth/remote_device_provider_impl.h" #include "components/cryptauth/secure_message_delegate_impl.h" #include "components/cryptauth/software_feature_manager_impl.h"
diff --git a/components/cryptauth/proto/BUILD.gn b/chromeos/services/device_sync/proto/BUILD.gn similarity index 86% rename from components/cryptauth/proto/BUILD.gn rename to chromeos/services/device_sync/proto/BUILD.gn index 334639f..650449fd 100644 --- a/components/cryptauth/proto/BUILD.gn +++ b/chromeos/services/device_sync/proto/BUILD.gn
@@ -1,4 +1,4 @@ -# Copyright 2014 The Chromium Authors. All rights reserved. +# Copyright 2018 The Chromium Authors. All rights reserved. # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file.
diff --git a/components/cryptauth/proto/cryptauth_api.proto b/chromeos/services/device_sync/proto/cryptauth_api.proto similarity index 96% rename from components/cryptauth/proto/cryptauth_api.proto rename to chromeos/services/device_sync/proto/cryptauth_api.proto index ecda43c..b2589b8 100644 --- a/components/cryptauth/proto/cryptauth_api.proto +++ b/chromeos/services/device_sync/proto/cryptauth_api.proto
@@ -2,8 +2,14 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// Definitions for CryptAuth API calls. Do not edit unless transcribing -// from server definitions. +// Definitions for calls to the CryptAuth back-end. The DeviceSync service +// performs two main functions: +// (1) Enroll (i.e., register) the Chromebook with the CryptAuth server by +// providing information about the device. +// (2) Download metadata about other devices associated with the user's +// account. +// +// This file defines the protocol messages and enums used to perform these RPCs. syntax = "proto2"; package cryptauth; @@ -79,20 +85,20 @@ optional string bluetooth_address = 3; // Whether or not this device can be used as an unlock key - optional bool unlock_key = 4 [ default = false ]; + optional bool unlock_key = 4 [default = false]; // Whether or not this device can be unlocked - optional bool unlockable = 5 [ default = false ]; + optional bool unlockable = 5 [default = false]; // The last time this device updated its info with the server. optional int64 last_update_time_millis = 6; // Whether or not this device hardware supports providing a mobile hotspot. - optional bool mobile_hotspot_supported = 7 [ default = false ]; + optional bool mobile_hotspot_supported = 7 [default = false]; // The type of the device (e.g. Android vs iOS). // TODO(khorimoto): Change this to a string so it works with Apiary endpoints. - optional DeviceType device_type = 8 [ default = UNKNOWN ]; + optional DeviceType device_type = 8 [default = UNKNOWN]; // A list of seeds for EID BLE advertisements targeting this device. repeated BeaconSeed beacon_seeds = 9;
diff --git a/components/cryptauth/proto/enum_util.cc b/chromeos/services/device_sync/proto/enum_util.cc similarity index 98% rename from components/cryptauth/proto/enum_util.cc rename to chromeos/services/device_sync/proto/enum_util.cc index 90235af72..0b3dcca 100644 --- a/components/cryptauth/proto/enum_util.cc +++ b/chromeos/services/device_sync/proto/enum_util.cc
@@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "components/cryptauth/proto/enum_util.h" +#include "chromeos/services/device_sync/proto/enum_util.h" namespace cryptauth {
diff --git a/components/cryptauth/proto/enum_util.h b/chromeos/services/device_sync/proto/enum_util.h similarity index 86% rename from components/cryptauth/proto/enum_util.h rename to chromeos/services/device_sync/proto/enum_util.h index c155ba2..6810953 100644 --- a/components/cryptauth/proto/enum_util.h +++ b/chromeos/services/device_sync/proto/enum_util.h
@@ -2,12 +2,12 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef COMPONENTS_CRYPTAUTH_PROTO_ENUM_UTIL_H_ -#define COMPONENTS_CRYPTAUTH_PROTO_ENUM_UTIL_H_ +#ifndef CHROMEOS_SERVICES_DEVICE_SYNC_PROTO_ENUM_UTIL_H_ +#define CHROMEOS_SERVICES_DEVICE_SYNC_PROTO_ENUM_UTIL_H_ #include <ostream> -#include "components/cryptauth/proto/cryptauth_api.pb.h" +#include "chromeos/services/device_sync/proto/cryptauth_api.pb.h" namespace cryptauth { @@ -38,4 +38,4 @@ } // namespace cryptauth -#endif // COMPONENTS_CRYPTAUTH_PROTO_ENUM_UTIL_H_ +#endif // CHROMEOS_SERVICES_DEVICE_SYNC_PROTO_ENUM_UTIL_H_
diff --git a/components/cryptauth/proto/securemessage.proto b/chromeos/services/device_sync/proto/securemessage.proto similarity index 100% rename from components/cryptauth/proto/securemessage.proto rename to chromeos/services/device_sync/proto/securemessage.proto
diff --git a/chromeos/services/multidevice_setup/BUILD.gn b/chromeos/services/multidevice_setup/BUILD.gn index bbe94e4..2097244 100644 --- a/chromeos/services/multidevice_setup/BUILD.gn +++ b/chromeos/services/multidevice_setup/BUILD.gn
@@ -58,6 +58,7 @@ "//base", "//chromeos/components/multidevice", "//chromeos/components/proximity_auth/logging", + "//chromeos/services/device_sync/proto:util", "//chromeos/services/device_sync/public/cpp", "//chromeos/services/device_sync/public/mojom", "//chromeos/services/multidevice_setup/proto", @@ -70,7 +71,6 @@ "//chromeos/services/secure_channel/public/cpp/client", "//chromeos/services/secure_channel/public/mojom", "//components/cryptauth", - "//components/cryptauth/proto:util", "//components/pref_registry", "//components/prefs:prefs", "//services/service_manager/public/cpp",
diff --git a/chromeos/services/multidevice_setup/device_reenroller.cc b/chromeos/services/multidevice_setup/device_reenroller.cc index b7cf3209..014f309f 100644 --- a/chromeos/services/multidevice_setup/device_reenroller.cc +++ b/chromeos/services/multidevice_setup/device_reenroller.cc
@@ -7,8 +7,8 @@ #include "base/containers/flat_set.h" #include "base/no_destructor.h" #include "chromeos/components/proximity_auth/logging/logging.h" +#include "chromeos/services/device_sync/proto/enum_util.h" #include "components/cryptauth/gcm_device_info_provider.h" -#include "components/cryptauth/proto/enum_util.h" namespace chromeos {
diff --git a/chromeos/services/multidevice_setup/device_reenroller.h b/chromeos/services/multidevice_setup/device_reenroller.h index e111642..f669f36 100644 --- a/chromeos/services/multidevice_setup/device_reenroller.h +++ b/chromeos/services/multidevice_setup/device_reenroller.h
@@ -8,8 +8,8 @@ #include <memory> #include "base/macros.h" +#include "chromeos/services/device_sync/proto/cryptauth_api.pb.h" #include "chromeos/services/device_sync/public/cpp/device_sync_client.h" -#include "components/cryptauth/proto/cryptauth_api.pb.h" namespace base { class OneShotTimer;
diff --git a/chromeos/services/multidevice_setup/eligible_host_devices_provider_impl_unittest.cc b/chromeos/services/multidevice_setup/eligible_host_devices_provider_impl_unittest.cc index ded1528..0c2ca99 100644 --- a/chromeos/services/multidevice_setup/eligible_host_devices_provider_impl_unittest.cc +++ b/chromeos/services/multidevice_setup/eligible_host_devices_provider_impl_unittest.cc
@@ -12,6 +12,7 @@ #include "chromeos/components/multidevice/remote_device_test_util.h" #include "chromeos/components/multidevice/software_feature.h" #include "chromeos/components/multidevice/software_feature_state.h" +#include "chromeos/services/device_sync/proto/cryptauth_api.pb.h" #include "chromeos/services/device_sync/public/cpp/fake_device_sync_client.h" #include "testing/gtest/include/gtest/gtest.h"
diff --git a/chromeos/services/secure_channel/ble_scanner_impl.cc b/chromeos/services/secure_channel/ble_scanner_impl.cc index 613af1c..552d207 100644 --- a/chromeos/services/secure_channel/ble_scanner_impl.cc +++ b/chromeos/services/secure_channel/ble_scanner_impl.cc
@@ -13,9 +13,9 @@ #include "base/strings/string_util.h" #include "chromeos/components/multidevice/remote_device_ref.h" #include "chromeos/components/proximity_auth/logging/logging.h" +#include "chromeos/services/device_sync/proto/cryptauth_api.pb.h" #include "chromeos/services/secure_channel/ble_constants.h" #include "chromeos/services/secure_channel/ble_synchronizer_base.h" -#include "components/cryptauth/proto/cryptauth_api.pb.h" #include "device/bluetooth/bluetooth_device.h" #include "device/bluetooth/bluetooth_discovery_session.h" #include "device/bluetooth/bluetooth_uuid.h"
diff --git a/chromeos/services/secure_channel/public/mojom/secure_channel.mojom b/chromeos/services/secure_channel/public/mojom/secure_channel.mojom index 06a053b..8df2e04 100644 --- a/chromeos/services/secure_channel/public/mojom/secure_channel.mojom +++ b/chromeos/services/secure_channel/public/mojom/secure_channel.mojom
@@ -92,7 +92,7 @@ // bytes were publicly visible over BLE when the connection with the remote // device was being established. It is used by some clients for further // cryptographic communication. - // Defined by //components/cryptauth/proto/securemessage.proto. + // Defined by //chromeos/services/device_sync/proto/securemessage.proto. string channel_binding_data; };
diff --git a/components/autofill/content/renderer/password_autofill_agent.cc b/components/autofill/content/renderer/password_autofill_agent.cc index bf3c410..e5dc15d1 100644 --- a/components/autofill/content/renderer/password_autofill_agent.cc +++ b/components/autofill/content/renderer/password_autofill_agent.cc
@@ -1772,8 +1772,13 @@ logger->LogMessage(Logger::STRING_FILL_USERNAME_AND_PASSWORD_METHOD); // Don't fill username if password can't be set. - if (!IsElementAutocompletable(*password_element)) + if (!IsElementAutocompletable(*password_element)) { + if (logger) { + logger->LogMessage( + Logger::STRING_FAILED_TO_FILL_NO_AUTOCOMPLETEABLE_ELEMENT); + } return false; + } // |current_username| is the username for credentials that are going to be // autofilled. It is selected according to the algorithm: @@ -1819,6 +1824,13 @@ !prefilled_placeholder_username) { LogPrefilledUsernameFillOutcome( PrefilledUsernameFillOutcome::kPrefilledUsernameNotOverridden); + if (logger) + logger->LogMessage(Logger::STRING_FAILED_TO_FILL_PREFILLED_USERNAME); + return false; + } + if (logger) { + logger->LogMessage( + Logger::STRING_FAILED_TO_FILL_FOUND_NO_PASSWORD_FOR_USERNAME); } return false; } @@ -1902,13 +1914,21 @@ cur_frame = cur_frame->Parent(); if (!IsPublicSuffixDomainMatch( bottom_frame_origin.Utf8(), - cur_frame->GetSecurityOrigin().ToString().Utf8())) + cur_frame->GetSecurityOrigin().ToString().Utf8())) { + if (logger) + logger->LogMessage(Logger::STRING_FAILED_TO_FILL_INTO_IFRAME); return false; + } } // If we can't modify the password, don't try to set the username - if (!IsElementAutocompletable(password_element)) + if (!IsElementAutocompletable(password_element)) { + if (logger) { + logger->LogMessage( + Logger::STRING_FAILED_TO_FILL_NO_AUTOCOMPLETEABLE_ELEMENT); + } return false; + } bool exact_username_match = username_element.IsNull() || IsElementEditable(username_element);
diff --git a/components/autofill/core/browser/autofill_metrics.cc b/components/autofill/core/browser/autofill_metrics.cc index 2a7c8d4f..17c9d68 100644 --- a/components/autofill/core/browser/autofill_metrics.cc +++ b/components/autofill/core/browser/autofill_metrics.cc
@@ -726,12 +726,19 @@ void AutofillMetrics::LogCreditCardInfoBarMetric( InfoBarMetric metric, bool is_uploading, + bool is_requesting_cardholder_name, int previous_save_credit_card_prompt_user_decision) { DCHECK_LT(metric, NUM_INFO_BAR_METRICS); std::string destination = is_uploading ? ".Server" : ".Local"; base::UmaHistogramEnumeration("Autofill.CreditCardInfoBar" + destination, metric, NUM_INFO_BAR_METRICS); + if (is_requesting_cardholder_name) { + base::UmaHistogramEnumeration("Autofill.CreditCardInfoBar" + destination + + ".RequestingCardholderName", + metric, NUM_INFO_BAR_METRICS); + } + base::UmaHistogramEnumeration( "Autofill.CreditCardInfoBar" + destination + PreviousSaveCreditCardPromptUserDecisionToString( @@ -962,6 +969,13 @@ } // static +void AutofillMetrics::LogCardholderNameFixFlowPromptEvent( + CardholderNameFixFlowPromptEvent event) { + UMA_HISTOGRAM_ENUMERATION("Autofill.CardholderNameFixFlowPrompt.Events", + event, NUM_FIXFLOW_PROMPT_EVENTS); +} + +// static void AutofillMetrics::LogUnmaskPromptEventDuration( const base::TimeDelta& duration, UnmaskPromptEvent close_event) { @@ -2179,6 +2193,12 @@ return form_type_bv; } +void AutofillMetrics::LogServerCardLinkClicked( + AutofillSyncSigninState sync_state) { + UMA_HISTOGRAM_ENUMERATION("Autofill.ServerCardLinkClicked", sync_state, + AutofillSyncSigninState::kNumSyncStates); +} + void AutofillMetrics::FormInteractionsUkmLogger::LogFormSubmitted( bool is_for_credit_card, const std::set<FormType>& form_types,
diff --git a/components/autofill/core/browser/autofill_metrics.h b/components/autofill/core/browser/autofill_metrics.h index a4337c68..10903b3 100644 --- a/components/autofill/core/browser/autofill_metrics.h +++ b/components/autofill/core/browser/autofill_metrics.h
@@ -684,6 +684,19 @@ BANK_NAME_NUM_FORM_EVENTS, }; + // Cardholder name fix flow prompt metrics. + enum CardholderNameFixFlowPromptEvent { + // The prompt was shown. + CARDHOLDER_NAME_FIX_FLOW_PROMPT_SHOWN = 0, + // The prompt was accepted by user. + CARDHOLDER_NAME_FIX_FLOW_PROMPT_ACCEPTED, + // The prompt was dismissed by user. + CARDHOLDER_NAME_FIX_FLOW_PROMPT_DISMISSED, + // The prompt was closed without user interaction. + CARDHOLDER_NAME_FIX_FLOW_PROMPT_CLOSED_WITHOUT_INTERACTION, + NUM_FIXFLOW_PROMPT_EVENTS, + }; + // Events related to the Unmask Credit Card Prompt. enum UnmaskPromptEvent { // The prompt was shown. @@ -947,6 +960,7 @@ static void LogCreditCardInfoBarMetric( InfoBarMetric metric, bool is_uploading, + bool is_requesting_cardholder_name, int previous_save_credit_card_prompt_user_decision); static void LogCreditCardFillingInfoBarMetric(InfoBarMetric metric); static void LogSaveCardRequestExpirationDateReasonMetric( @@ -1033,6 +1047,10 @@ // Logs |event| to the unmask prompt events histogram. static void LogUnmaskPromptEvent(UnmaskPromptEvent event); + // Logs |event| to cardholder name fix flow prompt events histogram. + static void LogCardholderNameFixFlowPromptEvent( + CardholderNameFixFlowPromptEvent event); + // Logs the time elapsed between the unmask prompt being shown and it // being closed. static void LogUnmaskPromptEventDuration(const base::TimeDelta& duration, @@ -1250,6 +1268,10 @@ // Converts form type to bit vector to store in UKM. static int64_t FormTypesToBitVector(const std::set<FormType>& form_types); + // Records the fact that the server card link was clicked with information + // about the current sync state. + static void LogServerCardLinkClicked(AutofillSyncSigninState sync_state); + // Utility to log autofill form events in the relevant histograms depending on // the presence of server and/or local data. class FormEventLogger {
diff --git a/components/autofill/core/browser/autofill_metrics_unittest.cc b/components/autofill/core/browser/autofill_metrics_unittest.cc index 4bcc836..dfa941e 100644 --- a/components/autofill/core/browser/autofill_metrics_unittest.cc +++ b/components/autofill/core/browser/autofill_metrics_unittest.cc
@@ -8345,4 +8345,23 @@ } } +TEST_F(AutofillMetricsTest, LogServerCardLinkClicked) { + { + base::HistogramTester histogram_tester; + AutofillMetrics::LogServerCardLinkClicked( + AutofillSyncSigninState::kSignedIn); + histogram_tester.ExpectTotalCount("Autofill.ServerCardLinkClicked", 1); + histogram_tester.ExpectBucketCount("Autofill.ServerCardLinkClicked", + AutofillSyncSigninState::kSignedIn, 1); + } + { + base::HistogramTester histogram_tester; + AutofillMetrics::LogServerCardLinkClicked( + AutofillSyncSigninState::kSignedOut); + histogram_tester.ExpectTotalCount("Autofill.ServerCardLinkClicked", 1); + histogram_tester.ExpectBucketCount("Autofill.ServerCardLinkClicked", + AutofillSyncSigninState::kSignedOut, 1); + } +} + } // namespace autofill
diff --git a/components/autofill/core/browser/autofill_save_card_infobar_delegate_mobile.cc b/components/autofill/core/browser/autofill_save_card_infobar_delegate_mobile.cc index 1a9d6f2..8463dfb 100644 --- a/components/autofill/core/browser/autofill_save_card_infobar_delegate_mobile.cc +++ b/components/autofill/core/browser/autofill_save_card_infobar_delegate_mobile.cc
@@ -57,6 +57,7 @@ /*escape_apostrophes=*/true)) { AutofillMetrics::LogCreditCardInfoBarMetric( AutofillMetrics::INFOBAR_NOT_SHOWN_INVALID_LEGAL_MESSAGE, upload_, + should_request_name_from_user_, pref_service_->GetInteger( prefs::kAutofillAcceptSaveCreditCardPromptState)); return; @@ -64,7 +65,7 @@ } AutofillMetrics::LogCreditCardInfoBarMetric( - AutofillMetrics::INFOBAR_SHOWN, upload_, + AutofillMetrics::INFOBAR_SHOWN, upload_, should_request_name_from_user_, pref_service_->GetInteger( prefs::kAutofillAcceptSaveCreditCardPromptState)); } @@ -177,7 +178,7 @@ DCHECK(!had_user_interaction_); AutofillMetrics::LogCreditCardInfoBarMetric( - user_action, upload_, + user_action, upload_, should_request_name_from_user_, pref_service_->GetInteger( prefs::kAutofillAcceptSaveCreditCardPromptState)); pref_service_->SetInteger(
diff --git a/components/autofill/core/browser/credit_card_save_manager.cc b/components/autofill/core/browser/credit_card_save_manager.cc index 3edf31cc..a52de27 100644 --- a/components/autofill/core/browser/credit_card_save_manager.cc +++ b/components/autofill/core/browser/credit_card_save_manager.cc
@@ -775,6 +775,8 @@ OnUserDidIgnoreOrDeclineSave(upload_request_.card.LastFourDigits()); break; } + + personal_data_manager_->OnUserAcceptedUpstreamOffer(); } #if defined(OS_ANDROID)
diff --git a/components/autofill/core/browser/credit_card_save_manager_unittest.cc b/components/autofill/core/browser/credit_card_save_manager_unittest.cc index 70cd010..0053dab2 100644 --- a/components/autofill/core/browser/credit_card_save_manager_unittest.cc +++ b/components/autofill/core/browser/credit_card_save_manager_unittest.cc
@@ -89,6 +89,13 @@ } // anonymous namespace +class MockPersonalDataManager : public TestPersonalDataManager { + public: + MockPersonalDataManager() {} + ~MockPersonalDataManager() override {} + MOCK_METHOD0(OnUserAcceptedUpstreamOffer, void()); +}; + class CreditCardSaveManagerTest : public testing::Test { public: void SetUp() override { @@ -315,7 +322,7 @@ std::unique_ptr<TestAutofillDriver> autofill_driver_; std::unique_ptr<TestAutofillManager> autofill_manager_; scoped_refptr<net::TestURLRequestContextGetter> request_context_; - TestPersonalDataManager personal_data_; + MockPersonalDataManager personal_data_; syncer::TestSyncService sync_service_; base::test::ScopedFeatureList scoped_feature_list_; // Ends up getting owned (and destroyed) by TestFormDataImporter: @@ -4633,4 +4640,13 @@ /*sample=*/2, /*count=*/1); } +// Make sure that the PersonalDataManager gets notified when the user accepts +// an upload offer. +TEST_F(CreditCardSaveManagerTest, OnUserDidAcceptUpload_NotifiesPDM) { + EXPECT_CALL(personal_data_, OnUserAcceptedUpstreamOffer); + + // Simulate that the user has accepted the upload from the prompt. + UserHasAcceptedUpload({}); +} + } // namespace autofill
diff --git a/components/autofill/core/browser/local_card_migration_manager.cc b/components/autofill/core/browser/local_card_migration_manager.cc index 1fa4c5b..a10aee8 100644 --- a/components/autofill/core/browser/local_card_migration_manager.cc +++ b/components/autofill/core/browser/local_card_migration_manager.cc
@@ -150,8 +150,11 @@ bool has_google_payments_account = (payments::GetBillingCustomerId(personal_data_manager_, payments_client_->GetPrefService()) != 0); + bool sync_feature_enabled = + (personal_data_manager_->GetSyncSigninState() == + AutofillSyncSigninState::kSignedInAndSyncFeature); return migration_experiment_enabled && credit_card_upload_enabled && - has_google_payments_account; + has_google_payments_account && sync_feature_enabled; } void LocalCardMigrationManager::OnDidGetUploadDetails(
diff --git a/components/autofill/core/browser/local_card_migration_manager_unittest.cc b/components/autofill/core/browser/local_card_migration_manager_unittest.cc index dc90b1e..34190481 100644 --- a/components/autofill/core/browser/local_card_migration_manager_unittest.cc +++ b/components/autofill/core/browser/local_card_migration_manager_unittest.cc
@@ -444,6 +444,42 @@ EXPECT_FALSE(local_card_migration_manager_->LocalCardMigrationWasTriggered()); } +// Do not trigger migration if user only signs in. +TEST_F(LocalCardMigrationManagerTest, MigrateCreditCard_SignInOnly) { + EnableAutofillCreditCardLocalCardMigrationExperiment(); + + // Make a non-primary account available with both a refresh token and cookie + // to be in Sync Transport for Wallet mode, in which case this account is + // signed in only without sync enabled. + sync_service_.SetIsAuthenticatedAccountPrimary(false); + sync_service_.SetActiveDataTypes( + syncer::ModelTypeSet(syncer::AUTOFILL_WALLET_DATA)); + + base::test::ScopedFeatureList scoped_features; + scoped_features.InitWithFeatures( + /*enabled_features=*/{features::kAutofillEnableAccountWalletStorage}, + /*disabled_features=*/{}); + + // Add a local credit card whose |TypeAndLastFourDigits| matches what we will + // enter below. + AddLocalCreditCard(personal_data_, "Flo Master", "4111111111111111", "11", + test::NextYear().c_str(), "1", "guid1"); + // Add another local credit card. + AddLocalCreditCard(personal_data_, "Flo Master", "5555555555554444", "11", + test::NextYear().c_str(), "1", "guid2"); + + // Set up our credit card form data. + FormData credit_card_form; + test::CreateTestCreditCardFormData(&credit_card_form, true, false); + FormsSeen(std::vector<FormData>(1, credit_card_form)); + + // Edit the data, and submit. + EditCreditCardFrom(credit_card_form, "Flo Master", "4111111111111111", "11", + test::NextYear().c_str(), "123"); + FormSubmitted(credit_card_form); + EXPECT_FALSE(local_card_migration_manager_->LocalCardMigrationWasTriggered()); +} + // Use one local card with more valid local cards available but billing customer // number is blank, will not trigger migration. TEST_F(LocalCardMigrationManagerTest, MigrateCreditCard_NoPaymentsAccount) {
diff --git a/components/autofill/core/browser/personal_data_manager.cc b/components/autofill/core/browser/personal_data_manager.cc index 6d018910..1ca568a 100644 --- a/components/autofill/core/browser/personal_data_manager.cc +++ b/components/autofill/core/browser/personal_data_manager.cc
@@ -2104,6 +2104,20 @@ pref_service_, sync_service_->GetAuthenticatedAccountInfo().account_id); } +void PersonalDataManager::LogServerCardLinkClicked() const { + AutofillMetrics::LogServerCardLinkClicked(GetSyncSigninState()); +} + +void PersonalDataManager::OnUserAcceptedUpstreamOffer() { + // If the user is in sync transport mode for Wallet, record an opt-in. + if (GetSyncSigninState() == + AutofillSyncSigninState::kSignedInAndWalletSyncTransportEnabled) { + prefs::SetUserOptedInWalletSyncTransport( + pref_service_, sync_service_->GetAuthenticatedAccountInfo().account_id, + /*opted_in=*/true); + } +} + std::vector<Suggestion> PersonalDataManager::GetSuggestionsForCards( const AutofillType& type, const base::string16& field_contents,
diff --git a/components/autofill/core/browser/personal_data_manager.h b/components/autofill/core/browser/personal_data_manager.h index 9a3832a..3207b90 100644 --- a/components/autofill/core/browser/personal_data_manager.h +++ b/components/autofill/core/browser/personal_data_manager.h
@@ -383,6 +383,13 @@ // account should be shown in the dropdown. bool ShouldShowCardsFromAccountOption() const; + // Logs the fact that the server card link was clicked including information + // about the current sync state. + void LogServerCardLinkClicked() const; + + // Records the sync transport consent if the user is in sync transport mode. + virtual void OnUserAcceptedUpstreamOffer(); + protected: // Only PersonalDataManagerFactory and certain tests can create instances of // PersonalDataManager.
diff --git a/components/autofill/core/browser/personal_data_manager_unittest.cc b/components/autofill/core/browser/personal_data_manager_unittest.cc index b079c4b..c9c0092 100644 --- a/components/autofill/core/browser/personal_data_manager_unittest.cc +++ b/components/autofill/core/browser/personal_data_manager_unittest.cc
@@ -7308,4 +7308,107 @@ } } +TEST_F(PersonalDataManagerTest, OnUserAcceptedUpstreamOffer) { + /////////////////////////////////////////////////////////// + // kSignedInAndWalletSyncTransportEnabled + /////////////////////////////////////////////////////////// + // Make a non-primary account available with both a refresh token and cookie + // to be in Sync Transport for Wallet mode. + AccountInfo active_info; + active_info.email = "test@gmail.com"; + active_info.account_id = "account_id"; + identity_test_env_.SetPrimaryAccount(active_info.email); + sync_service_.SetAuthenticatedAccountInfo(active_info); + sync_service_.SetIsAuthenticatedAccountPrimary(false); + sync_service_.SetActiveDataTypes( + syncer::ModelTypeSet(syncer::AUTOFILL_WALLET_DATA)); + // Make sure there are no opt-ins recorded yet. + ASSERT_FALSE(prefs::IsUserOptedInWalletSyncTransport(prefs_.get(), + active_info.account_id)); +// The kSignedInAndWalletSyncTransportEnabled state is not available on CrOS. +#if !defined(OS_CHROMEOS) + { + base::test::ScopedFeatureList scoped_features; + scoped_features.InitWithFeatures( + /*enabled_features=*/{features::kAutofillEnableAccountWalletStorage}, + /*disabled_features=*/{}); + + EXPECT_EQ(AutofillSyncSigninState::kSignedInAndWalletSyncTransportEnabled, + personal_data_->GetSyncSigninState()); + + // Make sure an opt-in gets recorded if the user accepted an Upstream offer. + personal_data_->OnUserAcceptedUpstreamOffer(); + EXPECT_TRUE(prefs::IsUserOptedInWalletSyncTransport( + prefs_.get(), active_info.account_id)); + } +#endif // !defined(OS_CHROMEOS) + + // Clear the prefs. + prefs::ClearSyncTransportOptIns(prefs_.get()); + ASSERT_FALSE(prefs::IsUserOptedInWalletSyncTransport(prefs_.get(), + active_info.account_id)); + + /////////////////////////////////////////////////////////// + // kSignedIn + /////////////////////////////////////////////////////////// + { + base::test::ScopedFeatureList scoped_features; + scoped_features.InitWithFeatures( + /*enabled_features=*/{}, + /*disabled_features=*/{features::kAutofillEnableAccountWalletStorage}); + + EXPECT_EQ(AutofillSyncSigninState::kSignedIn, + personal_data_->GetSyncSigninState()); + + // Make sure an opt-in does not get recorded even if the user accepted an + // Upstream offer. + personal_data_->OnUserAcceptedUpstreamOffer(); + EXPECT_FALSE(prefs::IsUserOptedInWalletSyncTransport( + prefs_.get(), active_info.account_id)); + } + + // Clear the prefs. + prefs::ClearSyncTransportOptIns(prefs_.get()); + ASSERT_FALSE(prefs::IsUserOptedInWalletSyncTransport(prefs_.get(), + active_info.account_id)); + + /////////////////////////////////////////////////////////// + // kSignedInAndSyncFeature + /////////////////////////////////////////////////////////// + sync_service_.SetIsAuthenticatedAccountPrimary(true); + { + EXPECT_EQ(AutofillSyncSigninState::kSignedInAndSyncFeature, + personal_data_->GetSyncSigninState()); + + // Make sure an opt-in does not get recorded even if the user accepted an + // Upstream offer. + personal_data_->OnUserAcceptedUpstreamOffer(); + EXPECT_FALSE(prefs::IsUserOptedInWalletSyncTransport( + prefs_.get(), active_info.account_id)); + } + + // Clear the prefs. + prefs::ClearSyncTransportOptIns(prefs_.get()); + ASSERT_FALSE(prefs::IsUserOptedInWalletSyncTransport(prefs_.get(), + active_info.account_id)); + + /////////////////////////////////////////////////////////// + // kSignedOut + /////////////////////////////////////////////////////////// +// ClearPrimaryAccount is not supported on CrOS. +#if !defined(OS_CHROMEOS) + { + identity_test_env_.ClearPrimaryAccount(); + EXPECT_EQ(AutofillSyncSigninState::kSignedOut, + personal_data_->GetSyncSigninState()); + + // Make sure an opt-in does not get recorded even if the user accepted an + // Upstream offer. + personal_data_->OnUserAcceptedUpstreamOffer(); + EXPECT_FALSE(prefs::IsUserOptedInWalletSyncTransport( + prefs_.get(), active_info.account_id)); + } +#endif // !defined(OS_CHROMEOS) +} + } // namespace autofill
diff --git a/components/autofill/core/browser/sync_utils.h b/components/autofill/core/browser/sync_utils.h index 124104c..2774bedb 100644 --- a/components/autofill/core/browser/sync_utils.h +++ b/components/autofill/core/browser/sync_utils.h
@@ -6,6 +6,8 @@ namespace autofill { +// Since these values are persisted to logs, they should not be re-numbered or +// removed. enum AutofillSyncSigninState { // The user is not signed in to Chromium. kSignedOut,
diff --git a/components/autofill/core/browser/ui/card_name_fix_flow_view_delegate_mobile.cc b/components/autofill/core/browser/ui/card_name_fix_flow_view_delegate_mobile.cc index db81f703..286c7e7 100644 --- a/components/autofill/core/browser/ui/card_name_fix_flow_view_delegate_mobile.cc +++ b/components/autofill/core/browser/ui/card_name_fix_flow_view_delegate_mobile.cc
@@ -21,9 +21,16 @@ : inferred_cardholder_name_(inferred_cardholder_name), upload_save_card_callback_(std::move(upload_save_card_callback)) { DCHECK(!upload_save_card_callback_.is_null()); + AutofillMetrics::LogSaveCardCardholderNamePrefilled( + !inferred_cardholder_name_.empty()); } -CardNameFixFlowViewDelegateMobile::~CardNameFixFlowViewDelegateMobile() {} +CardNameFixFlowViewDelegateMobile::~CardNameFixFlowViewDelegateMobile() { + if (!had_user_interaction_) + LogUserAction( + AutofillMetrics:: + CARDHOLDER_NAME_FIX_FLOW_PROMPT_CLOSED_WITHOUT_INTERACTION); +} int CardNameFixFlowViewDelegateMobile::GetIconId() const { return IDR_AUTOFILL_GOOGLE_PAY_WITH_DIVIDER; @@ -45,6 +52,24 @@ void CardNameFixFlowViewDelegateMobile::Accept(const base::string16& name) { std::move(upload_save_card_callback_).Run(name); + LogUserAction(AutofillMetrics::CARDHOLDER_NAME_FIX_FLOW_PROMPT_ACCEPTED); + AutofillMetrics::LogSaveCardCardholderNameWasEdited( + inferred_cardholder_name_ != name); +} + +void CardNameFixFlowViewDelegateMobile::Dismissed() { + LogUserAction(AutofillMetrics::CARDHOLDER_NAME_FIX_FLOW_PROMPT_DISMISSED); +} + +void CardNameFixFlowViewDelegateMobile::Shown() { + LogUserAction(AutofillMetrics::CARDHOLDER_NAME_FIX_FLOW_PROMPT_SHOWN); +} + +void CardNameFixFlowViewDelegateMobile::LogUserAction( + AutofillMetrics::CardholderNameFixFlowPromptEvent user_action) { + DCHECK(!had_user_interaction_); + AutofillMetrics::LogCardholderNameFixFlowPromptEvent(user_action); + had_user_interaction_ = true; } } // namespace autofill
diff --git a/components/autofill/core/browser/ui/card_name_fix_flow_view_delegate_mobile.h b/components/autofill/core/browser/ui/card_name_fix_flow_view_delegate_mobile.h index b048cb9..e769fda 100644 --- a/components/autofill/core/browser/ui/card_name_fix_flow_view_delegate_mobile.h +++ b/components/autofill/core/browser/ui/card_name_fix_flow_view_delegate_mobile.h
@@ -10,6 +10,7 @@ #include "base/callback.h" #include "base/macros.h" #include "base/strings/string16.h" +#include "components/autofill/core/browser/autofill_metrics.h" namespace autofill { @@ -29,8 +30,13 @@ base::string16 GetInferredCardHolderName() const; base::string16 GetSaveButtonLabel() const; void Accept(const base::string16& name); + void Dismissed(); + void Shown(); private: + void LogUserAction( + AutofillMetrics::CardholderNameFixFlowPromptEvent user_action); + // Inferred cardholder name from Gaia account. base::string16 inferred_cardholder_name_; @@ -38,6 +44,9 @@ // fix flow. base::OnceCallback<void(const base::string16&)> upload_save_card_callback_; + // Did the user ever explicitly accept or dismiss this prompt? + bool had_user_interaction_; + DISALLOW_COPY_AND_ASSIGN(CardNameFixFlowViewDelegateMobile); };
diff --git a/components/autofill/core/common/save_password_progress_logger.cc b/components/autofill/core/common/save_password_progress_logger.cc index 32094baf..f50881b7 100644 --- a/components/autofill/core/common/save_password_progress_logger.cc +++ b/components/autofill/core/common/save_password_progress_logger.cc
@@ -446,6 +446,16 @@ return "Form parsing input"; case STRING_FORM_PARSING_OUTPUT: return "Form parsing output"; + case STRING_FAILED_TO_FILL_INTO_IFRAME: + return "Failed to fill: Form is in iframe on a non-PSL-matching security " + "origin"; + case STRING_FAILED_TO_FILL_NO_AUTOCOMPLETEABLE_ELEMENT: + return "Failed to fill: No autocompleteable element found"; + case STRING_FAILED_TO_FILL_PREFILLED_USERNAME: + return "Failed to fill: Username field was prefilled, but no credential " + "exists whose username matches the prefilled value"; + case STRING_FAILED_TO_FILL_FOUND_NO_PASSWORD_FOR_USERNAME: + return "Failed to fill: No credential matching found"; case SavePasswordProgressLogger::STRING_INVALID: return "INVALID"; // Intentionally no default: clause here -- all IDs need to get covered.
diff --git a/components/autofill/core/common/save_password_progress_logger.h b/components/autofill/core/common/save_password_progress_logger.h index 40775e0..c000a5cf 100644 --- a/components/autofill/core/common/save_password_progress_logger.h +++ b/components/autofill/core/common/save_password_progress_logger.h
@@ -166,6 +166,10 @@ STRING_IS_FORM_TAG, STRING_FORM_PARSING_INPUT, STRING_FORM_PARSING_OUTPUT, + STRING_FAILED_TO_FILL_INTO_IFRAME, + STRING_FAILED_TO_FILL_NO_AUTOCOMPLETEABLE_ELEMENT, + STRING_FAILED_TO_FILL_PREFILLED_USERNAME, + STRING_FAILED_TO_FILL_FOUND_NO_PASSWORD_FOR_USERNAME, STRING_INVALID, // Represents a string returned in a case of an error. STRING_MAX = STRING_INVALID };
diff --git a/components/cryptauth/BUILD.gn b/components/cryptauth/BUILD.gn index 49de1e1..3287cb27 100644 --- a/components/cryptauth/BUILD.gn +++ b/components/cryptauth/BUILD.gn
@@ -93,8 +93,8 @@ "//chromeos", "//chromeos/components/multidevice", "//chromeos/components/proximity_auth/logging", + "//chromeos/services/device_sync/proto:util", "//components/cryptauth/ble", - "//components/cryptauth/proto:util", "//components/gcm_driver", "//components/gcm_driver/common", "//components/prefs", @@ -106,7 +106,7 @@ ] public_deps = [ - "//components/cryptauth/proto", + "//chromeos/services/device_sync/proto", ] # TODO (hansberry): Resolve this. @@ -156,7 +156,7 @@ public_deps = [ ":cryptauth", "//chromeos/components/multidevice", - "//components/cryptauth/proto", + "//chromeos/services/device_sync/proto", ] deps = [ @@ -198,8 +198,8 @@ "//base/test:test_support", "//chromeos/components/multidevice", "//chromeos/components/multidevice:test_support", + "//chromeos/services/device_sync/proto:util", "//components/cryptauth/ble:unit_tests", - "//components/cryptauth/proto:util", "//components/gcm_driver:test_support", "//components/prefs:test_support", "//google_apis:test_support",
diff --git a/components/cryptauth/background_eid_generator.cc b/components/cryptauth/background_eid_generator.cc index 747842a..e3167519 100644 --- a/components/cryptauth/background_eid_generator.cc +++ b/components/cryptauth/background_eid_generator.cc
@@ -13,7 +13,7 @@ #include "chromeos/components/multidevice/beacon_seed.h" #include "chromeos/components/multidevice/remote_device_ref.h" #include "chromeos/components/proximity_auth/logging/logging.h" -#include "components/cryptauth/proto/cryptauth_api.pb.h" +#include "chromeos/services/device_sync/proto/cryptauth_api.pb.h" #include "components/cryptauth/raw_eid_generator.h" #include "components/cryptauth/raw_eid_generator_impl.h"
diff --git a/components/cryptauth/background_eid_generator_unittest.cc b/components/cryptauth/background_eid_generator_unittest.cc index b14f2078..2040dcb 100644 --- a/components/cryptauth/background_eid_generator_unittest.cc +++ b/components/cryptauth/background_eid_generator_unittest.cc
@@ -14,7 +14,7 @@ #include "chromeos/components/multidevice/beacon_seed.h" #include "chromeos/components/multidevice/remote_device_ref.h" #include "chromeos/components/multidevice/remote_device_test_util.h" -#include "components/cryptauth/proto/cryptauth_api.pb.h" +#include "chromeos/services/device_sync/proto/cryptauth_api.pb.h" #include "components/cryptauth/raw_eid_generator_impl.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h"
diff --git a/components/cryptauth/ble/BUILD.gn b/components/cryptauth/ble/BUILD.gn index 5f216d0d..457f4a8c0 100644 --- a/components/cryptauth/ble/BUILD.gn +++ b/components/cryptauth/ble/BUILD.gn
@@ -36,7 +36,7 @@ ] public_deps = [ - "//components/cryptauth/proto", + "//chromeos/services/device_sync/proto", ] } @@ -55,7 +55,7 @@ ] public_deps = [ - "//components/cryptauth/proto", + "//chromeos/services/device_sync/proto", ] } @@ -85,6 +85,6 @@ ] public_deps = [ - "//components/cryptauth/proto", + "//chromeos/services/device_sync/proto", ] }
diff --git a/components/cryptauth/ble/ble_advertisement_generator_unittest.cc b/components/cryptauth/ble/ble_advertisement_generator_unittest.cc index b3d41cd..a9d87366 100644 --- a/components/cryptauth/ble/ble_advertisement_generator_unittest.cc +++ b/components/cryptauth/ble/ble_advertisement_generator_unittest.cc
@@ -12,8 +12,8 @@ #include "base/stl_util.h" #include "chromeos/components/multidevice/remote_device_ref.h" #include "chromeos/components/multidevice/remote_device_test_util.h" +#include "chromeos/services/device_sync/proto/cryptauth_api.pb.h" #include "components/cryptauth/mock_foreground_eid_generator.h" -#include "components/cryptauth/proto/cryptauth_api.pb.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h"
diff --git a/components/cryptauth/cryptauth_client.h b/components/cryptauth/cryptauth_client.h index 868748f..8830141 100644 --- a/components/cryptauth/cryptauth_client.h +++ b/components/cryptauth/cryptauth_client.h
@@ -37,7 +37,7 @@ // Implmentations shall only processes a single request, so create a new // instance for each request you make. DO NOT REUSE. // For documentation on each API call, see -// components/cryptauth/proto/cryptauth_api.proto +// chromeos/services/device_sync/proto/cryptauth_api.proto class CryptAuthClient { public: typedef base::Callback<void(NetworkRequestError)> ErrorCallback;
diff --git a/components/cryptauth/cryptauth_client_impl.h b/components/cryptauth/cryptauth_client_impl.h index 71e57be5..88d7c891 100644 --- a/components/cryptauth/cryptauth_client_impl.h +++ b/components/cryptauth/cryptauth_client_impl.h
@@ -7,9 +7,9 @@ #include "base/macros.h" #include "base/memory/weak_ptr.h" +#include "chromeos/services/device_sync/proto/cryptauth_api.pb.h" #include "components/cryptauth/cryptauth_api_call_flow.h" #include "components/cryptauth/cryptauth_client.h" -#include "components/cryptauth/proto/cryptauth_api.pb.h" #include "net/traffic_annotation/network_traffic_annotation.h" #include "services/identity/public/cpp/access_token_info.h"
diff --git a/components/cryptauth/cryptauth_client_impl_unittest.cc b/components/cryptauth/cryptauth_client_impl_unittest.cc index 180710e0..30ff617 100644 --- a/components/cryptauth/cryptauth_client_impl_unittest.cc +++ b/components/cryptauth/cryptauth_client_impl_unittest.cc
@@ -10,8 +10,8 @@ #include "base/test/gtest_util.h" #include "base/test/null_task_runner.h" #include "base/test/scoped_task_environment.h" +#include "chromeos/services/device_sync/proto/cryptauth_api.pb.h" #include "components/cryptauth/cryptauth_api_call_flow.h" -#include "components/cryptauth/proto/cryptauth_api.pb.h" #include "components/cryptauth/switches.h" #include "net/traffic_annotation/network_traffic_annotation_test_helper.h" #include "services/identity/public/cpp/identity_test_environment.h"
diff --git a/components/cryptauth/cryptauth_device_manager.h b/components/cryptauth/cryptauth_device_manager.h index b22848b..4ccb140d 100644 --- a/components/cryptauth/cryptauth_device_manager.h +++ b/components/cryptauth/cryptauth_device_manager.h
@@ -9,7 +9,7 @@ #include "base/macros.h" #include "base/observer_list.h" -#include "components/cryptauth/proto/cryptauth_api.pb.h" +#include "chromeos/services/device_sync/proto/cryptauth_api.pb.h" class PrefRegistrySimple;
diff --git a/components/cryptauth/cryptauth_device_manager_impl.cc b/components/cryptauth/cryptauth_device_manager_impl.cc index ea11dfcb..80fb72f8 100644 --- a/components/cryptauth/cryptauth_device_manager_impl.cc +++ b/components/cryptauth/cryptauth_device_manager_impl.cc
@@ -16,9 +16,9 @@ #include "base/strings/string_number_conversions.h" #include "chromeos/components/multidevice/software_feature_state.h" #include "chromeos/components/proximity_auth/logging/logging.h" +#include "chromeos/services/device_sync/proto/enum_util.h" #include "components/cryptauth/cryptauth_client.h" #include "components/cryptauth/pref_names.h" -#include "components/cryptauth/proto/enum_util.h" #include "components/cryptauth/sync_scheduler_impl.h" #include "components/prefs/pref_registry_simple.h" #include "components/prefs/pref_service.h"
diff --git a/components/cryptauth/cryptauth_device_manager_impl.h b/components/cryptauth/cryptauth_device_manager_impl.h index 936cd97..484c55b3 100644 --- a/components/cryptauth/cryptauth_device_manager_impl.h +++ b/components/cryptauth/cryptauth_device_manager_impl.h
@@ -11,10 +11,10 @@ #include "base/memory/weak_ptr.h" #include "base/time/clock.h" #include "base/time/time.h" +#include "chromeos/services/device_sync/proto/cryptauth_api.pb.h" #include "components/cryptauth/cryptauth_device_manager.h" #include "components/cryptauth/cryptauth_gcm_manager.h" #include "components/cryptauth/network_request_error.h" -#include "components/cryptauth/proto/cryptauth_api.pb.h" #include "components/cryptauth/sync_scheduler.h" class PrefService;
diff --git a/components/cryptauth/cryptauth_device_manager_impl_unittest.cc b/components/cryptauth/cryptauth_device_manager_impl_unittest.cc index e3db395..4a5371e 100644 --- a/components/cryptauth/cryptauth_device_manager_impl_unittest.cc +++ b/components/cryptauth/cryptauth_device_manager_impl_unittest.cc
@@ -18,12 +18,12 @@ #include "base/test/metrics/histogram_tester.h" #include "base/test/simple_test_clock.h" #include "chromeos/components/multidevice/software_feature_state.h" +#include "chromeos/services/device_sync/proto/enum_util.h" #include "components/cryptauth/fake_cryptauth_gcm_manager.h" #include "components/cryptauth/mock_cryptauth_client.h" #include "components/cryptauth/mock_sync_scheduler.h" #include "components/cryptauth/network_request_error.h" #include "components/cryptauth/pref_names.h" -#include "components/cryptauth/proto/enum_util.h" #include "components/prefs/scoped_user_pref_update.h" #include "components/prefs/testing_pref_service.h" #include "net/traffic_annotation/network_traffic_annotation_test_helper.h"
diff --git a/components/cryptauth/cryptauth_enroller.h b/components/cryptauth/cryptauth_enroller.h index 9a72d33a..c62dc6d 100644 --- a/components/cryptauth/cryptauth_enroller.h +++ b/components/cryptauth/cryptauth_enroller.h
@@ -9,7 +9,7 @@ #include <string> #include "base/callback_forward.h" -#include "components/cryptauth/proto/cryptauth_api.pb.h" +#include "chromeos/services/device_sync/proto/cryptauth_api.pb.h" namespace cryptauth {
diff --git a/components/cryptauth/cryptauth_enroller_impl.h b/components/cryptauth/cryptauth_enroller_impl.h index aa3c6e3..32a870d 100644 --- a/components/cryptauth/cryptauth_enroller_impl.h +++ b/components/cryptauth/cryptauth_enroller_impl.h
@@ -10,9 +10,9 @@ #include "base/callback.h" #include "base/macros.h" #include "base/memory/weak_ptr.h" +#include "chromeos/services/device_sync/proto/cryptauth_api.pb.h" #include "components/cryptauth/cryptauth_enroller.h" #include "components/cryptauth/network_request_error.h" -#include "components/cryptauth/proto/cryptauth_api.pb.h" namespace cryptauth {
diff --git a/components/cryptauth/cryptauth_enrollment_manager.h b/components/cryptauth/cryptauth_enrollment_manager.h index 4a5d1c8..cadad1d0 100644 --- a/components/cryptauth/cryptauth_enrollment_manager.h +++ b/components/cryptauth/cryptauth_enrollment_manager.h
@@ -10,7 +10,7 @@ #include "base/macros.h" #include "base/observer_list.h" #include "base/time/time.h" -#include "components/cryptauth/proto/cryptauth_api.pb.h" +#include "chromeos/services/device_sync/proto/cryptauth_api.pb.h" class PrefRegistrySimple;
diff --git a/components/cryptauth/cryptauth_enrollment_manager_impl.cc b/components/cryptauth/cryptauth_enrollment_manager_impl.cc index 5681671..4f66afa 100644 --- a/components/cryptauth/cryptauth_enrollment_manager_impl.cc +++ b/components/cryptauth/cryptauth_enrollment_manager_impl.cc
@@ -13,9 +13,9 @@ #include "base/time/clock.h" #include "base/time/time.h" #include "chromeos/components/proximity_auth/logging/logging.h" +#include "chromeos/services/device_sync/proto/enum_util.h" #include "components/cryptauth/cryptauth_enroller.h" #include "components/cryptauth/pref_names.h" -#include "components/cryptauth/proto/enum_util.h" #include "components/cryptauth/secure_message_delegate.h" #include "components/cryptauth/sync_scheduler_impl.h" #include "components/prefs/pref_registry_simple.h"
diff --git a/components/cryptauth/cryptauth_enrollment_manager_impl.h b/components/cryptauth/cryptauth_enrollment_manager_impl.h index 1b758c5d..34ec300 100644 --- a/components/cryptauth/cryptauth_enrollment_manager_impl.h +++ b/components/cryptauth/cryptauth_enrollment_manager_impl.h
@@ -11,9 +11,9 @@ #include "base/memory/weak_ptr.h" #include "base/observer_list.h" #include "base/time/time.h" +#include "chromeos/services/device_sync/proto/cryptauth_api.pb.h" #include "components/cryptauth/cryptauth_enrollment_manager.h" #include "components/cryptauth/cryptauth_gcm_manager.h" -#include "components/cryptauth/proto/cryptauth_api.pb.h" #include "components/cryptauth/sync_scheduler.h" class PrefService;
diff --git a/components/cryptauth/cryptauth_service.h b/components/cryptauth/cryptauth_service.h index f63a184c..27546cd 100644 --- a/components/cryptauth/cryptauth_service.h +++ b/components/cryptauth/cryptauth_service.h
@@ -8,7 +8,7 @@ #include <memory> #include "base/macros.h" -#include "components/cryptauth/proto/cryptauth_api.pb.h" +#include "chromeos/services/device_sync/proto/cryptauth_api.pb.h" #include "components/prefs/pref_registry_simple.h" namespace cryptauth {
diff --git a/components/cryptauth/device_classifier_util.h b/components/cryptauth/device_classifier_util.h index 71bd093..0c2bb6ee 100644 --- a/components/cryptauth/device_classifier_util.h +++ b/components/cryptauth/device_classifier_util.h
@@ -5,7 +5,7 @@ #ifndef COMPONENTS_CRYPTAUTH_DEVICE_CLASSIFIER_UTIL_H_ #define COMPONENTS_CRYPTAUTH_DEVICE_CLASSIFIER_UTIL_H_ -#include "components/cryptauth/proto/cryptauth_api.pb.h" +#include "chromeos/services/device_sync/proto/cryptauth_api.pb.h" namespace cryptauth {
diff --git a/components/cryptauth/device_to_device_initiator_helper.cc b/components/cryptauth/device_to_device_initiator_helper.cc index ad9ff7b6..2d37f105 100644 --- a/components/cryptauth/device_to_device_initiator_helper.cc +++ b/components/cryptauth/device_to_device_initiator_helper.cc
@@ -7,7 +7,7 @@ #include "base/bind.h" #include "base/callback.h" #include "chromeos/components/proximity_auth/logging/logging.h" -#include "components/cryptauth/proto/cryptauth_api.pb.h" +#include "chromeos/services/device_sync/proto/cryptauth_api.pb.h" #include "components/cryptauth/secure_message_delegate.h" namespace cryptauth {
diff --git a/components/cryptauth/device_to_device_initiator_helper.h b/components/cryptauth/device_to_device_initiator_helper.h index c9627f9..a38952d 100644 --- a/components/cryptauth/device_to_device_initiator_helper.h +++ b/components/cryptauth/device_to_device_initiator_helper.h
@@ -11,7 +11,7 @@ #include "base/callback.h" #include "base/macros.h" #include "base/memory/weak_ptr.h" -#include "components/cryptauth/proto/securemessage.pb.h" +#include "chromeos/services/device_sync/proto/securemessage.pb.h" #include "components/cryptauth/session_keys.h" namespace cryptauth {
diff --git a/components/cryptauth/device_to_device_responder_operations.cc b/components/cryptauth/device_to_device_responder_operations.cc index 6a70960..9ed64fa 100644 --- a/components/cryptauth/device_to_device_responder_operations.cc +++ b/components/cryptauth/device_to_device_responder_operations.cc
@@ -7,8 +7,8 @@ #include "base/bind.h" #include "base/callback.h" #include "chromeos/components/proximity_auth/logging/logging.h" -#include "components/cryptauth/proto/cryptauth_api.pb.h" -#include "components/cryptauth/proto/securemessage.pb.h" +#include "chromeos/services/device_sync/proto/cryptauth_api.pb.h" +#include "chromeos/services/device_sync/proto/securemessage.pb.h" #include "components/cryptauth/secure_message_delegate.h" namespace cryptauth {
diff --git a/components/cryptauth/device_to_device_secure_context.cc b/components/cryptauth/device_to_device_secure_context.cc index 1b80e230..9ce2cc57 100644 --- a/components/cryptauth/device_to_device_secure_context.cc +++ b/components/cryptauth/device_to_device_secure_context.cc
@@ -9,8 +9,8 @@ #include "base/bind.h" #include "base/callback.h" #include "chromeos/components/proximity_auth/logging/logging.h" -#include "components/cryptauth/proto/cryptauth_api.pb.h" -#include "components/cryptauth/proto/securemessage.pb.h" +#include "chromeos/services/device_sync/proto/cryptauth_api.pb.h" +#include "chromeos/services/device_sync/proto/securemessage.pb.h" #include "components/cryptauth/secure_message_delegate.h" namespace cryptauth {
diff --git a/components/cryptauth/device_to_device_secure_context_unittest.cc b/components/cryptauth/device_to_device_secure_context_unittest.cc index 388cea6..5ade1cd 100644 --- a/components/cryptauth/device_to_device_secure_context_unittest.cc +++ b/components/cryptauth/device_to_device_secure_context_unittest.cc
@@ -8,9 +8,9 @@ #include "base/bind.h" #include "base/callback.h" +#include "chromeos/services/device_sync/proto/cryptauth_api.pb.h" +#include "chromeos/services/device_sync/proto/securemessage.pb.h" #include "components/cryptauth/fake_secure_message_delegate.h" -#include "components/cryptauth/proto/cryptauth_api.pb.h" -#include "components/cryptauth/proto/securemessage.pb.h" #include "components/cryptauth/session_keys.h" #include "testing/gtest/include/gtest/gtest.h"
diff --git a/components/cryptauth/fake_cryptauth_device_manager.h b/components/cryptauth/fake_cryptauth_device_manager.h index 459990e5..8d5bf3e9 100644 --- a/components/cryptauth/fake_cryptauth_device_manager.h +++ b/components/cryptauth/fake_cryptauth_device_manager.h
@@ -8,8 +8,8 @@ #include <memory> #include "base/macros.h" +#include "chromeos/services/device_sync/proto/cryptauth_api.pb.h" #include "components/cryptauth/cryptauth_device_manager.h" -#include "components/cryptauth/proto/cryptauth_api.pb.h" namespace cryptauth {
diff --git a/components/cryptauth/fake_cryptauth_enrollment_manager.h b/components/cryptauth/fake_cryptauth_enrollment_manager.h index fe3ac91..810ba4a5 100644 --- a/components/cryptauth/fake_cryptauth_enrollment_manager.h +++ b/components/cryptauth/fake_cryptauth_enrollment_manager.h
@@ -10,8 +10,8 @@ #include "base/macros.h" #include "base/optional.h" #include "base/time/time.h" +#include "chromeos/services/device_sync/proto/cryptauth_api.pb.h" #include "components/cryptauth/cryptauth_enrollment_manager.h" -#include "components/cryptauth/proto/cryptauth_api.pb.h" namespace cryptauth {
diff --git a/components/cryptauth/fake_cryptauth_service.h b/components/cryptauth/fake_cryptauth_service.h index c19a8173..9b4d651 100644 --- a/components/cryptauth/fake_cryptauth_service.h +++ b/components/cryptauth/fake_cryptauth_service.h
@@ -8,8 +8,8 @@ #include <memory> #include "base/macros.h" +#include "chromeos/services/device_sync/proto/cryptauth_api.pb.h" #include "components/cryptauth/cryptauth_service.h" -#include "components/cryptauth/proto/cryptauth_api.pb.h" namespace cryptauth {
diff --git a/components/cryptauth/fake_gcm_device_info_provider.h b/components/cryptauth/fake_gcm_device_info_provider.h index 324532ad..e3084f0 100644 --- a/components/cryptauth/fake_gcm_device_info_provider.h +++ b/components/cryptauth/fake_gcm_device_info_provider.h
@@ -6,8 +6,8 @@ #define COMPONENTS_CRYPTAUTH_FAKE_GCM_DEVICE_INFO_PROVIDER_H_ #include "base/macros.h" +#include "chromeos/services/device_sync/proto/cryptauth_api.pb.h" #include "components/cryptauth/gcm_device_info_provider.h" -#include "components/cryptauth/proto/cryptauth_api.pb.h" namespace cryptauth {
diff --git a/components/cryptauth/foreground_eid_generator.cc b/components/cryptauth/foreground_eid_generator.cc index e13271a..ffb4bf8 100644 --- a/components/cryptauth/foreground_eid_generator.cc +++ b/components/cryptauth/foreground_eid_generator.cc
@@ -13,7 +13,7 @@ #include "base/time/time.h" #include "chromeos/components/multidevice/remote_device_ref.h" #include "chromeos/components/proximity_auth/logging/logging.h" -#include "components/cryptauth/proto/cryptauth_api.pb.h" +#include "chromeos/services/device_sync/proto/cryptauth_api.pb.h" #include "components/cryptauth/raw_eid_generator.h" #include "components/cryptauth/raw_eid_generator_impl.h"
diff --git a/components/cryptauth/foreground_eid_generator_unittest.cc b/components/cryptauth/foreground_eid_generator_unittest.cc index 5d81131..ea099e3 100644 --- a/components/cryptauth/foreground_eid_generator_unittest.cc +++ b/components/cryptauth/foreground_eid_generator_unittest.cc
@@ -11,7 +11,7 @@ #include "base/test/simple_test_clock.h" #include "base/time/time.h" #include "chromeos/components/multidevice/remote_device_ref.h" -#include "components/cryptauth/proto/cryptauth_api.pb.h" +#include "chromeos/services/device_sync/proto/cryptauth_api.pb.h" #include "components/cryptauth/raw_eid_generator_impl.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h"
diff --git a/components/cryptauth/gcm_device_info_provider.h b/components/cryptauth/gcm_device_info_provider.h index f508a62..dd4070f 100644 --- a/components/cryptauth/gcm_device_info_provider.h +++ b/components/cryptauth/gcm_device_info_provider.h
@@ -6,7 +6,7 @@ #define COMPONENTS_CRYPTAUTH_GCM_DEVICE_INFO_PROVIDER_H_ #include "base/macros.h" -#include "components/cryptauth/proto/cryptauth_api.pb.h" +#include "chromeos/services/device_sync/proto/cryptauth_api.pb.h" namespace cryptauth {
diff --git a/components/cryptauth/mock_cryptauth_client.h b/components/cryptauth/mock_cryptauth_client.h index c0e9189..9592265 100644 --- a/components/cryptauth/mock_cryptauth_client.h +++ b/components/cryptauth/mock_cryptauth_client.h
@@ -7,8 +7,8 @@ #include "base/macros.h" #include "base/observer_list.h" +#include "chromeos/services/device_sync/proto/cryptauth_api.pb.h" #include "components/cryptauth/cryptauth_client.h" -#include "components/cryptauth/proto/cryptauth_api.pb.h" #include "testing/gmock/include/gmock/gmock.h" namespace cryptauth {
diff --git a/components/cryptauth/pref_names.cc b/components/cryptauth/pref_names.cc index adb1330..b0675aa 100644 --- a/components/cryptauth/pref_names.cc +++ b/components/cryptauth/pref_names.cc
@@ -18,7 +18,7 @@ // The reason that the next device_sync is performed. This should be one of the // enum values of InvocationReason in -// components/cryptauth/proto/cryptauth_api.proto. +// chromeos/services/device_sync/proto/cryptauth_api.proto. const char kCryptAuthDeviceSyncReason[] = "cryptauth.device_sync.reason"; // A list of unlock keys (stored as dictionaries) synced from CryptAuth. Unlock @@ -38,7 +38,7 @@ // The reason that the next enrollment is performed. This should be one of the // enum values of InvocationReason in -// components/cryptauth/proto/cryptauth_api.proto. +// chromeos/services/device_sync/proto/cryptauth_api.proto. const char kCryptAuthEnrollmentReason[] = "cryptauth.enrollment.reason"; // The public key of the user and device enrolled with CryptAuth.
diff --git a/components/cryptauth/remote_device_loader.cc b/components/cryptauth/remote_device_loader.cc index d1d35326..04143c58 100644 --- a/components/cryptauth/remote_device_loader.cc +++ b/components/cryptauth/remote_device_loader.cc
@@ -14,7 +14,7 @@ #include "chromeos/components/multidevice/remote_device_ref.h" #include "chromeos/components/multidevice/software_feature.h" #include "chromeos/components/proximity_auth/logging/logging.h" -#include "components/cryptauth/proto/enum_util.h" +#include "chromeos/services/device_sync/proto/enum_util.h" #include "components/cryptauth/secure_message_delegate.h" namespace cryptauth {
diff --git a/components/cryptauth/remote_device_loader.h b/components/cryptauth/remote_device_loader.h index c716d48..937e1f6 100644 --- a/components/cryptauth/remote_device_loader.h +++ b/components/cryptauth/remote_device_loader.h
@@ -12,7 +12,7 @@ #include "base/macros.h" #include "base/memory/weak_ptr.h" #include "chromeos/components/multidevice/remote_device.h" -#include "components/cryptauth/proto/cryptauth_api.pb.h" +#include "chromeos/services/device_sync/proto/cryptauth_api.pb.h" namespace cryptauth {
diff --git a/components/cryptauth/remote_device_loader_unittest.cc b/components/cryptauth/remote_device_loader_unittest.cc index ce8db53..ac2a1fc9 100644 --- a/components/cryptauth/remote_device_loader_unittest.cc +++ b/components/cryptauth/remote_device_loader_unittest.cc
@@ -11,8 +11,8 @@ #include "base/bind.h" #include "base/macros.h" +#include "chromeos/services/device_sync/proto/enum_util.h" #include "components/cryptauth/fake_secure_message_delegate.h" -#include "components/cryptauth/proto/enum_util.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h"
diff --git a/components/cryptauth/remote_device_provider_impl_unittest.cc b/components/cryptauth/remote_device_provider_impl_unittest.cc index e3e2f58c4..16ce82a1 100644 --- a/components/cryptauth/remote_device_provider_impl_unittest.cc +++ b/components/cryptauth/remote_device_provider_impl_unittest.cc
@@ -11,10 +11,10 @@ #include "base/memory/ptr_util.h" #include "base/run_loop.h" #include "chromeos/components/multidevice/remote_device_test_util.h" +#include "chromeos/services/device_sync/proto/cryptauth_api.pb.h" #include "components/cryptauth/cryptauth_device_manager.h" #include "components/cryptauth/fake_cryptauth_device_manager.h" #include "components/cryptauth/fake_secure_message_delegate.h" -#include "components/cryptauth/proto/cryptauth_api.pb.h" #include "components/cryptauth/remote_device_loader.h" #include "components/cryptauth/secure_message_delegate_impl.h" #include "testing/gmock/include/gmock/gmock.h"
diff --git a/components/cryptauth/secure_message_delegate.h b/components/cryptauth/secure_message_delegate.h index 2f02f58d..f58035c 100644 --- a/components/cryptauth/secure_message_delegate.h +++ b/components/cryptauth/secure_message_delegate.h
@@ -9,7 +9,7 @@ #include <string> #include "base/callback_forward.h" -#include "components/cryptauth/proto/securemessage.pb.h" +#include "chromeos/services/device_sync/proto/securemessage.pb.h" namespace cryptauth {
diff --git a/components/cryptauth/software_feature_manager_impl.cc b/components/cryptauth/software_feature_manager_impl.cc index 34bc506..fd07733 100644 --- a/components/cryptauth/software_feature_manager_impl.cc +++ b/components/cryptauth/software_feature_manager_impl.cc
@@ -9,8 +9,8 @@ #include "base/logging.h" #include "base/memory/ptr_util.h" #include "base/no_destructor.h" -#include "components/cryptauth/proto/cryptauth_api.pb.h" -#include "components/cryptauth/proto/enum_util.h" +#include "chromeos/services/device_sync/proto/cryptauth_api.pb.h" +#include "chromeos/services/device_sync/proto/enum_util.h" namespace cryptauth {
diff --git a/components/cryptauth/software_feature_manager_impl.h b/components/cryptauth/software_feature_manager_impl.h index a490d99..82c4cffa 100644 --- a/components/cryptauth/software_feature_manager_impl.h +++ b/components/cryptauth/software_feature_manager_impl.h
@@ -9,8 +9,8 @@ #include "base/callback_forward.h" #include "base/containers/queue.h" #include "base/memory/weak_ptr.h" +#include "chromeos/services/device_sync/proto/cryptauth_api.pb.h" #include "components/cryptauth/cryptauth_client.h" -#include "components/cryptauth/proto/cryptauth_api.pb.h" #include "components/cryptauth/software_feature_manager.h" namespace cryptauth {
diff --git a/components/cryptauth/software_feature_manager_impl_unittest.cc b/components/cryptauth/software_feature_manager_impl_unittest.cc index 66fb9ff..8561464 100644 --- a/components/cryptauth/software_feature_manager_impl_unittest.cc +++ b/components/cryptauth/software_feature_manager_impl_unittest.cc
@@ -9,8 +9,8 @@ #include "chromeos/components/multidevice/remote_device_ref.h" #include "chromeos/components/multidevice/remote_device_test_util.h" #include "chromeos/components/multidevice/software_feature.h" +#include "chromeos/services/device_sync/proto/enum_util.h" #include "components/cryptauth/mock_cryptauth_client.h" -#include "components/cryptauth/proto/enum_util.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h"
diff --git a/components/omnibox/browser/BUILD.gn b/components/omnibox/browser/BUILD.gn index b6b7f59..78fcee34 100644 --- a/components/omnibox/browser/BUILD.gn +++ b/components/omnibox/browser/BUILD.gn
@@ -5,9 +5,9 @@ import("//build/buildflag_header.gni") import("//build/config/jumbo.gni") import("//build/config/ui.gni") +import("//components/vector_icons/vector_icons.gni") import("//device/vr/buildflags/buildflags.gni") import("//third_party/protobuf/proto_library.gni") -import("//components/vector_icons/vector_icons.gni") if (is_android) { import("//build/config/android/rules.gni") @@ -156,8 +156,6 @@ "omnibox_pref_names.h", "omnibox_view.cc", "omnibox_view.h", - "query_in_omnibox.cc", - "query_in_omnibox.h", "scored_history_match.cc", "scored_history_match.h", "search_provider.cc", @@ -380,7 +378,6 @@ "omnibox_pedal_unittest.cc", "omnibox_popup_model_unittest.cc", "omnibox_view_unittest.cc", - "query_in_omnibox_unittest.cc", "scored_history_match_unittest.cc", "search_suggestion_parser_unittest.cc", "shortcuts_backend_unittest.cc",
diff --git a/components/omnibox/browser/location_bar_model.h b/components/omnibox/browser/location_bar_model.h index 70c3a6c2..bb9faf5 100644 --- a/components/omnibox/browser/location_bar_model.h +++ b/components/omnibox/browser/location_bar_model.h
@@ -48,9 +48,13 @@ virtual security_state::SecurityLevel GetSecurityLevel( bool ignore_editing) const = 0; - // Returns whether the connection security fields have been initialized. - // After a navigation, this is false until the TLS state is updated. - virtual bool IsSecurityInfoInitialized() const = 0; + // Returns true if the toolbar should display the search terms. When this + // method returns true, the extracted search terms will be filled into + // |search_terms| if it's not nullptr. + // + // This method can be called with nullptr |search_terms| if the caller wants + // to check the display status only. Virtual for testing purposes. + virtual bool GetDisplaySearchTerms(base::string16* search_terms) = 0; // Returns the id of the icon to show to the left of the address, based on the // current URL. When search term replacement is active, this returns a search
diff --git a/components/omnibox/browser/location_bar_model_delegate.cc b/components/omnibox/browser/location_bar_model_delegate.cc index 1268f79..1eb9dc51 100644 --- a/components/omnibox/browser/location_bar_model_delegate.cc +++ b/components/omnibox/browser/location_bar_model_delegate.cc
@@ -33,3 +33,11 @@ bool LocationBarModelDelegate::IsOfflinePage() const { return false; } + +AutocompleteClassifier* LocationBarModelDelegate::GetAutocompleteClassifier() { + return nullptr; +} + +TemplateURLService* LocationBarModelDelegate::GetTemplateURLService() { + return nullptr; +}
diff --git a/components/omnibox/browser/location_bar_model_delegate.h b/components/omnibox/browser/location_bar_model_delegate.h index ce96972..0d523b9 100644 --- a/components/omnibox/browser/location_bar_model_delegate.h +++ b/components/omnibox/browser/location_bar_model_delegate.h
@@ -11,7 +11,9 @@ #include "base/strings/string16.h" #include "components/security_state/core/security_state.h" +class AutocompleteClassifier; class GURL; +class TemplateURLService; namespace gfx { struct VectorIcon; @@ -61,6 +63,12 @@ // previously-downloaded content. virtual bool IsOfflinePage() const; + // Returns the AutocompleteClassifier instance for the current page. + virtual AutocompleteClassifier* GetAutocompleteClassifier(); + + // Returns the TemplateURLService instance for the current page. + virtual TemplateURLService* GetTemplateURLService(); + protected: virtual ~LocationBarModelDelegate() {} };
diff --git a/components/omnibox/browser/location_bar_model_impl.cc b/components/omnibox/browser/location_bar_model_impl.cc index 78f4781..e03be9e 100644 --- a/components/omnibox/browser/location_bar_model_impl.cc +++ b/components/omnibox/browser/location_bar_model_impl.cc
@@ -10,10 +10,13 @@ #include "base/strings/utf_string_conversions.h" #include "base/time/time.h" #include "build/build_config.h" +#include "components/omnibox/browser/autocomplete_classifier.h" +#include "components/omnibox/browser/autocomplete_match.h" #include "components/omnibox/browser/buildflags.h" #include "components/omnibox/browser/location_bar_model_delegate.h" #include "components/omnibox/browser/omnibox_field_trial.h" #include "components/prefs/pref_service.h" +#include "components/search_engines/template_url_service.h" #include "components/security_state/core/security_state.h" #include "components/strings/grit/components_strings.h" #include "net/cert/cert_status_flags.h" @@ -103,10 +106,28 @@ return info.security_level; } -bool LocationBarModelImpl::IsSecurityInfoInitialized() const { +bool LocationBarModelImpl::GetDisplaySearchTerms(base::string16* search_terms) { + if (!base::FeatureList::IsEnabled(omnibox::kQueryInOmnibox)) + return false; + + // Only show the search terms if the site is secure. However, make an + // exception before the security state is initialized to prevent a UI flicker. security_state::SecurityInfo info; delegate_->GetSecurityInfo(&info); - return info.connection_info_initialized; + if (info.connection_info_initialized && + info.security_level != security_state::SecurityLevel::SECURE && + info.security_level != security_state::SecurityLevel::EV_SECURE) { + return false; + } + + base::string16 extracted_search_terms = ExtractSearchTermsInternal(GetURL()); + if (extracted_search_terms.empty()) + return false; + + if (search_terms) + *search_terms = extracted_search_terms; + + return true; } const gfx::VectorIcon& LocationBarModelImpl::GetVectorIcon() const { @@ -228,3 +249,45 @@ bool LocationBarModelImpl::IsOfflinePage() const { return delegate_->IsOfflinePage(); } + +base::string16 LocationBarModelImpl::ExtractSearchTermsInternal( + const GURL& url) { + AutocompleteClassifier* autocomplete_classifier = + delegate_->GetAutocompleteClassifier(); + TemplateURLService* template_url_service = delegate_->GetTemplateURLService(); + if (!autocomplete_classifier || !template_url_service) + return base::string16(); + + if (url.is_empty()) + return base::string16(); + + // Because we cache keyed by URL, if the user changes the default search + // provider, we will continue to extract the search terms from the cached URL + // (even if it's no longer from the default search provider) until the user + // changes tabs or navigates the tab. That is intentional, as it would be + // weird otherwise if the omnibox text changed without any user gesture. + if (url != cached_url_) { + cached_url_ = url; + cached_search_terms_.clear(); + + const TemplateURL* default_provider = + template_url_service->GetDefaultSearchProvider(); + if (default_provider) { + // If |url| doesn't match the default search provider, + // |cached_search_terms_| will remain empty. + default_provider->ExtractSearchTermsFromURL( + url, template_url_service->search_terms_data(), + &cached_search_terms_); + + // Clear out the search terms if it looks like a URL. + AutocompleteMatch match; + autocomplete_classifier->Classify( + cached_search_terms_, false, false, + metrics::OmniboxEventProto::INVALID_SPEC, &match, nullptr); + if (!AutocompleteMatch::IsSearchType(match.type)) + cached_search_terms_.clear(); + } + } + + return cached_search_terms_; +}
diff --git a/components/omnibox/browser/location_bar_model_impl.h b/components/omnibox/browser/location_bar_model_impl.h index 8277cad5..f2da5d9 100644 --- a/components/omnibox/browser/location_bar_model_impl.h +++ b/components/omnibox/browser/location_bar_model_impl.h
@@ -33,7 +33,7 @@ GURL GetURL() const override; security_state::SecurityLevel GetSecurityLevel( bool ignore_editing) const override; - bool IsSecurityInfoInitialized() const override; + bool GetDisplaySearchTerms(base::string16* search_terms) override; const gfx::VectorIcon& GetVectorIcon() const override; base::string16 GetSecureDisplayText() const override; base::string16 GetSecureAccessibilityText() const override; @@ -59,9 +59,20 @@ base::string16 GetFormattedURL( url_formatter::FormatUrlTypes format_types) const; + // Extracts search terms from |url|. Returns an empty string if |url| is not + // from the default search provider, if there are no search terms in |url|, + // or if the extracted search terms look too much like a URL. + base::string16 ExtractSearchTermsInternal(const GURL& url); + LocationBarModelDelegate* delegate_; const size_t max_url_display_chars_; + // Because extracting search terms from a URL string is relatively expensive, + // and we want to support cheap calls to GetDisplaySearchTerms, cache the + // result of the last-parsed URL string. + base::string16 cached_search_terms_; + GURL cached_url_; + DISALLOW_IMPLICIT_CONSTRUCTORS(LocationBarModelImpl); };
diff --git a/components/omnibox/browser/location_bar_model_impl_unittest.cc b/components/omnibox/browser/location_bar_model_impl_unittest.cc index 2c3a642e..7dea081 100644 --- a/components/omnibox/browser/location_bar_model_impl_unittest.cc +++ b/components/omnibox/browser/location_bar_model_impl_unittest.cc
@@ -6,8 +6,10 @@ #include "base/strings/utf_string_conversions.h" #include "base/test/scoped_feature_list.h" +#include "base/test/scoped_task_environment.h" #include "components/omnibox/browser/location_bar_model_delegate.h" #include "components/omnibox/browser/omnibox_field_trial.h" +#include "components/omnibox/browser/test_omnibox_client.h" #include "testing/gtest/include/gtest/gtest.h" #include "url/gurl.h" @@ -16,6 +18,9 @@ class FakeLocationBarModelDelegate : public LocationBarModelDelegate { public: void SetURL(const GURL& url) { url_ = url; } + void SetSecurityInfo(const security_state::SecurityInfo& info) { + security_info_ = info; + } // LocationBarModelDelegate: base::string16 FormattedStringWithEquivalentMeaning( @@ -29,28 +34,162 @@ return true; } + void GetSecurityInfo(security_state::SecurityInfo* result) const override { + *result = security_info_; + } + + AutocompleteClassifier* GetAutocompleteClassifier() override { + return omnibox_client_.GetAutocompleteClassifier(); + } + + TemplateURLService* GetTemplateURLService() override { + return omnibox_client_.GetTemplateURLService(); + } + private: GURL url_; + security_state::SecurityInfo security_info_; + TestOmniboxClient omnibox_client_; }; -TEST(LocationBarModelImplTest, - DisplayUrlAppliesFormattedStringWithEquivalentMeaning) { +class LocationBarModelImplTest : public testing::Test { + protected: + const GURL kValidSearchResultsPage = + GURL("https://www.google.com/search?q=foo+query"); + + LocationBarModelImplTest() : model_(&delegate_, 1024) {} + + FakeLocationBarModelDelegate* delegate() { return &delegate_; } + + LocationBarModelImpl* model() { return &model_; } + + private: + base::test::ScopedTaskEnvironment task_environment_; + FakeLocationBarModelDelegate delegate_; + LocationBarModelImpl model_; +}; + +TEST_F(LocationBarModelImplTest, + DisplayUrlAppliesFormattedStringWithEquivalentMeaning) { base::test::ScopedFeatureList feature_list; feature_list.InitWithFeatures({omnibox::kHideSteadyStateUrlScheme, omnibox::kHideSteadyStateUrlTrivialSubdomains}, {}); - FakeLocationBarModelDelegate delegate; - auto model = std::make_unique<LocationBarModelImpl>(&delegate, 1024); - - delegate.SetURL(GURL("http://www.google.com/")); + delegate()->SetURL(GURL("http://www.google.com/")); // Verify that both the full formatted URL and the display URL add the test // suffix. EXPECT_EQ(base::ASCIIToUTF16("www.google.com/TestSuffix"), - model->GetFormattedFullURL()); + model()->GetFormattedFullURL()); EXPECT_EQ(base::ASCIIToUTF16("google.com/TestSuffix"), - model->GetURLForDisplay()); + model()->GetURLForDisplay()); +} + +TEST_F(LocationBarModelImplTest, QueryInOmniboxFeatureFlagWorks) { + delegate()->SetURL(kValidSearchResultsPage); + security_state::SecurityInfo info; + info.connection_info_initialized = true; + info.security_level = security_state::SecurityLevel::SECURE; + delegate()->SetSecurityInfo(info); + + EXPECT_FALSE(model()->GetDisplaySearchTerms(nullptr)); + + base::test::ScopedFeatureList scoped_feature_list; + scoped_feature_list.InitAndEnableFeature(omnibox::kQueryInOmnibox); + + EXPECT_TRUE(model()->GetDisplaySearchTerms(nullptr)); +} + +TEST_F(LocationBarModelImplTest, QueryInOmniboxSecurityLevel) { + base::test::ScopedFeatureList scoped_feature_list; + scoped_feature_list.InitAndEnableFeature(omnibox::kQueryInOmnibox); + + delegate()->SetURL(kValidSearchResultsPage); + + security_state::SecurityInfo info; + info.connection_info_initialized = true; + + info.security_level = security_state::SecurityLevel::SECURE; + delegate()->SetSecurityInfo(info); + EXPECT_TRUE(model()->GetDisplaySearchTerms(nullptr)); + + info.security_level = security_state::SecurityLevel::EV_SECURE; + delegate()->SetSecurityInfo(info); + EXPECT_TRUE(model()->GetDisplaySearchTerms(nullptr)); + + // Insecure levels should not be allowed to display search terms. + info.security_level = security_state::SecurityLevel::NONE; + delegate()->SetSecurityInfo(info); + EXPECT_FALSE(model()->GetDisplaySearchTerms(nullptr)); + + info.security_level = security_state::SecurityLevel::DANGEROUS; + delegate()->SetSecurityInfo(info); + EXPECT_FALSE(model()->GetDisplaySearchTerms(nullptr)); + + // But ignore the level if the connection info has not been initialized. + info.connection_info_initialized = false; + info.security_level = security_state::SecurityLevel::NONE; + delegate()->SetSecurityInfo(info); + EXPECT_TRUE(model()->GetDisplaySearchTerms(nullptr)); +} + +TEST_F(LocationBarModelImplTest, + QueryInOmniboxDefaultSearchProviderWithAndWithoutQuery) { + base::test::ScopedFeatureList scoped_feature_list; + scoped_feature_list.InitAndEnableFeature(omnibox::kQueryInOmnibox); + + security_state::SecurityInfo info; + info.connection_info_initialized = true; + info.security_level = security_state::SecurityLevel::SECURE; + delegate()->SetSecurityInfo(info); + + delegate()->SetURL(kValidSearchResultsPage); + base::string16 result; + EXPECT_TRUE(model()->GetDisplaySearchTerms(&result)); + EXPECT_EQ(base::ASCIIToUTF16("foo query"), result); + + const GURL kDefaultSearchProviderURLWithNoQuery( + "https://www.google.com/maps"); + result.clear(); + delegate()->SetURL(kDefaultSearchProviderURLWithNoQuery); + EXPECT_FALSE(model()->GetDisplaySearchTerms(&result)); + EXPECT_EQ(base::string16(), result); +} + +TEST_F(LocationBarModelImplTest, QueryInOmniboxNonDefaultSearchProvider) { + base::test::ScopedFeatureList scoped_feature_list; + scoped_feature_list.InitAndEnableFeature(omnibox::kQueryInOmnibox); + + const GURL kNonDefaultSearchProvider( + "https://search.yahoo.com/search?ei=UTF-8&fr=crmas&p=foo+query"); + delegate()->SetURL(kNonDefaultSearchProvider); + security_state::SecurityInfo info; + info.connection_info_initialized = true; + info.security_level = security_state::SecurityLevel::SECURE; + delegate()->SetSecurityInfo(info); + + base::string16 result; + EXPECT_FALSE(model()->GetDisplaySearchTerms(&result)); + EXPECT_EQ(base::string16(), result); +} + +TEST_F(LocationBarModelImplTest, QueryInOmniboxLookalikeURL) { + base::test::ScopedFeatureList scoped_feature_list; + scoped_feature_list.InitAndEnableFeature(omnibox::kQueryInOmnibox); + + security_state::SecurityInfo info; + info.connection_info_initialized = true; + info.security_level = security_state::SecurityLevel::SECURE; + delegate()->SetSecurityInfo(info); + + const GURL kLookalikeURLQuery( + "https://www.google.com/search?q=lookalike.com"); + delegate()->SetURL(kLookalikeURLQuery); + + base::string16 result; + EXPECT_FALSE(model()->GetDisplaySearchTerms(&result)); + EXPECT_EQ(base::string16(), result); } } // namespace
diff --git a/components/omnibox/browser/omnibox_client.cc b/components/omnibox/browser/omnibox_client.cc index 33521319..598d847 100644 --- a/components/omnibox/browser/omnibox_client.cc +++ b/components/omnibox/browser/omnibox_client.cc
@@ -73,10 +73,6 @@ return nullptr; } -QueryInOmnibox* OmniboxClient::GetQueryInOmnibox() { - return nullptr; -} - gfx::Image OmniboxClient::GetIconIfExtensionMatch( const AutocompleteMatch& match) const { return gfx::Image();
diff --git a/components/omnibox/browser/omnibox_client.h b/components/omnibox/browser/omnibox_client.h index d95ed12..d947144cf 100644 --- a/components/omnibox/browser/omnibox_client.h +++ b/components/omnibox/browser/omnibox_client.h
@@ -14,7 +14,6 @@ class AutocompleteResult; class GURL; -class QueryInOmnibox; class SessionID; class TemplateURL; class TemplateURLService; @@ -94,7 +93,6 @@ virtual TemplateURLService* GetTemplateURLService(); virtual const AutocompleteSchemeClassifier& GetSchemeClassifier() const = 0; virtual AutocompleteClassifier* GetAutocompleteClassifier(); - virtual QueryInOmnibox* GetQueryInOmnibox(); // Returns the icon corresponding to |match| if match is an extension match // and an empty icon otherwise.
diff --git a/components/omnibox/browser/omnibox_edit_model.cc b/components/omnibox/browser/omnibox_edit_model.cc index ff8835c..df8143a6 100644 --- a/components/omnibox/browser/omnibox_edit_model.cc +++ b/components/omnibox/browser/omnibox_edit_model.cc
@@ -37,7 +37,6 @@ #include "components/omnibox/browser/omnibox_popup_model.h" #include "components/omnibox/browser/omnibox_popup_view.h" #include "components/omnibox/browser/omnibox_view.h" -#include "components/omnibox/browser/query_in_omnibox.h" #include "components/omnibox/browser/search_provider.h" #include "components/search_engines/template_url.h" #include "components/search_engines/template_url_prepopulate_data.h" @@ -242,7 +241,7 @@ LocationBarModel* location_bar_model = controller()->GetLocationBarModel(); url_for_editing_ = location_bar_model->GetFormattedFullURL(); - if (GetQueryInOmniboxSearchTerms(&display_text_)) { + if (location_bar_model->GetDisplaySearchTerms(&display_text_)) { // The search query has been inserted into |display_text_|. DCHECK(!display_text_.empty()); } else { @@ -300,7 +299,9 @@ // Early exit if we don't want to exit Query in Omnibox mode, and the omnibox // is displaying a query. - if (!exit_query_in_omnibox && GetQueryInOmniboxSearchTerms(nullptr)) + LocationBarModel* location_bar_model = controller()->GetLocationBarModel(); + if (!exit_query_in_omnibox && + location_bar_model->GetDisplaySearchTerms(nullptr)) return; SetUserText(url_for_editing_); @@ -338,8 +339,11 @@ // checking is needed. By avoiding checking in this case, we avoid calling // into the autocomplete providers, and thus initializing the history system, // as long as possible, which speeds startup. - if (!user_input_in_progress_ && !GetQueryInOmniboxSearchTerms(nullptr)) + LocationBarModel* location_bar_model = controller()->GetLocationBarModel(); + if (!user_input_in_progress_ && + !location_bar_model->GetDisplaySearchTerms(nullptr)) { return true; + } return !AutocompleteMatch::IsSearchType(CurrentMatch(nullptr).type); } @@ -359,8 +363,9 @@ // // This early exit is meant for cases where we elide portions of the URL, so // it's inappropriate for the Query in Omnibox case. + LocationBarModel* location_bar_model = controller()->GetLocationBarModel(); if (!user_input_in_progress_ && *text == GetPermanentDisplayText() && - !GetQueryInOmniboxSearchTerms(nullptr)) { + !location_bar_model->GetDisplaySearchTerms(nullptr)) { // It's safe to copy the underlying URL. These lines ensure that if the // scheme was stripped it's added back, and the URL is unescaped (we escape // parts of it for display). @@ -1392,19 +1397,6 @@ OnPopupDataChanged(inline_autocompletion, nullptr, keyword, is_keyword_hint); } -bool OmniboxEditModel::GetQueryInOmniboxSearchTerms( - base::string16* search_terms) const { - QueryInOmnibox* query_in_omnibox = client()->GetQueryInOmnibox(); - if (!query_in_omnibox) - return false; - - LocationBarModel* location_bar_model = controller()->GetLocationBarModel(); - bool ignore_security_level = !location_bar_model->IsSecurityInfoInitialized(); - return query_in_omnibox->GetDisplaySearchTerms( - location_bar_model->GetSecurityLevel(false /* ignore_editing */), - ignore_security_level, location_bar_model->GetURL(), search_terms); -} - // static const char OmniboxEditModel::kCutOrCopyAllTextHistogram[] = "Omnibox.CutOrCopyAllText"; @@ -1460,8 +1452,10 @@ (!popup_model() || !popup_model()->has_selected_match())) *alternate_nav_url = result().alternate_nav_url(); } else { + LocationBarModel* location_bar_model = controller()->GetLocationBarModel(); base::string16 text_for_match_generation = - (user_input_in_progress() || GetQueryInOmniboxSearchTerms(nullptr)) + (user_input_in_progress() || + location_bar_model->GetDisplaySearchTerms(nullptr)) ? view_->GetText() : url_for_editing_;
diff --git a/components/omnibox/browser/omnibox_edit_model.h b/components/omnibox/browser/omnibox_edit_model.h index 0146c389..6d4e1220 100644 --- a/components/omnibox/browser/omnibox_edit_model.h +++ b/components/omnibox/browser/omnibox_edit_model.h
@@ -365,10 +365,6 @@ // Called when the current match has changed in the OmniboxController. void OnCurrentMatchChanged(); - // Convenience method for QueryInOmnibox::GetDisplaySearchTerms. - // Returns true if Query in Omnibox is active. |search_terms| may be nullptr. - bool GetQueryInOmniboxSearchTerms(base::string16* search_terms) const; - // Used for testing purposes only. base::string16 GetUserTextForTesting() const { return user_text_; }
diff --git a/components/omnibox/browser/omnibox_edit_model_unittest.cc b/components/omnibox/browser/omnibox_edit_model_unittest.cc index f48c1f3..be488abe 100644 --- a/components/omnibox/browser/omnibox_edit_model_unittest.cc +++ b/components/omnibox/browser/omnibox_edit_model_unittest.cc
@@ -165,10 +165,7 @@ TEST_F(OmniboxEditModelTest, AdjustTextForCopyQueryInOmnibox) { location_bar_model()->set_url(GURL("https://www.example.com/")); location_bar_model()->set_url_for_display(base::ASCIIToUTF16("example.com")); - - TestOmniboxClient* client = - static_cast<TestOmniboxClient*>(model()->client()); - client->SetFakeSearchTermsForQueryInOmnibox(base::ASCIIToUTF16("foobar")); + location_bar_model()->set_display_search_terms(base::ASCIIToUTF16("foobar")); model()->ResetDisplayTexts(); // Verify that we copy the query verbatim when nothing has been modified. @@ -273,9 +270,7 @@ // Tests that when there is a Query in Omnibox, generate matches from the // query, instead of the full formatted URL. - TestOmniboxClient* client = - static_cast<TestOmniboxClient*>(model()->client()); - client->SetFakeSearchTermsForQueryInOmnibox(base::ASCIIToUTF16("foobar")); + location_bar_model()->set_display_search_terms(base::ASCIIToUTF16("foobar")); model()->ResetDisplayTexts(); { @@ -301,10 +296,6 @@ model()->GetPermanentDisplayText()); #endif - base::string16 search_terms; - EXPECT_FALSE(model()->GetQueryInOmniboxSearchTerms(&search_terms)); - EXPECT_TRUE(search_terms.empty()); - EXPECT_TRUE(model()->CurrentTextIsURL()); // Verify we can unelide and show the full URL properly. @@ -323,20 +314,12 @@ TEST_F(OmniboxEditModelTest, DisplayAndExitQueryInOmnibox) { location_bar_model()->set_url(GURL("https://www.example.com/")); location_bar_model()->set_url_for_display(base::ASCIIToUTF16("example.com")); - - // Verify the displayed text when there is a Query in Omnibox match. - TestOmniboxClient* client = - static_cast<TestOmniboxClient*>(model()->client()); - client->SetFakeSearchTermsForQueryInOmnibox(base::ASCIIToUTF16("foobar")); + location_bar_model()->set_display_search_terms(base::ASCIIToUTF16("foobar")); EXPECT_TRUE(model()->ResetDisplayTexts()); + model()->Revert(); EXPECT_EQ(base::ASCIIToUTF16("foobar"), model()->GetPermanentDisplayText()); EXPECT_EQ(base::ASCIIToUTF16("foobar"), view()->GetText()); - - base::string16 search_terms; - EXPECT_TRUE(model()->GetQueryInOmniboxSearchTerms(&search_terms)); - EXPECT_FALSE(search_terms.empty()); - EXPECT_EQ(base::ASCIIToUTF16("foobar"), search_terms); EXPECT_FALSE(model()->CurrentTextIsURL()); EXPECT_TRUE(model()->ShouldShowCurrentPageIcon());
diff --git a/components/omnibox/browser/omnibox_view.cc b/components/omnibox/browser/omnibox_view.cc index c07df36..1839db1 100644 --- a/components/omnibox/browser/omnibox_view.cc +++ b/components/omnibox/browser/omnibox_view.cc
@@ -20,7 +20,6 @@ #include "components/omnibox/browser/omnibox_edit_controller.h" #include "components/omnibox/browser/omnibox_edit_model.h" #include "components/omnibox/browser/omnibox_field_trial.h" -#include "components/omnibox/browser/query_in_omnibox.h" #include "extensions/common/constants.h" #include "ui/base/l10n/l10n_util.h" @@ -128,15 +127,16 @@ if (model_->ShouldShowCurrentPageIcon()) { // Query in Omnibox. - if (model_->GetQueryInOmniboxSearchTerms(nullptr /* search_terms */)) { + LocationBarModel* location_bar_model = controller_->GetLocationBarModel(); + if (location_bar_model->GetDisplaySearchTerms(nullptr /* search_terms */)) { gfx::Image icon = model_->client()->GetFaviconForDefaultSearchProvider( std::move(on_icon_fetched)); if (!icon.IsEmpty()) return model_->client()->GetSizedIcon(icon).AsImageSkia(); } - return gfx::CreateVectorIcon( - controller_->GetLocationBarModel()->GetVectorIcon(), dip_size, color); + return gfx::CreateVectorIcon(location_bar_model->GetVectorIcon(), dip_size, + color); } gfx::Image favicon;
diff --git a/components/omnibox/browser/query_in_omnibox.cc b/components/omnibox/browser/query_in_omnibox.cc deleted file mode 100644 index bc2fc6f..0000000 --- a/components/omnibox/browser/query_in_omnibox.cc +++ /dev/null
@@ -1,85 +0,0 @@ -// Copyright 2018 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "components/omnibox/browser/query_in_omnibox.h" - -#include "base/feature_list.h" -#include "components/omnibox/browser/autocomplete_classifier.h" -#include "components/omnibox/browser/autocomplete_match.h" -#include "components/omnibox/browser/omnibox_field_trial.h" -#include "components/search_engines/template_url_service.h" - -namespace { - -bool SecurityLevelSafeForQueryInOmnibox( - security_state::SecurityLevel security_level) { - return security_level == security_state::SecurityLevel::SECURE || - security_level == security_state::SecurityLevel::EV_SECURE; -} - -} // namespace - -QueryInOmnibox::QueryInOmnibox(AutocompleteClassifier* autocomplete_classifier, - TemplateURLService* template_url_service) - : autocomplete_classifier_(autocomplete_classifier), - template_url_service_(template_url_service) { - DCHECK(autocomplete_classifier_); - DCHECK(template_url_service_); -} - -QueryInOmnibox::QueryInOmnibox() - : autocomplete_classifier_(nullptr), template_url_service_(nullptr) {} - -bool QueryInOmnibox::GetDisplaySearchTerms( - security_state::SecurityLevel security_level, - bool ignore_security_level, - const GURL& url, - base::string16* search_terms) { - if (!base::FeatureList::IsEnabled(omnibox::kQueryInOmnibox)) - return false; - - if (!ignore_security_level && - !SecurityLevelSafeForQueryInOmnibox(security_level)) { - return false; - } - - base::string16 extracted_search_terms = ExtractSearchTermsInternal(url); - if (extracted_search_terms.empty()) - return false; - - if (search_terms) - *search_terms = extracted_search_terms; - - return true; -} - -base::string16 QueryInOmnibox::ExtractSearchTermsInternal(const GURL& url) { - if (url.is_empty()) - return base::string16(); - - if (url != cached_url_) { - cached_url_ = url; - cached_search_terms_.clear(); - - const TemplateURL* default_provider = - template_url_service_->GetDefaultSearchProvider(); - if (default_provider) { - // If |url| doesn't match the default search provider, - // |cached_search_terms_| will remain empty. - default_provider->ExtractSearchTermsFromURL( - url, template_url_service_->search_terms_data(), - &cached_search_terms_); - - // Clear out the search terms if it looks like a URL. - AutocompleteMatch match; - autocomplete_classifier_->Classify( - cached_search_terms_, false, false, - metrics::OmniboxEventProto::INVALID_SPEC, &match, nullptr); - if (!AutocompleteMatch::IsSearchType(match.type)) - cached_search_terms_.clear(); - } - } - - return cached_search_terms_; -}
diff --git a/components/omnibox/browser/query_in_omnibox.h b/components/omnibox/browser/query_in_omnibox.h deleted file mode 100644 index 803f601..0000000 --- a/components/omnibox/browser/query_in_omnibox.h +++ /dev/null
@@ -1,69 +0,0 @@ -// Copyright 2018 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef COMPONENTS_OMNIBOX_BROWSER_QUERY_IN_OMNIBOX_H_ -#define COMPONENTS_OMNIBOX_BROWSER_QUERY_IN_OMNIBOX_H_ - -#include "base/macros.h" -#include "base/strings/string16.h" -#include "components/keyed_service/core/keyed_service.h" -#include "components/security_state/core/security_state.h" -#include "url/gurl.h" - -class AutocompleteClassifier; -class TemplateURLService; - -// This class holds the business logic for Query in Omnibox shared between both -// Android and Desktop. -class QueryInOmnibox : public KeyedService { - public: - QueryInOmnibox(AutocompleteClassifier* autocomplete_classifier, - TemplateURLService* template_url_service); - - // Returns true if the toolbar should display the search terms. When this - // method returns true, the extracted search terms will be filled into - // |search_terms| if its not nullptr. |ignore_security_level| can be set to - // true to avoid a flicker during page loading for a search results page - // before the SSL state updates. - // - // This method will return false if any of the following are true: - // - Query in Omnibox is disabled - // - |security_level| is insufficient to show search terms instead of the URL - // and |ignore_security_level| is false. - // - |url| is not from the default search provider - // - There are no search terms to extract from |url| - // - The extracted search terms look too much like a URL (could confuse user) - // - // This method can be called with nullptr |search_terms| if the caller wants - // to check the display status only. Virtual for testing purposes. - virtual bool GetDisplaySearchTerms( - security_state::SecurityLevel security_level, - bool ignore_security_level, - const GURL& url, - base::string16* search_terms); - - protected: - // For testing only. - QueryInOmnibox(); - - private: - // Extracts search terms from |url|. Returns an empty string if |url| is not - // from the default search provider, if there are no search terms in |url|, - // or if the extracted search terms look too much like a URL. - base::string16 ExtractSearchTermsInternal(const GURL& url); - - // Because extracting search terms from a URL string is relatively expensive, - // and we want to support cheap calls to GetDisplaySearchTerms, cache the - // result of the last-parsed URL string. - base::string16 cached_search_terms_; - GURL cached_url_; - - // Non-owning weak pointers. - AutocompleteClassifier* const autocomplete_classifier_; - TemplateURLService* const template_url_service_; - - DISALLOW_COPY_AND_ASSIGN(QueryInOmnibox); -}; - -#endif // COMPONENTS_OMNIBOX_BROWSER_QUERY_IN_OMNIBOX_H_
diff --git a/components/omnibox/browser/query_in_omnibox_unittest.cc b/components/omnibox/browser/query_in_omnibox_unittest.cc deleted file mode 100644 index 7f138ee..0000000 --- a/components/omnibox/browser/query_in_omnibox_unittest.cc +++ /dev/null
@@ -1,120 +0,0 @@ -// Copyright 2018 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "components/omnibox/browser/query_in_omnibox.h" - -#include "base/strings/utf_string_conversions.h" -#include "base/test/scoped_feature_list.h" -#include "base/test/scoped_task_environment.h" -#include "components/omnibox/browser/omnibox_field_trial.h" -#include "components/omnibox/browser/test_omnibox_client.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace { - -const GURL kValidSearchResultsPage = - GURL("https://www.google.com/search?q=foo+query"); - -} // namespace - -class QueryInOmniboxTest : public testing::Test { - protected: - QueryInOmniboxTest() - : omnibox_client_(new TestOmniboxClient), - model_(new QueryInOmnibox(omnibox_client_->GetAutocompleteClassifier(), - omnibox_client_->GetTemplateURLService())) {} - - QueryInOmnibox* model() { return model_.get(); } - - private: - base::test::ScopedTaskEnvironment task_environment_; - std::unique_ptr<TestOmniboxClient> omnibox_client_; - std::unique_ptr<QueryInOmnibox> model_; -}; - -TEST_F(QueryInOmniboxTest, FeatureFlagWorks) { - EXPECT_FALSE( - model()->GetDisplaySearchTerms(security_state::SecurityLevel::SECURE, - false, kValidSearchResultsPage, nullptr)); - - base::test::ScopedFeatureList scoped_feature_list; - scoped_feature_list.InitAndEnableFeature(omnibox::kQueryInOmnibox); - - EXPECT_TRUE( - model()->GetDisplaySearchTerms(security_state::SecurityLevel::SECURE, - false, kValidSearchResultsPage, nullptr)); -} - -TEST_F(QueryInOmniboxTest, SecurityLevel) { - base::test::ScopedFeatureList scoped_feature_list; - scoped_feature_list.InitAndEnableFeature(omnibox::kQueryInOmnibox); - - EXPECT_TRUE( - model()->GetDisplaySearchTerms(security_state::SecurityLevel::SECURE, - false, kValidSearchResultsPage, nullptr)); - EXPECT_TRUE( - model()->GetDisplaySearchTerms(security_state::SecurityLevel::EV_SECURE, - false, kValidSearchResultsPage, nullptr)); - - // Insecure levels should not be allowed to display search terms. - EXPECT_FALSE( - model()->GetDisplaySearchTerms(security_state::SecurityLevel::NONE, false, - kValidSearchResultsPage, nullptr)); - EXPECT_FALSE( - model()->GetDisplaySearchTerms(security_state::SecurityLevel::DANGEROUS, - false, kValidSearchResultsPage, nullptr)); - - // But respect the flag on to ignore the security level. - EXPECT_TRUE( - model()->GetDisplaySearchTerms(security_state::SecurityLevel::NONE, true, - kValidSearchResultsPage, nullptr)); - EXPECT_TRUE( - model()->GetDisplaySearchTerms(security_state::SecurityLevel::DANGEROUS, - true, kValidSearchResultsPage, nullptr)); -} - -TEST_F(QueryInOmniboxTest, DefaultSearchProviderWithAndWithoutQuery) { - base::test::ScopedFeatureList scoped_feature_list; - scoped_feature_list.InitAndEnableFeature(omnibox::kQueryInOmnibox); - - base::string16 result; - EXPECT_TRUE( - model()->GetDisplaySearchTerms(security_state::SecurityLevel::SECURE, - false, kValidSearchResultsPage, &result)); - EXPECT_EQ(base::ASCIIToUTF16("foo query"), result); - - const GURL kDefaultSearchProviderURLWithNoQuery( - "https://www.google.com/maps"); - result.clear(); - EXPECT_FALSE(model()->GetDisplaySearchTerms( - security_state::SecurityLevel::SECURE, false, - kDefaultSearchProviderURLWithNoQuery, &result)); - EXPECT_EQ(base::string16(), result); -} - -TEST_F(QueryInOmniboxTest, NonDefaultSearchProvider) { - base::test::ScopedFeatureList scoped_feature_list; - scoped_feature_list.InitAndEnableFeature(omnibox::kQueryInOmnibox); - - const GURL kNonDefaultSearchProvider( - "https://search.yahoo.com/search?ei=UTF-8&fr=crmas&p=foo+query"); - base::string16 result; - EXPECT_FALSE(model()->GetDisplaySearchTerms( - security_state::SecurityLevel::SECURE, false, kNonDefaultSearchProvider, - &result)); - EXPECT_EQ(base::string16(), result); -} - -TEST_F(QueryInOmniboxTest, LookalikeURL) { - base::test::ScopedFeatureList scoped_feature_list; - scoped_feature_list.InitAndEnableFeature(omnibox::kQueryInOmnibox); - - const GURL kLookalikeURLQuery( - "https://www.google.com/search?q=lookalike.com"); - base::string16 result; - EXPECT_FALSE( - model()->GetDisplaySearchTerms(security_state::SecurityLevel::SECURE, - false, kLookalikeURLQuery, &result)); - EXPECT_EQ(base::string16(), result); -}
diff --git a/components/omnibox/browser/test_location_bar_model.cc b/components/omnibox/browser/test_location_bar_model.cc index 6c0b1e89..79094aa 100644 --- a/components/omnibox/browser/test_location_bar_model.cc +++ b/components/omnibox/browser/test_location_bar_model.cc
@@ -43,7 +43,13 @@ return security_level_; } -bool TestLocationBarModel::IsSecurityInfoInitialized() const { +bool TestLocationBarModel::GetDisplaySearchTerms(base::string16* search_terms) { + if (display_search_terms_.empty()) + return false; + + if (search_terms) + *search_terms = display_search_terms_; + return true; }
diff --git a/components/omnibox/browser/test_location_bar_model.h b/components/omnibox/browser/test_location_bar_model.h index 11fabe9..7f6317a 100644 --- a/components/omnibox/browser/test_location_bar_model.h +++ b/components/omnibox/browser/test_location_bar_model.h
@@ -29,7 +29,7 @@ GURL GetURL() const override; security_state::SecurityLevel GetSecurityLevel( bool ignore_editing) const override; - bool IsSecurityInfoInitialized() const override; + bool GetDisplaySearchTerms(base::string16* search_terms) override; const gfx::VectorIcon& GetVectorIcon() const override; base::string16 GetSecureDisplayText() const override; base::string16 GetSecureAccessibilityText() const override; @@ -47,6 +47,9 @@ void set_security_level(security_state::SecurityLevel security_level) { security_level_ = security_level; } + void set_display_search_terms(const base::string16& terms) { + display_search_terms_ = terms; + } void set_icon(const gfx::VectorIcon& icon) { icon_ = &icon; } void set_ev_cert_name(const base::string16& ev_cert_name) { ev_cert_name_ = ev_cert_name; @@ -67,6 +70,7 @@ GURL url_; security_state::SecurityLevel security_level_ = security_state::NONE; + base::string16 display_search_terms_; const gfx::VectorIcon* icon_ = nullptr; base::string16 ev_cert_name_; bool should_display_url_ = false;
diff --git a/components/omnibox/browser/test_omnibox_client.cc b/components/omnibox/browser/test_omnibox_client.cc index d8842f7..a19ba11 100644 --- a/components/omnibox/browser/test_omnibox_client.cc +++ b/components/omnibox/browser/test_omnibox_client.cc
@@ -11,7 +11,6 @@ #include "components/omnibox/browser/autocomplete_controller.h" #include "components/omnibox/browser/autocomplete_scheme_classifier.h" #include "components/omnibox/browser/mock_autocomplete_provider_client.h" -#include "components/omnibox/browser/query_in_omnibox.h" #include "components/search_engines/search_terms_data.h" #include "components/search_engines/template_url_service.h" #include "components/search_engines/template_url_service_client.h" @@ -21,30 +20,6 @@ #include "ui/gfx/image/image.h" #include "ui/gfx/image/image_skia.h" -class FakeQueryInOmnibox : public QueryInOmnibox { - public: - void set_fake_search_terms(const base::string16& terms) { - fake_search_terms_ = terms; - } - - // QueryInOmnibox: - bool GetDisplaySearchTerms(security_state::SecurityLevel security_level, - bool ignore_security_level, - const GURL& url, - base::string16* search_terms) override { - if (fake_search_terms_.empty()) - return false; - - if (search_terms) - *search_terms = fake_search_terms_; - - return true; - } - - private: - base::string16 fake_search_terms_; -}; - TestOmniboxClient::TestOmniboxClient() : session_id_(SessionID::FromSerializedValue(1)), bookmark_model_(nullptr), @@ -53,18 +28,12 @@ CreateAutocompleteProviderClient(), nullptr, AutocompleteClassifier::DefaultOmniboxProviders()), - std::make_unique<TestSchemeClassifier>()), - fake_query_in_omnibox_(new FakeQueryInOmnibox) {} + std::make_unique<TestSchemeClassifier>()) {} TestOmniboxClient::~TestOmniboxClient() { autocomplete_classifier_.Shutdown(); } -void TestOmniboxClient::SetFakeSearchTermsForQueryInOmnibox( - const base::string16& terms) { - fake_query_in_omnibox_->set_fake_search_terms(terms); -} - std::unique_ptr<AutocompleteProviderClient> TestOmniboxClient::CreateAutocompleteProviderClient() { std::unique_ptr<MockAutocompleteProviderClient> provider_client( @@ -128,10 +97,6 @@ return &autocomplete_classifier_; } -QueryInOmnibox* TestOmniboxClient::GetQueryInOmnibox() { - return fake_query_in_omnibox_.get(); -} - gfx::Image TestOmniboxClient::GetSizedIcon( const gfx::VectorIcon& vector_icon_type, SkColor vector_icon_color) const {
diff --git a/components/omnibox/browser/test_omnibox_client.h b/components/omnibox/browser/test_omnibox_client.h index e811e15d..3426821 100644 --- a/components/omnibox/browser/test_omnibox_client.h +++ b/components/omnibox/browser/test_omnibox_client.h
@@ -17,7 +17,6 @@ #include "components/sessions/core/session_id.h" class AutocompleteSchemeClassifier; -class FakeQueryInOmnibox; // Fake implementation of OmniboxClient for use in tests. class TestOmniboxClient : public OmniboxClient { @@ -29,10 +28,6 @@ return alternate_nav_match_; } - // Sets fake search terms for Query in Omnibox feature to return. If |terms| - // is empty, the URL will be treated as a non search results page. - void SetFakeSearchTermsForQueryInOmnibox(const base::string16& terms); - // OmniboxClient: std::unique_ptr<AutocompleteProviderClient> CreateAutocompleteProviderClient() override; @@ -47,7 +42,6 @@ TemplateURLService* GetTemplateURLService() override; const AutocompleteSchemeClassifier& GetSchemeClassifier() const override; AutocompleteClassifier* GetAutocompleteClassifier() override; - QueryInOmnibox* GetQueryInOmnibox() override; gfx::Image GetSizedIcon(const gfx::VectorIcon& vector_icon_type, SkColor vector_icon_color) const override; gfx::Image GetFaviconForPageUrl( @@ -63,7 +57,6 @@ TemplateURLService* template_url_service_; TestSchemeClassifier scheme_classifier_; AutocompleteClassifier autocomplete_classifier_; - std::unique_ptr<FakeQueryInOmnibox> fake_query_in_omnibox_; GURL page_url_for_last_favicon_request_; DISALLOW_COPY_AND_ASSIGN(TestOmniboxClient);
diff --git a/components/safe_browsing/features.cc b/components/safe_browsing/features.cc index a73404f..771820e 100644 --- a/components/safe_browsing/features.cc +++ b/components/safe_browsing/features.cc
@@ -52,6 +52,9 @@ const base::Feature kUseLocalBlacklistsV2{"SafeBrowsingUseLocalBlacklistsV2", base::FEATURE_DISABLED_BY_DEFAULT}; +const base::Feature kInspectRarContentFeature{ + "InspectRarContent", base::FEATURE_DISABLED_BY_DEFAULT}; + namespace { // List of experimental features. Boolean value for each list member should be // set to true if the experiment is currently running at a probability other
diff --git a/components/safe_browsing/features.h b/components/safe_browsing/features.h index 07a81d1..06721b0 100644 --- a/components/safe_browsing/features.h +++ b/components/safe_browsing/features.h
@@ -54,6 +54,10 @@ // Controls whether Chrome on Android uses locally cached blacklists. extern const base::Feature kUseLocalBlacklistsV2; +// Controls whether we inspect the content of RAR files, or just report the +// filenames contained in the archive. +extern const base::Feature kInspectRarContentFeature; + base::ListValue GetFeatureStatusList(); } // namespace safe_browsing
diff --git a/components/task_scheduler_util/variations_util.cc b/components/task_scheduler_util/variations_util.cc index a184f52..cff79ac 100644 --- a/components/task_scheduler_util/variations_util.cc +++ b/components/task_scheduler_util/variations_util.cc
@@ -21,7 +21,7 @@ namespace { // Builds a SchedulerWorkerPoolParams from the pool descriptor in -// |variation_params[variation_param_prefix + pool_name]|. Returns an invalid +// |variation_params[pool_name]|. Returns an invalid // SchedulerWorkerPoolParams on failure. // // The pool descriptor is a semi-colon separated value string with the following @@ -33,11 +33,9 @@ // 4. Detach Time in Milliseconds (int) // Additional values may appear as necessary and will be ignored. std::unique_ptr<base::SchedulerWorkerPoolParams> GetWorkerPoolParams( - base::StringPiece variation_param_prefix, base::StringPiece pool_name, const std::map<std::string, std::string>& variation_params) { - auto pool_descriptor_it = - variation_params.find(base::StrCat({variation_param_prefix, pool_name})); + auto pool_descriptor_it = variation_params.find(pool_name.as_string()); if (pool_descriptor_it == variation_params.end()) return nullptr; const auto& pool_descriptor = pool_descriptor_it->second; @@ -86,20 +84,26 @@ } // namespace +const base::Feature kBrowserSchedulerInitParams = { + "BrowserSchedulerInitParams", base::FEATURE_DISABLED_BY_DEFAULT}; + +const base::Feature kRendererSchedulerInitParams = { + "RendererSchedulerInitParams", base::FEATURE_DISABLED_BY_DEFAULT}; + std::unique_ptr<base::TaskScheduler::InitParams> GetTaskSchedulerInitParams( - base::StringPiece variation_param_prefix) { + const base::Feature& feature) { std::map<std::string, std::string> variation_params; - if (!base::GetFieldTrialParams("BrowserScheduler", &variation_params)) + if (!base::GetFieldTrialParamsByFeature(feature, &variation_params)) return nullptr; - const auto background_worker_pool_params = GetWorkerPoolParams( - variation_param_prefix, "Background", variation_params); - const auto background_blocking_worker_pool_params = GetWorkerPoolParams( - variation_param_prefix, "BackgroundBlocking", variation_params); - const auto foreground_worker_pool_params = GetWorkerPoolParams( - variation_param_prefix, "Foreground", variation_params); - const auto foreground_blocking_worker_pool_params = GetWorkerPoolParams( - variation_param_prefix, "ForegroundBlocking", variation_params); + const auto background_worker_pool_params = + GetWorkerPoolParams("Background", variation_params); + const auto background_blocking_worker_pool_params = + GetWorkerPoolParams("BackgroundBlocking", variation_params); + const auto foreground_worker_pool_params = + GetWorkerPoolParams("Foreground", variation_params); + const auto foreground_blocking_worker_pool_params = + GetWorkerPoolParams("ForegroundBlocking", variation_params); if (!background_worker_pool_params || !background_blocking_worker_pool_params || @@ -115,16 +119,16 @@ std::unique_ptr<base::TaskScheduler::InitParams> GetTaskSchedulerInitParamsForBrowser() { - // Variations params for the browser processes have no prefix. - constexpr char kVariationParamPrefix[] = ""; - return GetTaskSchedulerInitParams(kVariationParamPrefix); + // Variations params for the browser processes are associated with the feature + // |kBrowserSchedulerInitParams|. + return GetTaskSchedulerInitParams(kBrowserSchedulerInitParams); } std::unique_ptr<base::TaskScheduler::InitParams> GetTaskSchedulerInitParamsForRenderer() { - // Variations params for renderer processes are prefixed with "Renderer". - constexpr char kVariationParamPrefix[] = "Renderer"; - return GetTaskSchedulerInitParams(kVariationParamPrefix); + // Variations params for the renderer processes are associated with the + // feature |kRendererSchedulerInitParams|. + return GetTaskSchedulerInitParams(kRendererSchedulerInitParams); } } // namespace task_scheduler_util
diff --git a/components/task_scheduler_util/variations_util.h b/components/task_scheduler_util/variations_util.h index c09c4320..eb8328a 100644 --- a/components/task_scheduler_util/variations_util.h +++ b/components/task_scheduler_util/variations_util.h
@@ -7,19 +7,22 @@ #include <memory> +#include "base/feature_list.h" #include "base/strings/string_piece.h" #include "base/task/task_scheduler/task_scheduler.h" namespace task_scheduler_util { +extern const base::Feature kBrowserSchedulerInitParams; +extern const base::Feature kRendererSchedulerInitParams; + // Builds a TaskScheduler::InitParams from variations params that are prefixed -// with |variation_param_prefix| in the BrowserScheduler field trial. Returns -// nullptr on failure. +// for |feature|. Returns nullptr on failure. // // TODO(fdoray): Move this to the anonymous namespace in the .cc file. // https://crbug.com/810049 std::unique_ptr<base::TaskScheduler::InitParams> GetTaskSchedulerInitParams( - base::StringPiece variation_param_prefix); + const base::Feature& feature); // Builds a TaskScheduler::InitParams to use in the browser process from // variation params in the BrowserScheduler field trial.
diff --git a/components/task_scheduler_util/variations_util_unittest.cc b/components/task_scheduler_util/variations_util_unittest.cc index a3a3627b..7193ca8 100644 --- a/components/task_scheduler_util/variations_util_unittest.cc +++ b/components/task_scheduler_util/variations_util_unittest.cc
@@ -24,8 +24,10 @@ void SetVariationParams( const std::map<std::string, std::string>& variation_params) { - variation_params_manager_.SetVariationParams("BrowserScheduler", - variation_params); + std::set<std::string> features; + features.insert(kRendererSchedulerInitParams.name); + variation_params_manager_.SetVariationParamsWithFeatureAssociations( + "DummyTrial", variation_params, features); } private: @@ -38,13 +40,13 @@ TEST_F(TaskSchedulerUtilVariationsUtilTest, OrderingParams5) { std::map<std::string, std::string> variation_params; - variation_params["RendererBackground"] = "1;1;1;0;42"; - variation_params["RendererBackgroundBlocking"] = "2;2;1;0;52"; - variation_params["RendererForeground"] = "4;4;1;0;62"; - variation_params["RendererForegroundBlocking"] = "8;8;1;0;72"; + variation_params["Background"] = "1;1;1;0;42"; + variation_params["BackgroundBlocking"] = "2;2;1;0;52"; + variation_params["Foreground"] = "4;4;1;0;62"; + variation_params["ForegroundBlocking"] = "8;8;1;0;72"; SetVariationParams(variation_params); - auto init_params = GetTaskSchedulerInitParams("Renderer"); + auto init_params = GetTaskSchedulerInitParams(kRendererSchedulerInitParams); ASSERT_TRUE(init_params); EXPECT_EQ(1, init_params->background_worker_pool_params.max_tasks()); @@ -81,63 +83,63 @@ } TEST_F(TaskSchedulerUtilVariationsUtilTest, NoData) { - EXPECT_FALSE(GetTaskSchedulerInitParams("Renderer")); + EXPECT_FALSE(GetTaskSchedulerInitParams(kRendererSchedulerInitParams)); } TEST_F(TaskSchedulerUtilVariationsUtilTest, IncompleteParameters) { std::map<std::string, std::string> variation_params; - variation_params["RendererBackground"] = "1;1;1;0"; - variation_params["RendererBackgroundBlocking"] = "2;2;1;0"; - variation_params["RendererForeground"] = "4;4;1;0"; - variation_params["RendererForegroundBlocking"] = "8;8;1;0"; + variation_params["Background"] = "1;1;1;0"; + variation_params["BackgroundBlocking"] = "2;2;1;0"; + variation_params["Foreground"] = "4;4;1;0"; + variation_params["ForegroundBlocking"] = "8;8;1;0"; SetVariationParams(variation_params); - EXPECT_FALSE(GetTaskSchedulerInitParams("Renderer")); + EXPECT_FALSE(GetTaskSchedulerInitParams(kRendererSchedulerInitParams)); } TEST_F(TaskSchedulerUtilVariationsUtilTest, InvalidParametersFormat) { std::map<std::string, std::string> variation_params; - variation_params["RendererBackground"] = "a;b;c;d;e"; - variation_params["RendererBackgroundBlocking"] = "a;b;c;d;e"; - variation_params["RendererForeground"] = "a;b;c;d;e"; - variation_params["RendererForegroundBlocking"] = "a;b;c;d;e"; + variation_params["Background"] = "a;b;c;d;e"; + variation_params["BackgroundBlocking"] = "a;b;c;d;e"; + variation_params["Foreground"] = "a;b;c;d;e"; + variation_params["ForegroundBlocking"] = "a;b;c;d;e"; SetVariationParams(variation_params); - EXPECT_FALSE(GetTaskSchedulerInitParams("Renderer")); + EXPECT_FALSE(GetTaskSchedulerInitParams(kRendererSchedulerInitParams)); } TEST_F(TaskSchedulerUtilVariationsUtilTest, ZeroMaxThreads) { // The Background pool has a maximum number of threads equal to zero, which is // invalid. std::map<std::string, std::string> variation_params; - variation_params["RendererBackground"] = "0;0;0;0;0"; - variation_params["RendererBackgroundBlocking"] = "2;2;1;0;52"; - variation_params["RendererForeground"] = "4;4;1;0;62"; - variation_params["RendererForegroundBlocking"] = "8;8;1;0;72"; + variation_params["Background"] = "0;0;0;0;0"; + variation_params["BackgroundBlocking"] = "2;2;1;0;52"; + variation_params["Foreground"] = "4;4;1;0;62"; + variation_params["ForegroundBlocking"] = "8;8;1;0;72"; SetVariationParams(variation_params); - EXPECT_FALSE(GetTaskSchedulerInitParams("Renderer")); + EXPECT_FALSE(GetTaskSchedulerInitParams(kRendererSchedulerInitParams)); } TEST_F(TaskSchedulerUtilVariationsUtilTest, NegativeMaxThreads) { // The Background pool has a negative maximum number of threads, which is // invalid. std::map<std::string, std::string> variation_params; - variation_params["RendererBackground"] = "-5;-5;0;0;0"; - variation_params["RendererBackgroundBlocking"] = "2;2;1;0;52"; - variation_params["RendererForeground"] = "4;4;1;0;62"; - variation_params["RendererForegroundBlocking"] = "8;8;1;0;72"; + variation_params["Background"] = "-5;-5;0;0;0"; + variation_params["BackgroundBlocking"] = "2;2;1;0;52"; + variation_params["Foreground"] = "4;4;1;0;62"; + variation_params["ForegroundBlocking"] = "8;8;1;0;72"; SetVariationParams(variation_params); - EXPECT_FALSE(GetTaskSchedulerInitParams("Renderer")); + EXPECT_FALSE(GetTaskSchedulerInitParams(kRendererSchedulerInitParams)); } TEST_F(TaskSchedulerUtilVariationsUtilTest, NegativeSuggestedReclaimTime) { // The Background pool has a negative suggested reclaim time, which is // invalid. std::map<std::string, std::string> variation_params; - variation_params["RendererBackground"] = "1;1;1;0;-5"; - variation_params["RendererBackgroundBlocking"] = "2;2;1;0;52"; - variation_params["RendererForeground"] = "4;4;1;0;62"; - variation_params["RendererForegroundBlocking"] = "8;8;1;0;72"; + variation_params["Background"] = "1;1;1;0;-5"; + variation_params["BackgroundBlocking"] = "2;2;1;0;52"; + variation_params["Foreground"] = "4;4;1;0;62"; + variation_params["ForegroundBlocking"] = "8;8;1;0;72"; SetVariationParams(variation_params); - EXPECT_FALSE(GetTaskSchedulerInitParams("Renderer")); + EXPECT_FALSE(GetTaskSchedulerInitParams(kRendererSchedulerInitParams)); } } // namespace task_scheduler_util
diff --git a/content/browser/dom_storage/local_storage_context_mojo.cc b/content/browser/dom_storage/local_storage_context_mojo.cc index 830d0a7..0053914 100644 --- a/content/browser/dom_storage/local_storage_context_mojo.cc +++ b/content/browser/dom_storage/local_storage_context_mojo.cc
@@ -833,6 +833,7 @@ if (database_) tried_to_recreate_during_open_ = false; + LogDatabaseOpenResult(OpenResult::SUCCESS); open_result_histogram_ = nullptr; // |database_| should be known to either be valid or invalid by now. Run our
diff --git a/content/browser/dom_storage/session_storage_context_mojo.cc b/content/browser/dom_storage/session_storage_context_mojo.cc index dc2efbe..4d8777c 100644 --- a/content/browser/dom_storage/session_storage_context_mojo.cc +++ b/content/browser/dom_storage/session_storage_context_mojo.cc
@@ -880,6 +880,7 @@ if (database_) tried_to_recreate_during_open_ = false; + LogDatabaseOpenResult(OpenResult::kSuccess); open_result_histogram_ = nullptr; // |database_| should be known to either be valid or invalid by now. Run our
diff --git a/content/browser/network_service_instance.cc b/content/browser/network_service_instance.cc index 052092f..bf70366 100644 --- a/content/browser/network_service_instance.cc +++ b/content/browser/network_service_instance.cc
@@ -9,6 +9,7 @@ #include <string> #include <utility> +#include "base/deferred_sequenced_task_runner.h" #include "base/environment.h" #include "base/feature_list.h" #include "base/no_destructor.h" @@ -21,6 +22,7 @@ #include "content/public/browser/browser_task_traits.h" #include "content/public/browser/browser_thread.h" #include "content/public/browser/content_browser_client.h" +#include "content/public/common/network_service_util.h" #include "content/public/common/service_manager_connection.h" #include "content/public/common/service_names.mojom.h" #include "net/log/net_log_util.h" @@ -244,4 +246,11 @@ } } +scoped_refptr<base::DeferredSequencedTaskRunner> GetNetworkTaskRunner() { + DCHECK(IsInProcessNetworkService()); + static base::NoDestructor<scoped_refptr<base::DeferredSequencedTaskRunner>> + instance(new base::DeferredSequencedTaskRunner()); + return instance->get(); +} + } // namespace content
diff --git a/content/browser/renderer_host/render_process_host_impl.cc b/content/browser/renderer_host/render_process_host_impl.cc index 9839916..ee890ea 100644 --- a/content/browser/renderer_host/render_process_host_impl.cc +++ b/content/browser/renderer_host/render_process_host_impl.cc
@@ -3624,8 +3624,7 @@ void RenderProcessHostImpl::EnableWebRtcEventLogOutput(int lid, int output_period_ms) { - Send(new PeerConnectionTracker_StartEventLogOutput( - lid, base::saturated_cast<unsigned int>(output_period_ms))); + Send(new PeerConnectionTracker_StartEventLog(lid, output_period_ms)); } void RenderProcessHostImpl::DisableWebRtcEventLogOutput(int lid) {
diff --git a/content/browser/service_manager/service_manager_context.cc b/content/browser/service_manager/service_manager_context.cc index b3ea530..f8e1d62 100644 --- a/content/browser/service_manager/service_manager_context.cc +++ b/content/browser/service_manager/service_manager_context.cc
@@ -122,6 +122,11 @@ base::LazyInstance<std::map<std::string, base::WeakPtr<UtilityProcessHost>>>:: Leaky g_active_process_groups; +// If enabled, network service will run in it's own thread when running +// in-process, otherwise it is run on the IO thread. +const base::Feature kNetworkServiceDedicatedThread{ + "NetworkServiceDedicatedThread", base::FEATURE_ENABLED_BY_DEFAULT}; + void DestroyConnectorOnIOThread() { g_io_thread_connector.Get().reset(); } // Launch a process for a service once its sandbox type is known. @@ -705,9 +710,17 @@ base::FeatureList::IsEnabled(network::features::kNetworkService); if (network_service_enabled) { if (IsInProcessNetworkService()) { + scoped_refptr<base::SequencedTaskRunner> task_runner = + service_manager_thread_task_runner_; + if (base::FeatureList::IsEnabled(kNetworkServiceDedicatedThread)) { + base::Thread::Options options(base::MessageLoop::TYPE_IO, 0); + network_service_thread_.StartWithOptions(options); + task_runner = network_service_thread_.task_runner(); + } + + GetNetworkTaskRunner()->StartWithTaskRunner(task_runner); RegisterInProcessService(packaged_services_connection_.get(), - mojom::kNetworkServiceName, - service_manager_thread_task_runner_, + mojom::kNetworkServiceName, task_runner, base::BindRepeating(&CreateNetworkService)); } else { out_of_process_services[mojom::kNetworkServiceName] =
diff --git a/content/browser/service_manager/service_manager_context.h b/content/browser/service_manager/service_manager_context.h index c2c540da..f520f8f 100644 --- a/content/browser/service_manager/service_manager_context.h +++ b/content/browser/service_manager/service_manager_context.h
@@ -12,6 +12,7 @@ #include "base/memory/ref_counted.h" #include "base/memory/weak_ptr.h" #include "base/single_thread_task_runner.h" +#include "base/threading/thread.h" #include "content/common/content_export.h" #include "services/service_manager/public/mojom/service.mojom.h" @@ -65,6 +66,7 @@ service_manager_thread_task_runner_; scoped_refptr<InProcessServiceManagerContext> in_process_context_; std::unique_ptr<ServiceManagerConnection> packaged_services_connection_; + base::Thread network_service_thread_{"NetworkService"}; base::WeakPtrFactory<ServiceManagerContext> weak_ptr_factory_{this}; DISALLOW_COPY_AND_ASSIGN(ServiceManagerContext);
diff --git a/content/browser/web_contents/web_contents_impl_browsertest.cc b/content/browser/web_contents/web_contents_impl_browsertest.cc index be45ea8..2000249 100644 --- a/content/browser/web_contents/web_contents_impl_browsertest.cc +++ b/content/browser/web_contents/web_contents_impl_browsertest.cc
@@ -14,6 +14,7 @@ #include "base/run_loop.h" #include "base/strings/pattern.h" #include "base/strings/utf_string_conversions.h" +#include "base/test/scoped_feature_list.h" #include "base/threading/thread_restrictions.h" #include "base/time/time.h" #include "base/values.h" @@ -54,6 +55,7 @@ #include "content/shell/browser/shell.h" #include "content/test/content_browser_test_utils_internal.h" #include "content/test/test_content_browser_client.h" +#include "net/base/features.h" #include "net/dns/mock_host_resolver.h" #include "net/test/embedded_test_server/controllable_http_response.h" #include "net/test/embedded_test_server/embedded_test_server.h" @@ -734,12 +736,35 @@ EXPECT_TRUE(resource_load_info_found); } + // Returns the resource with the given url if found, otherwise nullptr. + mojom::ResourceLoadInfoPtr* FindResource(const GURL& url) { + for (auto& resource : resource_load_infos_) { + if (resource->url == url) + return &resource; + } + return nullptr; + } + void Reset() { resource_load_infos_.clear(); memory_cached_loaded_urls_.clear(); resource_is_associated_with_main_frame_.clear(); } + void WaitForResourceCompletion(const GURL& url) { + // If we've already seen the resource, return immediately. + for (const auto& load_info : resource_load_infos_) { + if (load_info->url == url) + return; + } + + // Otherwise wait for it. + base::RunLoop loop; + waiting_url_ = url; + waiting_callback_ = loop.QuitClosure(); + loop.Run(); + } + private: // WebContentsObserver implementation: void ResourceLoadComplete( @@ -750,6 +775,12 @@ resource_load_infos_.push_back(resource_load_info.Clone()); resource_is_associated_with_main_frame_.push_back( render_frame_host->GetParent() == nullptr); + + // Have we been waiting for this resource? If so, run the callback. + if (waiting_url_.is_valid() && resource_load_info.url == waiting_url_) { + waiting_url_ = GURL(); + std::move(waiting_callback_).Run(); + } } void DidLoadResourceFromMemoryCache(const GURL& url, @@ -761,6 +792,8 @@ std::vector<GURL> memory_cached_loaded_urls_; std::vector<mojom::ResourceLoadInfoPtr> resource_load_infos_; std::vector<bool> resource_is_associated_with_main_frame_; + GURL waiting_url_; + base::OnceClosure waiting_callback_; DISALLOW_COPY_AND_ASSIGN(ResourceLoadObserver); }; @@ -854,6 +887,198 @@ observer.resource_load_infos()[1]->network_info->network_accessed); } +class WebContentsSplitCacheBrowserTest : public WebContentsImplBrowserTest { + public: + enum class Context { kMainFrame, kSameOriginFrame, kCrossOriginFrame }; + WebContentsSplitCacheBrowserTest() {} + + // WebContentsImplBrowserTest: + void SetUpOnMainThread() override { + WebContentsImplBrowserTest::SetUpOnMainThread(); + + embedded_test_server()->RegisterRequestHandler(base::BindRepeating( + &WebContentsSplitCacheBrowserTest::CachedScriptHandler, + base::Unretained(this))); + ASSERT_TRUE(embedded_test_server()->Start()); + } + + std::unique_ptr<net::test_server::HttpResponse> CachedScriptHandler( + const net::test_server::HttpRequest& request) { + GURL absolute_url = embedded_test_server()->GetURL(request.relative_url); + + // Return a page that redirects to d.com/title1.html. + if (absolute_url.path() == "/redirect_to_d") { + auto http_response = + std::make_unique<net::test_server::BasicHttpResponse>(); + http_response->set_code(net::HTTP_SEE_OTHER); + http_response->AddCustomHeader( + "Location", + embedded_test_server()->GetURL("d.com", "/title1.html").spec()); + return http_response; + } + + // Return valid cacheable script. + if (absolute_url.path() == "/script") { + auto http_response = + std::make_unique<net::test_server::BasicHttpResponse>(); + http_response->set_code(net::HTTP_OK); + http_response->set_content("console.log(\"Hello World\");"); + http_response->set_content_type("application/javascript"); + http_response->AddCustomHeader("Cache-Control", "max-age=1000"); + return http_response; + } + + return std::unique_ptr<net::test_server::HttpResponse>(); + } + + protected: + // Loads 3p.com/script on page |url|, optionally from |sub_frame| if it's + // valid and return if the script was cached or not. + bool TestResourceLoad(const GURL& url, const GURL& sub_frame) { + // Kill the renderer to clear the in-memory cache. + NavigateToURL(shell(), GURL("chrome:crash")); + + // Observe network requests. + ResourceLoadObserver observer(shell()); + + NavigateToURL(shell(), url); + + RenderFrameHost* host_to_load_resource = + shell()->web_contents()->GetMainFrame(); + + // If there is supposed to be a sub-frame, create it. + if (sub_frame.is_valid()) { + const char kLoadIframeScript[] = + "var iframe = document.createElement('iframe');" + "iframe.src='%s';" + "document.body.appendChild(iframe);"; + std::string create_iframe_script = + base::StringPrintf(kLoadIframeScript, sub_frame.spec().c_str()); + EXPECT_TRUE(ExecuteScript(shell(), create_iframe_script)); + EXPECT_TRUE(WaitForLoadStop(shell()->web_contents())); + + host_to_load_resource = + static_cast<WebContentsImpl*>(shell()->web_contents()) + ->GetFrameTree() + ->root() + ->child_at(0) + ->current_frame_host(); + } + + const char kLoadResourceScript[] = R"( + var script = document.createElement("script"); + script.src = '%s'; + document.body.appendChild(script); + )"; + GURL resource = GenURL("3p.com", "/script"); + std::string loader_script = + base::StringPrintf(kLoadResourceScript, resource.spec().c_str()); + + EXPECT_TRUE(ExecuteScript(host_to_load_resource, loader_script)); + observer.WaitForResourceCompletion(resource); + return (*observer.FindResource(resource))->was_cached; + } + + GURL GenURL(const std::string& host, const std::string& path) { + return embedded_test_server()->GetURL(host, path); + } + + private: + DISALLOW_COPY_AND_ASSIGN(WebContentsSplitCacheBrowserTest); +}; + +class WebContentsSplitCacheBrowserTestEnabled + : public WebContentsSplitCacheBrowserTest { + public: + WebContentsSplitCacheBrowserTestEnabled() { + feature_list.InitAndEnableFeature( + net::features::kSplitCacheByTopFrameOrigin); + } + + private: + base::test::ScopedFeatureList feature_list; +}; + +class WebContentsSplitCacheBrowserTestDisabled + : public WebContentsSplitCacheBrowserTest { + public: + WebContentsSplitCacheBrowserTestDisabled() { + feature_list.InitAndDisableFeature( + net::features::kSplitCacheByTopFrameOrigin); + } + + private: + base::test::ScopedFeatureList feature_list; +}; + +IN_PROC_BROWSER_TEST_F(WebContentsSplitCacheBrowserTestEnabled, SplitCache) { + // Load a cacheable resource for the first time, and it's not cached. + EXPECT_FALSE(TestResourceLoad(GenURL("a.com", "/title1.html"), GURL())); + + // The second time, it's cached. + EXPECT_TRUE(TestResourceLoad(GenURL("a.com", "/title1.html"), GURL())); + + // Now load it from a different site, and the resource isn't cached because + // the top frame origin is different. + EXPECT_FALSE(TestResourceLoad(GenURL("b.com", "/title1.html"), GURL())); + + // Now load it from 3p.com, which is same-site to the cacheable + // resource. Still not supposed to be cached. + EXPECT_FALSE(TestResourceLoad(GenURL("3p.com", "/title1.html"), GURL())); + + // Load it from a a.com/redirect_to_d which redirects to d.com/title1.html and + // the resource shouldn't be cached because now we're on d.com. + EXPECT_FALSE(TestResourceLoad(GenURL("a.com", "/redirect_to_d"), GURL())); + + // Load the resource from a same-origin iframe on a page where it's already + // cached. It should still be cached. + EXPECT_TRUE(TestResourceLoad(GenURL("a.com", "/title1.html"), + GenURL("a.com", "/title1.html"))); + + // Load the resource from a cross-origin iframe on a page where it's already + // cached. It should still be cached. + EXPECT_TRUE(TestResourceLoad(GenURL("a.com", "/title1.html"), + GenURL("d.com", "/title1.html"))); + + // Load the resource from a same-origin iframe on a page where it's not + // cached. It should not be cached. + EXPECT_FALSE(TestResourceLoad(GenURL("e.com", "/title1.html"), + GenURL("e.com", "/title1.html"))); + + // Load the resource from a cross-origin iframe where the iframe's origin has + // seen the object before but the top frame hasn't. It should not be cached. + EXPECT_FALSE(TestResourceLoad(GenURL("f.com", "/title1.html"), + GenURL("a.com", "/title1.html"))); + + // Load the resource from a data url which has an opaque origin. It shouldn't + // be cached. + GURL data_url("data:text/html,<body>Hello World</body>"); + EXPECT_FALSE(TestResourceLoad(data_url, GURL())); + + // Load the same resource from the same data url, it shouldn't be cached + // because the origin should be unique. + // TODO(crbug.com/910711): This test should return false! Opaque origins + // shouldn't share cache space. The issue is that opaque origins stringify as + // "null". + EXPECT_TRUE(TestResourceLoad(data_url, GURL())); +} + +IN_PROC_BROWSER_TEST_F(WebContentsSplitCacheBrowserTestDisabled, + NonSplitCache) { + // Load a cacheable resource for the first time, and it's not cached. + EXPECT_FALSE(TestResourceLoad(GenURL("a.com", "/title1.html"), GURL())); + + // The second time, it's cached. + EXPECT_TRUE(TestResourceLoad(GenURL("a.com", "/title1.html"), GURL())); + + // Now load it from a different site, and the resource is cached. + EXPECT_TRUE(TestResourceLoad(GenURL("b.com", "/title1.html"), GURL())); + + // Load it from a cross-origin iframe, and it's still cached. + EXPECT_TRUE(TestResourceLoad(GenURL("b.com", "/title1.html"), + GenURL("c.com", "/title1.html"))); +} + IN_PROC_BROWSER_TEST_F(WebContentsImplBrowserTest, ResourceLoadCompleteFromLocalResource) { ResourceLoadObserver observer(shell());
diff --git a/content/common/media/peer_connection_tracker_messages.h b/content/common/media/peer_connection_tracker_messages.h index 73d4979..f95240e 100644 --- a/content/common/media/peer_connection_tracker_messages.h +++ b/content/common/media/peer_connection_tracker_messages.h
@@ -41,10 +41,7 @@ // Messages sent to PeerConnectionTracker. IPC_MESSAGE_CONTROL0(PeerConnectionTracker_GetAllStats) IPC_MESSAGE_CONTROL0(PeerConnectionTracker_OnSuspend) -IPC_MESSAGE_CONTROL2(PeerConnectionTracker_StartEventLogFile, - int /* peer_connection_local_id */, - IPC::PlatformFileForTransit /* file */) -IPC_MESSAGE_CONTROL2(PeerConnectionTracker_StartEventLogOutput, +IPC_MESSAGE_CONTROL2(PeerConnectionTracker_StartEventLog, int /* peer_connection_local_id */, int /* output_period_ms */) IPC_MESSAGE_CONTROL1(PeerConnectionTracker_StopEventLog,
diff --git a/content/public/browser/network_service_instance.h b/content/public/browser/network_service_instance.h index 3c3cbaa..3bed383 100644 --- a/content/public/browser/network_service_instance.h +++ b/content/public/browser/network_service_instance.h
@@ -12,6 +12,10 @@ #include "content/common/content_export.h" #include "services/network/public/cpp/network_connection_tracker.h" +namespace base { +class DeferredSequencedTaskRunner; +} + namespace net { class NetworkChangeNotifier; } // namespace net @@ -89,6 +93,12 @@ CONTENT_EXPORT void SetNetworkConnectionTrackerForTesting( network::NetworkConnectionTracker* network_connection_tracker); +// Gets the task runner for the thread the network service will be running on +// when running in-process. Can only be called when network service is in +// process. +CONTENT_EXPORT scoped_refptr<base::DeferredSequencedTaskRunner> +GetNetworkTaskRunner(); + } // namespace content #endif // CONTENT_PUBLIC_BROWSER_NETWORK_SERVICE_INSTANCE_H_
diff --git a/content/renderer/media/webrtc/peer_connection_tracker.cc b/content/renderer/media/webrtc/peer_connection_tracker.cc index cabde67..42ded54 100644 --- a/content/renderer/media/webrtc/peer_connection_tracker.cc +++ b/content/renderer/media/webrtc/peer_connection_tracker.cc
@@ -17,7 +17,6 @@ #include "base/strings/utf_string_conversions.h" #include "base/threading/thread_task_runner_handle.h" #include "base/values.h" -#include "build/build_config.h" #include "content/child/child_thread_impl.h" #include "content/common/media/peer_connection_tracker_messages.h" #include "content/renderer/media/webrtc/rtc_peer_connection_handler.h" @@ -500,10 +499,7 @@ IPC_BEGIN_MESSAGE_MAP(PeerConnectionTracker, message) IPC_MESSAGE_HANDLER(PeerConnectionTracker_GetAllStats, OnGetAllStats) IPC_MESSAGE_HANDLER(PeerConnectionTracker_OnSuspend, OnSuspend) - IPC_MESSAGE_HANDLER(PeerConnectionTracker_StartEventLogFile, - OnStartEventLogFile) - IPC_MESSAGE_HANDLER(PeerConnectionTracker_StartEventLogOutput, - OnStartEventLogOutput) + IPC_MESSAGE_HANDLER(PeerConnectionTracker_StartEventLog, OnStartEventLog) IPC_MESSAGE_HANDLER(PeerConnectionTracker_StopEventLog, OnStopEventLog) IPC_MESSAGE_UNHANDLED(handled = false) IPC_END_MESSAGE_MAP() @@ -541,29 +537,8 @@ } } -void PeerConnectionTracker::OnStartEventLogFile( - int peer_connection_id, - IPC::PlatformFileForTransit file) { - DCHECK_CALLED_ON_VALID_THREAD(main_thread_); - for (auto& it : peer_connection_id_map_) { - if (it.second == peer_connection_id) { -#if defined(OS_ANDROID) - // A lower maximum filesize is used on Android because storage space is - // more scarce on mobile. This upper limit applies to each peer connection - // individually, so the total amount of used storage can be a multiple of - // this. - const int64_t kMaxFilesizeBytes = 10000000; -#else - const int64_t kMaxFilesizeBytes = 60000000; -#endif - it.first->StartEventLog(file, kMaxFilesizeBytes); - return; - } - } -} - -void PeerConnectionTracker::OnStartEventLogOutput(int peer_connection_id, - int output_period_ms) { +void PeerConnectionTracker::OnStartEventLog(int peer_connection_id, + int output_period_ms) { DCHECK_CALLED_ON_VALID_THREAD(main_thread_); for (auto& it : peer_connection_id_map_) { if (it.second == peer_connection_id) {
diff --git a/content/renderer/media/webrtc/peer_connection_tracker.h b/content/renderer/media/webrtc/peer_connection_tracker.h index 17125e3a..2fe3082ee 100644 --- a/content/renderer/media/webrtc/peer_connection_tracker.h +++ b/content/renderer/media/webrtc/peer_connection_tracker.h
@@ -222,15 +222,8 @@ // Called when the browser process reports a suspend event from the OS. void OnSuspend(); - // TODO(eladalon): Remove OnStartEventLogFile() and then rename - // OnStartEventLogOutput() to OnStartEventLog(). https://crbug.com/775415 - - // IPC Message handler for starting event log (file). - void OnStartEventLogFile(int peer_connection_id, - IPC::PlatformFileForTransit file); - - // IPC Message handler for starting event log (output). - void OnStartEventLogOutput(int peer_connection_id, int output_period_ms); + // IPC Message handler for starting event log. + void OnStartEventLog(int peer_connection_id, int output_period_ms); // IPC Message handler for stopping event log. void OnStopEventLog(int peer_connection_id);
diff --git a/content/renderer/media/webrtc/rtc_peer_connection_handler.cc b/content/renderer/media/webrtc/rtc_peer_connection_handler.cc index 4248ec7..22a558a 100644 --- a/content/renderer/media/webrtc/rtc_peer_connection_handler.cc +++ b/content/renderer/media/webrtc/rtc_peer_connection_handler.cc
@@ -1835,17 +1835,6 @@ client_->ClosePeerConnection(); } -void RTCPeerConnectionHandler::StartEventLog(IPC::PlatformFileForTransit file, - int64_t max_file_size_bytes) { - DCHECK(task_runner_->RunsTasksInCurrentSequence()); - DCHECK(file != IPC::InvalidPlatformFileForTransit()); - // TODO(eladalon): StartRtcEventLog() return value is not useful; remove it - // or find a way to be able to use it. - // https://crbug.com/775415 - native_peer_connection_->StartRtcEventLog( - IPC::PlatformFileForTransitToPlatformFile(file), max_file_size_bytes); -} - void RTCPeerConnectionHandler::StartEventLog(int output_period_ms) { DCHECK(task_runner_->RunsTasksInCurrentSequence()); // TODO(eladalon): StartRtcEventLog() return value is not useful; remove it
diff --git a/content/renderer/media/webrtc/rtc_peer_connection_handler.h b/content/renderer/media/webrtc/rtc_peer_connection_handler.h index e036b58..a3a85c5 100644 --- a/content/renderer/media/webrtc/rtc_peer_connection_handler.h +++ b/content/renderer/media/webrtc/rtc_peer_connection_handler.h
@@ -24,7 +24,6 @@ #include "content/renderer/media/webrtc/rtc_rtp_sender.h" #include "content/renderer/media/webrtc/transceiver_state_surfacer.h" #include "content/renderer/media/webrtc/webrtc_media_stream_track_adapter_map.h" -#include "ipc/ipc_platform_file.h" #include "third_party/blink/public/platform/web_media_stream_source.h" #include "third_party/blink/public/platform/web_rtc_peer_connection_handler.h" #include "third_party/blink/public/platform/web_rtc_stats.h" @@ -186,10 +185,6 @@ virtual void CloseClientPeerConnection(); // Start recording an event log. - // TODO(crbug.com/775415): Remove he version with IPC::PlatformFileForTransit, - // since it's no longer used. - void StartEventLog(IPC::PlatformFileForTransit file, - int64_t max_file_size_bytes); void StartEventLog(int output_period_ms); // Stop recording an event log. void StopEventLog();
diff --git a/content/renderer/service_worker/service_worker_subresource_loader.cc b/content/renderer/service_worker/service_worker_subresource_loader.cc index 783b9a8..1e76f9bb 100644 --- a/content/renderer/service_worker/service_worker_subresource_loader.cc +++ b/content/renderer/service_worker/service_worker_subresource_loader.cc
@@ -7,8 +7,10 @@ #include "base/atomic_sequence_num.h" #include "base/callback.h" #include "base/feature_list.h" +#include "base/metrics/histogram_functions.h" #include "base/metrics/histogram_macros.h" #include "base/optional.h" +#include "base/strings/strcat.h" #include "base/trace_event/trace_event.h" #include "content/common/service_worker/service_worker_loader_helpers.h" #include "content/common/service_worker/service_worker_types.h" @@ -53,6 +55,23 @@ return new_head; } +const char* FetchResponseSourceToSuffix( + network::mojom::FetchResponseSource source) { + // Don't change these returned strings. They are used for recording UMAs. + switch (source) { + case network::mojom::FetchResponseSource::kUnspecified: + return ".Unspecified"; + case network::mojom::FetchResponseSource::kNetwork: + return ".Network"; + case network::mojom::FetchResponseSource::kHttpCache: + return ".HttpCache"; + case network::mojom::FetchResponseSource::kCacheStorage: + return ".CacheStorage"; + } + NOTREACHED(); + return ".Unknown"; +} + // A wrapper URLLoaderClient that invokes the given RewriteHeaderCallback // whenever a response or redirect is received. class HeaderRewritingURLLoaderClient : public network::mojom::URLLoaderClient { @@ -175,6 +194,7 @@ resource_request_(resource_request), fallback_factory_(std::move(fallback_factory)), task_runner_(std::move(task_runner)), + response_source_(network::mojom::FetchResponseSource::kUnspecified), weak_factory_(this) { DCHECK(controller_connector_); response_head_.request_start = base::TimeTicks::Now(); @@ -466,6 +486,7 @@ &response_head_); response_head_.response_start = base::TimeTicks::Now(); response_head_.load_timing.receive_headers_end = base::TimeTicks::Now(); + response_source_ = response->response_source; // Handle a redirect response. ComputeRedirectInfo returns non-null redirect // info if the given response is a redirect. @@ -624,6 +645,12 @@ "ServiceWorker.LoadTiming.Subresource." "ResponseReceivedToCompleted2", completion_time - response_head_.load_timing.receive_headers_end); + // Same as above, breakdown by response source. + base::UmaHistogramMediumTimes( + base::StrCat({"ServiceWorker.LoadTiming.Subresource." + "ResponseReceivedToCompleted2", + FetchResponseSourceToSuffix(response_source_)}), + completion_time - response_head_.load_timing.receive_headers_end); } else { // Mojo message delay (network fallback case). See above for the detail. UMA_HISTOGRAM_TIMES(
diff --git a/content/renderer/service_worker/service_worker_subresource_loader.h b/content/renderer/service_worker/service_worker_subresource_loader.h index 3c9da8d1..8e2cb7e 100644 --- a/content/renderer/service_worker/service_worker_subresource_loader.h +++ b/content/renderer/service_worker/service_worker_subresource_loader.h
@@ -193,6 +193,7 @@ scoped_refptr<base::SequencedTaskRunner> task_runner_; blink::mojom::ServiceWorkerFetchEventTimingPtr fetch_event_timing_; + network::mojom::FetchResponseSource response_source_; base::WeakPtrFactory<ServiceWorkerSubresourceLoader> weak_factory_;
diff --git a/content/renderer/service_worker/service_worker_subresource_loader_unittest.cc b/content/renderer/service_worker/service_worker_subresource_loader_unittest.cc index 6c0bbca..6698317 100644 --- a/content/renderer/service_worker/service_worker_subresource_loader_unittest.cc +++ b/content/renderer/service_worker/service_worker_subresource_loader_unittest.cc
@@ -129,11 +129,13 @@ ~FakeControllerServiceWorker() override = default; static blink::mojom::FetchAPIResponsePtr OkResponse( - blink::mojom::SerializedBlobPtr blob_body) { + blink::mojom::SerializedBlobPtr blob_body, + network::mojom::FetchResponseSource response_source) { auto response = blink::mojom::FetchAPIResponse::New(); response->status_code = 200; response->status_text = "OK"; response->response_type = network::mojom::FetchResponseType::kDefault; + response->response_source = response_source; response->blob = std::move(blob_body); if (response->blob) { response->headers.emplace("Content-Length", @@ -240,6 +242,10 @@ } } + void SetResponseSource(network::mojom::FetchResponseSource source) { + response_source_ = source; + } + // blink::mojom::ControllerServiceWorker: void DispatchFetchEvent( blink::mojom::DispatchFetchEventParamsPtr params, @@ -257,8 +263,9 @@ switch (response_mode_) { case ResponseMode::kDefault: - response_callback->OnResponse(OkResponse(nullptr /* blob_body */), - std::move(timing)); + response_callback->OnResponse( + OkResponse(nullptr /* blob_body */, response_source_), + std::move(timing)); std::move(callback).Run( blink::mojom::ServiceWorkerEventStatus::COMPLETED); break; @@ -267,15 +274,16 @@ blink::mojom::ServiceWorkerEventStatus::ABORTED); break; case ResponseMode::kStream: - response_callback->OnResponseStream(OkResponse(nullptr /* blob_body */), - std::move(stream_handle_), - std::move(timing)); + response_callback->OnResponseStream( + OkResponse(nullptr /* blob_body */, response_source_), + std::move(stream_handle_), std::move(timing)); std::move(callback).Run( blink::mojom::ServiceWorkerEventStatus::COMPLETED); break; case ResponseMode::kBlob: - response_callback->OnResponse(OkResponse(std::move(blob_body_)), - std::move(timing)); + response_callback->OnResponse( + OkResponse(std::move(blob_body_), response_source_), + std::move(timing)); std::move(callback).Run( blink::mojom::ServiceWorkerEventStatus::COMPLETED); break; @@ -303,7 +311,7 @@ mojo::MakeRequest(&blob->blob)); // Respond with a 206 response. - auto response = OkResponse(std::move(blob)); + auto response = OkResponse(std::move(blob), response_source_); response->status_code = 206; response->headers.emplace( "Content-Range", base::StringPrintf("bytes %zu-%zu/%zu", start, end, @@ -383,6 +391,9 @@ // For ResponseMode::kRedirectResponse std::string redirect_location_header_; + network::mojom::FetchResponseSource response_source_ = + network::mojom::FetchResponseSource::kUnspecified; + DISALLOW_COPY_AND_ASSIGN(FakeControllerServiceWorker); }; @@ -639,6 +650,10 @@ 1); histogram_tester.ExpectTotalCount( "ServiceWorker.LoadTiming.Subresource.ResponseReceivedToCompleted2", 1); + histogram_tester.ExpectTotalCount( + "ServiceWorker.LoadTiming.Subresource.ResponseReceivedToCompleted2." + "Unspecified", + 1); } TEST_F(ServiceWorkerSubresourceLoaderTest, Abort) { @@ -876,6 +891,8 @@ mojo::DataPipe data_pipe; fake_controller_.RespondWithStream(mojo::MakeRequest(&stream_callback), std::move(data_pipe.consumer_handle)); + fake_controller_.SetResponseSource( + network::mojom::FetchResponseSource::kNetwork); network::mojom::URLLoaderFactoryPtr factory = CreateSubresourceLoaderFactory(); @@ -919,6 +936,10 @@ 1); histogram_tester.ExpectTotalCount( "ServiceWorker.LoadTiming.Subresource.ResponseReceivedToCompleted2", 1); + histogram_tester.ExpectTotalCount( + "ServiceWorker.LoadTiming.Subresource.ResponseReceivedToCompleted2." + "Network", + 1); } TEST_F(ServiceWorkerSubresourceLoaderTest, StreamResponse_Abort) { @@ -984,6 +1005,8 @@ 0x8D, 0xE3, 0x81, 0xBF, 0xE3, 0x81, 0x86, 0xE3, 0x82, 0x80}; fake_controller_.RespondWithBlob(kMetadata, kResponseBody); + fake_controller_.SetResponseSource( + network::mojom::FetchResponseSource::kCacheStorage); network::mojom::URLLoaderFactoryPtr factory = CreateSubresourceLoaderFactory(); @@ -1024,6 +1047,10 @@ 1); histogram_tester.ExpectTotalCount( "ServiceWorker.LoadTiming.Subresource.ResponseReceivedToCompleted2", 1); + histogram_tester.ExpectTotalCount( + "ServiceWorker.LoadTiming.Subresource.ResponseReceivedToCompleted2." + "CacheStorage", + 1); } TEST_F(ServiceWorkerSubresourceLoaderTest, BlobResponseWithoutMetadata) {
diff --git a/content/test/gpu/gpu_tests/pixel_expectations.py b/content/test/gpu/gpu_tests/pixel_expectations.py index 09da641c..dde2aaa 100644 --- a/content/test/gpu/gpu_tests/pixel_expectations.py +++ b/content/test/gpu/gpu_tests/pixel_expectations.py
@@ -58,15 +58,11 @@ # TODO(kbr): flakily timing out on this configuration. self.Flaky('*', ['linux', 'intel', 'debug'], bug=648369) - # TODO(sunnyps): re-enable after rebaselining - # self.Flaky('Pixel_Video_MP4', ['android', 'nvidia'], bug=716564) - # self.Flaky('Pixel_Video_MP4', ['linux', 'nvidia'], bug=819635) + # Flaky on Linux Nvidia + self.Flaky('Pixel_Video_MP4', ['linux', 'nvidia'], bug=819635) - # TODO(sunnyps): temporarily disabling for rebaselining. - self.Fail('Pixel_Video_MP4', bug=869677) - self.Fail('Pixel_Video_VP9', bug=869677) - self.Fail('Pixel_DirectComposition_Video_MP4', bug=869677) - self.Fail('Pixel_DirectComposition_Video_VP9', bug=869677) + # Fails on Linux Nvidia + self.Fail('Pixel_Video_VP9', ['linux', 'nvidia'], bug=858826) # Flaky for unknown reasons only on macOS. Not planning to investigate # further. @@ -83,11 +79,10 @@ ['android', ('qualcomm', 'Adreno (TM) 330')], bug=773293) # Failing on Mac Intel HighSierra - # TODO(sunnyps): re-enable after rebaselining. - # self.Fail('Pixel_Video_MP4', - # ['highsierra', ('intel', 0xa2e)], bug=774809) - # self.Fail('Pixel_Video_VP9', - # ['highsierra', ('intel', 0xa2e)], bug=774809) + self.Fail('Pixel_Video_MP4', + ['highsierra', ('intel', 0xa2e)], bug=774809) + self.Fail('Pixel_Video_VP9', + ['highsierra', ('intel', 0xa2e)], bug=774809) self.Fail('Pixel_WebGLGreenTriangle_NonChromiumImage_NoAA_NoAlpha', ['highsierra', 'mojave', ('intel', 0xa2e)], bug=774809) self.Flaky('Pixel_OffscreenCanvasTransferBeforeStyleResize', @@ -116,9 +111,9 @@ self.Fail('Pixel_WebGLSadCanvas', ['mac'], bug=872423) self.Fail('Pixel_WebGLSadCanvas', ['android'], bug=575305) - # Flaky on Android: crbug.com/860548 - # TODO(sunnyps): re-enable after rebaselining. - # self.Flaky('Pixel_Video_VP9', ['android'], bug=860548) + # Failing on Android in general: crbug.com/858826 + self.Fail('Pixel_Video_MP4', ['android'], bug=858826) + self.Fail('Pixel_Video_VP9', ['android'], bug=858826) self.Fail('Pixel_CanvasLowLatencyWebGL', ['android', 'nvidia'], bug=868596) self.Fail('Pixel_OffscreenCanvasWebGLPaintAfterResize', @@ -147,3 +142,9 @@ ['mac', ('amd', 0x679e)], bug=911413) self.Fail('Pixel_Video_MP4_FourColors_Rot_270', ['mac', ('amd', 0x679e)], bug=911413) + + # Fails on Windows Nvidia + self.Fail('Pixel_DirectComposition_Video_MP4', ['win', 'nvidia'], + bug=913138) + self.Fail('Pixel_DirectComposition_Video_VP9', ['win', 'nvidia'], + bug=913138)
diff --git a/docs/ui/aura/index.md b/docs/ui/aura/index.md new file mode 100644 index 0000000..296dd60 --- /dev/null +++ b/docs/ui/aura/index.md
@@ -0,0 +1,7 @@ +# Aura + +Aura abstracts the Window Manager away from Chromium on Windows, Linux, and +Chrome OS. + +# Main Documentation +* [Aura (Historical)](https://dev.chromium.org/developers/design-documents/aura)
diff --git a/docs/ui/compositor/index.md b/docs/ui/compositor/index.md new file mode 100644 index 0000000..0f5f371 --- /dev/null +++ b/docs/ui/compositor/index.md
@@ -0,0 +1,3 @@ +# Compositor + +[Main Documentation (Historical)](https://www.chromium.org/developers/design-documents/chromium-graphics)
diff --git a/docs/ui/frontline_triage.md b/docs/ui/frontline_triage.md new file mode 100644 index 0000000..1f88d193 --- /dev/null +++ b/docs/ui/frontline_triage.md
@@ -0,0 +1,45 @@ +# Chromium UI Frontline Triage Procedures and Policy + +## Filing New Issues + +### Steps + +0. Read and follow the [Chromium Code of Conduct](https://chromium.googlesource.com/chromium/src/+/master/CODE_OF_CONDUCT.md). +1. File your issue on http://crbug.com/. + * Required: Repro Steps + * Preferred: Screenshots + * Optional: Video Repro (Please keep brief and to the point) +2. Add the label Hotlist-DesktopUIConsider. +3. Find an appropriate component. + +### Consideration Deadline +Issues must be marked Hotlist-DesktopUIConsider by Wednesday 5:00p PT for +consideration for that week. + +## Weekly Triage Process +1. After the consideration deadline, query for all Hotlist-DesktopUIConsider + bugs. +2. For each bug, perform the following: + 1. Assess Priority + * P0: Emergency, must be fixed now or before the next Canary. Mark with a + ReleaseBlock label for the nearest build that does not have the + issue. + * P1: Bug most users will hit. Mark with a ReleaseBlock label. + * Mark ReleaseBlock-Dev if the issue impacts a core scenario (like + scrolling). + * Mark ReleaseBlock-Beta if the issue impacts a secondary scenario. + * Mark ReleaseBlock-Stable if Chrome should never ship with this issue. + * P2 - Bug that many users may hit and/or has a reasonable workaround. + * P3 - Bug that few users will hit. + 2. Schedule a milestone. + 3. Assign to relevant area owner: + * Omnibox: jdonneley@ + * Top Chrome: dfried@ + * UI Platform: robliao@ + * WebUI: dpapad@ +3. Once all bugs are triaged, remove the Hotlist-DesktopUIConsider label and add + Hotlist-DesktopUITriaged. + +## Periodic Review at Milestone Branch +For all Hotlist-DesktopUITriaged bugs, reassess priority and milestone using the +above standards.
diff --git a/docs/ui/index.md b/docs/ui/index.md new file mode 100644 index 0000000..54866b75 --- /dev/null +++ b/docs/ui/index.md
@@ -0,0 +1,7 @@ +# Chromium UI Development +Developing in Chromium UI? Trying to figure out how we handle bugs? You've +reached the right place. + +# Bug Triage +Chromium UI Bug Triage is sharded between several teams. +* [Frontline Triage Procedures](frontline_triage.md)
diff --git a/docs/ui/navbar.md b/docs/ui/navbar.md new file mode 100644 index 0000000..f960d40 --- /dev/null +++ b/docs/ui/navbar.md
@@ -0,0 +1,9 @@ +# Chromium UI Platform + +* [Chromium Docs Home](/docs/README.md) +* [Chromium UI](/docs/ui/index.md) +* [Aura](/docs/ui/aura/index.md) +* [Compositor](/docs/ui/compositor/index.md) +* [Views](/docs/ui/views/overview.md) + +[home]: /docs/ui/index.md
diff --git a/docs/windows_build_instructions.md b/docs/windows_build_instructions.md index b53b6b8..5350c0e 100644 --- a/docs/windows_build_instructions.md +++ b/docs/windows_build_instructions.md
@@ -23,21 +23,34 @@ ### Visual Studio -As of September, 2017 (R503915) Chromium requires Visual Studio 2017 (15.7.2) -to build. The clang-cl compiler is used but Visual Studio's header files, -libraries, and some tools are required. Visual Studio Community Edition should -work if its license is appropriate for you. You must install the "Desktop +As of September, 2017 (R503915) Chromium requires Visual Studio 2017 (15.7.2 or +higher) to build. The clang-cl compiler is used but Visual Studio's header +files, libraries, and some tools are required. Visual Studio Community Edition +should work if its license is appropriate for you. You must install the "Desktop development with C++" component and the "MFC and ATL support" sub-component. This can be done from the command line by passing these arguments to the Visual -Studio installer that you download: +Studio installer that you download (see below for ARM64 instructions): ```shell ---add Microsoft.VisualStudio.Workload.NativeDesktop - --add Microsoft.VisualStudio.Component.VC.ATLMFC --includeRecommended +$ PATH_TO_INSTALLER.EXE ^ +--add Microsoft.VisualStudio.Workload.NativeDesktop ^ +--add Microsoft.VisualStudio.Component.VC.ATLMFC ^ +--includeRecommended ``` -You must have the version 10.0.17134 Windows 10 SDK installed. This can be -installed separately or by checking the appropriate box in the Visual Studio -Installer. +If you want to build for ARM64 Win32 then some extra arguments are needed. The +full set for that case is: +```shell +$ PATH_TO_INSTALLER.EXE ^ +--add Microsoft.VisualStudio.Workload.NativeDesktop ^ +--add Microsoft.VisualStudio.Component.VC.ATLMFC ^ +--add Microsoft.VisualStudio.Component.VC.Tools.ARM64 ^ +--add Microsoft.VisualStudio.Component.VC.MFC.ARM64 ^ +--includeRecommended +``` + +You must have the version 10.0.17134 or higher Windows 10 SDK installed. This +can be installed separately or by checking the appropriate box in the Visual +Studio Installer. The SDK Debugging Tools must also be installed. If the Windows 10 SDK was installed via the Visual Studio installer, then they can be installed by going
diff --git a/extensions/browser/event_router.cc b/extensions/browser/event_router.cc index f9c61859..fc5753b 100644 --- a/extensions/browser/event_router.cc +++ b/extensions/browser/event_router.cc
@@ -1005,8 +1005,8 @@ Event::~Event() {} -Event* Event::DeepCopy() const { - Event* copy = new Event( +std::unique_ptr<Event> Event::DeepCopy() const { + auto copy = std::make_unique<Event>( histogram_value, event_name, event_args->CreateDeepCopy(), restrict_to_browser_context, event_url, user_gesture, filter_info); copy->will_dispatch_callback = will_dispatch_callback;
diff --git a/extensions/browser/event_router.h b/extensions/browser/event_router.h index 8e51c71..0397e21 100644 --- a/extensions/browser/event_router.h +++ b/extensions/browser/event_router.h
@@ -462,10 +462,8 @@ ~Event(); - // Makes a deep copy of this instance. Ownership is transferred to the - // caller. - // TODO(devlin): Have this return a unique_ptr. - Event* DeepCopy() const; + // Makes a deep copy of this instance. + std::unique_ptr<Event> DeepCopy() const; }; struct EventListenerInfo {
diff --git a/extensions/browser/events/lazy_event_dispatcher.cc b/extensions/browser/events/lazy_event_dispatcher.cc index 0fd7352..eec97c47 100644 --- a/extensions/browser/events/lazy_event_dispatcher.cc +++ b/extensions/browser/events/lazy_event_dispatcher.cc
@@ -107,7 +107,7 @@ // to avoid lifetime issues. Use a separate copy of the event args, so they // last until the event is dispatched. if (!event_->will_dispatch_callback.is_null()) { - dispatched_event.reset(event_->DeepCopy()); + dispatched_event.reset(event_->DeepCopy().release()); if (!dispatched_event->will_dispatch_callback.Run( dispatch_context->browser_context(), extension, dispatched_event.get(), listener_filter)) {
diff --git a/extensions/browser/extension_function_histogram_value.h b/extensions/browser/extension_function_histogram_value.h index 541dace..162320b7 100644 --- a/extensions/browser/extension_function_histogram_value.h +++ b/extensions/browser/extension_function_histogram_value.h
@@ -1359,6 +1359,7 @@ INPUTMETHODPRIVATE_SETSETTING = 1296, FILEMANAGERPRIVATEINTERNAL_UNSHAREPATHWITHCROSTINI = 1297, PASSWORDSPRIVATE_RECORDPASSWORDSPAGEACCESSINSETTINGS = 1298, + AUTOFILLPRIVATE_SERVERCARDLINKCLICKED = 1299, // Last entry: Add new entries above, then run: // python tools/metrics/histograms/update_extension_histograms.py ENUM_BOUNDARY
diff --git a/extensions/browser/test_event_router_observer.cc b/extensions/browser/test_event_router_observer.cc index 0837566c..5846d603 100644 --- a/extensions/browser/test_event_router_observer.cc +++ b/extensions/browser/test_event_router_observer.cc
@@ -4,8 +4,6 @@ #include "extensions/browser/test_event_router_observer.h" -#include "base/memory/ptr_util.h" - namespace extensions { TestEventRouterObserver::TestEventRouterObserver(EventRouter* event_router) @@ -26,12 +24,12 @@ void TestEventRouterObserver::OnWillDispatchEvent(const Event& event) { DCHECK(!event.event_name.empty()); - events_[event.event_name] = base::WrapUnique(event.DeepCopy()); + events_[event.event_name] = event.DeepCopy(); } void TestEventRouterObserver::OnDidDispatchEventToProcess(const Event& event) { DCHECK(!event.event_name.empty()); - dispatched_events_[event.event_name] = base::WrapUnique(event.DeepCopy()); + dispatched_events_[event.event_name] = event.DeepCopy(); } } // namespace extensions
diff --git a/extensions/common/manifest_constants.cc b/extensions/common/manifest_constants.cc index 96e17e5..d11479d 100644 --- a/extensions/common/manifest_constants.cc +++ b/extensions/common/manifest_constants.cc
@@ -719,6 +719,7 @@ const char kNPAPIPluginsNotSupported[] = "NPAPI plugins are not supported."; const char kOneUISurfaceOnly[] = "Only one of 'browser_action', 'page_action', and 'app' can be specified."; +const char kPageCaptureNeeded[] = "'pageCapture' permission is required."; const char kPermissionMarkedOptionalAndRequired[] = "Optional permission '*' is redundant with the required permissions;" "this permission will be omitted.";
diff --git a/extensions/common/manifest_constants.h b/extensions/common/manifest_constants.h index cc5a4a59..9b619031 100644 --- a/extensions/common/manifest_constants.h +++ b/extensions/common/manifest_constants.h
@@ -487,6 +487,7 @@ extern const char kNoWildCardsInPaths[]; extern const char kNPAPIPluginsNotSupported[]; extern const char kOneUISurfaceOnly[]; +extern const char kPageCaptureNeeded[]; extern const char kPermissionMarkedOptionalAndRequired[]; extern const char kPermissionMustBeOptional[]; extern const char kPermissionNotAllowed[];
diff --git a/extensions/common/permissions/permissions_data.cc b/extensions/common/permissions/permissions_data.cc index b0716c4..cbac510 100644 --- a/extensions/common/permissions/permissions_data.cc +++ b/extensions/common/permissions/permissions_data.cc
@@ -355,11 +355,14 @@ tab_permissions ? &tab_permissions->scriptable_hosts() : nullptr, error); } -bool PermissionsData::CanCaptureVisiblePage(const GURL& document_url, - int tab_id, - std::string* error) const { +bool PermissionsData::CanCaptureVisiblePage( + const GURL& document_url, + int tab_id, + std::string* error, + CaptureRequirement capture_requirement) const { bool has_active_tab = false; bool has_all_urls = false; + bool has_page_capture = false; // Check the real origin, in order to account for filesystem:, blob:, etc. // (url::Origin grabs the inner origin of these, whereas GURL::GetOrigin() // does not.) @@ -387,39 +390,54 @@ URLPattern::kAllUrlsPattern); has_all_urls = active_permissions_unsafe_->explicit_hosts().ContainsPattern(all_urls); + has_page_capture = active_permissions_unsafe_->HasAPIPermission( + APIPermission::kPageCapture); } - - // At least one of activeTab or <all_urls> is always required; no exceptions. - if (!has_active_tab && !has_all_urls) { - if (error) - *error = manifest_errors::kAllURLOrActiveTabNeeded; - return false; - } - - // We check GetPageAccess() (in addition to the <all_urls> and activeTab - // checks below) for the case of URLs that can be conditionally granted (such - // as file:// URLs or chrome:// URLs for component extensions). - // If an extension has <all_urls>, GetPageAccess() will still (correctly) - // return false if, for instance, the URL is a file:// URL and the extension - // does not have file access. - // See https://crbug.com/810220. - // If the extension has page access (and has activeTab or <all_urls>, as - // checked above), allow the capture. std::string access_error; - if (GetPageAccess(origin_url, tab_id, &access_error) == PageAccess::kAllowed) - return true; + if (capture_requirement == CaptureRequirement::kActiveTabOrAllUrls) { + if (!has_active_tab && !has_all_urls) { + if (error) + *error = manifest_errors::kAllURLOrActiveTabNeeded; + return false; + } + + // We check GetPageAccess() (in addition to the <all_urls> and activeTab + // checks below) for the case of URLs that can be conditionally granted + // (such as file:// URLs or chrome:// URLs for component extensions). If an + // extension has <all_urls>, GetPageAccess() will still (correctly) return + // false if, for instance, the URL is a file:// URL and the extension does + // not have file access. See https://crbug.com/810220. If the extension has + // page access (and has activeTab or <all_urls>), allow the capture. + if (GetPageAccess(origin_url, tab_id, &access_error) == + PageAccess::kAllowed) + return true; + } else { + DCHECK_EQ(CaptureRequirement::kPageCapture, capture_requirement); + if (!has_page_capture) { + if (error) + *error = manifest_errors::kPageCaptureNeeded; + } + + // If the URL is a typical web URL, the pageCapture permission is + // sufficient. + if ((origin_url.SchemeIs(url::kHttpScheme) || + origin_url.SchemeIs(url::kHttpsScheme)) && + !origin.IsSameOriginWith(url::Origin::Create( + ExtensionsClient::Get()->GetWebstoreBaseURL()))) { + return true; + } + } // The extension doesn't have explicit page access. However, there are a // number of cases where tab capture may still be allowed. // First special case: an extension's own pages. // These aren't restricted URLs, but won't be matched by <all_urls> or - // activeTab (since the extension scheme is not included in the list of valid - // schemes for extension permissions). - // To capture an extension's own page, either activeTab or <all_urls> is - // needed (it's no higher privilege than a normal web page). At least one - // of these is still needed because the extension page may have embedded - // web content. + // activeTab (since the extension scheme is not included in the list of + // valid schemes for extension permissions). To capture an extension's own + // page, either activeTab or <all_urls> is needed (it's no higher privilege + // than a normal web page). At least one of these is still needed because + // the extension page may have embedded web content. // TODO(devlin): Should activeTab/<all_urls> account for the extension's own // domain? if (origin_url.host() == extension_id_) @@ -449,7 +467,6 @@ *error = access_error; return false; } - // If the extension has activeTab, these origins are allowed. if (has_active_tab) return true;
diff --git a/extensions/common/permissions/permissions_data.h b/extensions/common/permissions/permissions_data.h index 68cba77..f6e5c89 100644 --- a/extensions/common/permissions/permissions_data.h +++ b/extensions/common/permissions/permissions_data.h
@@ -24,6 +24,16 @@ namespace extensions { class URLPatternSet; +// The possible type of requirements needed in order to capture the current +// page. +enum class CaptureRequirement { + kActiveTabOrAllUrls, // The extension needs to have the <all_urls> or + // activeTab permission in order to capture the current + // page. + kPageCapture, // <all_urls> is not a requirement to be able to capture + // the current page. +}; + // A container for the permissions state of an extension, including active, // withheld, and tab-specific permissions. // Thread-Safety: Since this is an object on the Extension object, *some* thread @@ -214,11 +224,11 @@ // is insufficient. // Instead: // - If the page is a chrome:// page, require activeTab. - // - For all other pages, require host permissions to the document - // (GetPageAccess()) and one of either <all_urls> or granted activeTab. + // - For all other pages, ensure |capture_requirement| is satisfied. bool CanCaptureVisiblePage(const GURL& document_url, int tab_id, - std::string* error) const; + std::string* error, + CaptureRequirement capture_requirement) const; const TabPermissionsMap& tab_specific_permissions() const { DCHECK(!thread_checker_ || thread_checker_->CalledOnValidThread());
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder.cc b/gpu/command_buffer/service/gles2_cmd_decoder.cc index 2fc9a53..6ddbef4 100644 --- a/gpu/command_buffer/service/gles2_cmd_decoder.cc +++ b/gpu/command_buffer/service/gles2_cmd_decoder.cc
@@ -10889,7 +10889,7 @@ return true; } -bool GLES2DecoderImpl::CheckMultiDrawArraysVertices( +ALWAYS_INLINE bool GLES2DecoderImpl::CheckMultiDrawArraysVertices( const char* function_name, bool instanced, const GLint* firsts, @@ -10943,13 +10943,14 @@ return true; } -bool GLES2DecoderImpl::CheckTransformFeedback(const char* function_name, - bool instanced, - GLenum mode, - const GLsizei* counts, - const GLsizei* primcounts, - GLsizei drawcount, - GLsizei* vertices_drawn) { +ALWAYS_INLINE bool GLES2DecoderImpl::CheckTransformFeedback( + const char* function_name, + bool instanced, + GLenum mode, + const GLsizei* counts, + const GLsizei* primcounts, + GLsizei drawcount, + GLsizei* vertices_drawn) { DCHECK(state_.bound_transform_feedback.get()); if (state_.bound_transform_feedback->active() && !state_.bound_transform_feedback->paused()) { @@ -10983,13 +10984,14 @@ return true; } -error::Error GLES2DecoderImpl::DoMultiDrawArrays(const char* function_name, - bool instanced, - GLenum mode, - const GLint* firsts, - const GLsizei* counts, - const GLsizei* primcounts, - GLsizei drawcount) { +ALWAYS_INLINE error::Error GLES2DecoderImpl::DoMultiDrawArrays( + const char* function_name, + bool instanced, + GLenum mode, + const GLint* firsts, + const GLsizei* counts, + const GLsizei* primcounts, + GLsizei drawcount) { error::Error error = WillAccessBoundFramebufferForDraw(); if (error != error::kNoError) return error; @@ -11125,7 +11127,7 @@ &primcount, 1); } -bool GLES2DecoderImpl::CheckMultiDrawElementsVertices( +ALWAYS_INLINE bool GLES2DecoderImpl::CheckMultiDrawElementsVertices( const char* function_name, bool instanced, const GLsizei* counts, @@ -11180,14 +11182,15 @@ return true; } -error::Error GLES2DecoderImpl::DoMultiDrawElements(const char* function_name, - bool instanced, - GLenum mode, - const GLsizei* counts, - GLenum type, - const int32_t* offsets, - const GLsizei* primcounts, - GLsizei drawcount) { +ALWAYS_INLINE error::Error GLES2DecoderImpl::DoMultiDrawElements( + const char* function_name, + bool instanced, + GLenum mode, + const GLsizei* counts, + GLenum type, + const int32_t* offsets, + const GLsizei* primcounts, + GLsizei drawcount) { error::Error error = WillAccessBoundFramebufferForDraw(); if (error != error::kNoError) return error; @@ -13745,7 +13748,7 @@ bool result = false; if (api()->glCheckFramebufferStatusEXTFn(fb_target) == GL_FRAMEBUFFER_COMPLETE) { - api()->glColorMaskFn(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); + state_.SetDeviceColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); api()->glClearColorFn(0.0, 0.0, 0.0, 0.0); api()->glClearStencilFn(0); state_.SetDeviceStencilMaskSeparate(GL_FRONT, kDefaultStencilMask);
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_drawing.cc b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_drawing.cc index a492e391..69e8df6 100644 --- a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_drawing.cc +++ b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_drawing.cc
@@ -2304,7 +2304,7 @@ .WillOnce(Return(GL_FRAMEBUFFER_COMPLETE)) .RetiresOnSaturation(); - EXPECT_CALL(*gl_, ColorMask(1, 1, 1, 1)).Times(1).RetiresOnSaturation(); + SetupExpectationsForColorMask(true, true, true, true); EXPECT_CALL(*gl_, ClearColor(0.0f, 0.0f, 0.0f, 0.0f)) .Times(1) .RetiresOnSaturation(); @@ -2378,7 +2378,7 @@ .WillOnce(Return(GL_FRAMEBUFFER_COMPLETE)) .RetiresOnSaturation(); - EXPECT_CALL(*gl_, ColorMask(1, 1, 1, 1)).Times(1).RetiresOnSaturation(); + SetupExpectationsForColorMask(true, true, true, true); EXPECT_CALL(*gl_, ClearColor(0.0f, 0.0f, 0.0f, 0.0f)) .Times(1) .RetiresOnSaturation();
diff --git a/gpu/command_buffer/service/raster_decoder.cc b/gpu/command_buffer/service/raster_decoder.cc index e34d92f..e020829 100644 --- a/gpu/command_buffer/service/raster_decoder.cc +++ b/gpu/command_buffer/service/raster_decoder.cc
@@ -13,6 +13,7 @@ #include "base/atomic_sequence_num.h" #include "base/containers/flat_map.h" +#include "base/debug/crash_logging.h" #include "base/logging.h" #include "base/memory/ref_counted.h" #include "base/memory/weak_ptr.h" @@ -884,6 +885,9 @@ // Make this decoder's GL context current. bool RasterDecoderImpl::MakeCurrent() { + if (raster_decoder_context_state_->use_vulkan_gr_context) + return true; + if (!context_.get()) return false; @@ -1606,12 +1610,14 @@ } void RasterDecoderImpl::DoFinish() { - api()->glFinishFn(); + if (!raster_decoder_context_state_->use_vulkan_gr_context) + api()->glFinishFn(); ProcessPendingQueries(true); } void RasterDecoderImpl::DoFlush() { - api()->glFlushFn(); + if (!raster_decoder_context_state_->use_vulkan_gr_context) + api()->glFlushFn(); ProcessPendingQueries(false); } @@ -2321,24 +2327,33 @@ return; } - deserialized_op->Raster(canvas, playback_params); - deserialized_op->DestroyThis(); - - paint_buffer_size -= skip; - paint_buffer_memory += skip; - #if defined(OS_MACOSX) - // Aggressively call glFlush on macOS to determine if this is sufficient to - // avoid GL driver crashes. This will cause very significant performance - // regressions. - // TODO(ccameron): If this makes the crashes go away, then (1) try moving - // this flush outside of the above while loop and (2) add instrumentation - // to find the culprit ops. + // Flush before and after the raster op. Add crash instrumentation to dump + // the current raster op. + // TODO(ccameron): Harvest this data to see if there is a pattern to the ops + // that cause crashes. // https://crbug.com/906453 if (gr_context()) gr_context()->flush(); api()->glFlushFn(); + static auto* crash_key = base::debug::AllocateCrashKeyString( + "mac_paint_op_in_flush", base::debug::CrashKeySize::Size32); + base::debug::SetCrashKeyString( + crash_key, cc::PaintOpTypeToString(deserialized_op->GetType())); #endif + + deserialized_op->Raster(canvas, playback_params); + deserialized_op->DestroyThis(); + +#if defined(OS_MACOSX) + if (gr_context()) + gr_context()->flush(); + api()->glFlushFn(); + base::debug::ClearCrashKeyString(crash_key); +#endif + + paint_buffer_size -= skip; + paint_buffer_memory += skip; } } @@ -2383,19 +2398,6 @@ // prepareForExternalIO above. Use kDeferLaterCommands to ensure we yield to // the Scheduler before processing more commands. current_decoder_error_ = error::kDeferLaterCommands; - -#if defined(OS_MACOSX) - // Aggressively call glFlush on macOS to determine if this is sufficient to - // avoid GL driver crashes. - // TODO(ccameron): If this is not sufficient, then add a flush to - // DoRasterCHROMIUM as well. Also add crash report data to indicate which - // sequence of commands result in the crash, and formalize this as a GPU - // bug workaround. - // https://crbug.com/906453 - if (gr_context()) - gr_context()->flush(); - api()->glFlushFn(); -#endif } void RasterDecoderImpl::DoCreateTransferCacheEntryINTERNAL(
diff --git a/gpu/command_buffer/service/raster_decoder_context_state.cc b/gpu/command_buffer/service/raster_decoder_context_state.cc index 9dc7b516..dc08769 100644 --- a/gpu/command_buffer/service/raster_decoder_context_state.cc +++ b/gpu/command_buffer/service/raster_decoder_context_state.cc
@@ -45,6 +45,8 @@ real_context_(std::move(context)), surface_(std::move(surface)), weak_ptr_factory_(this) { + if (use_vulkan_gr_context) + use_virtualized_gl_contexts = false; if (base::ThreadTaskRunnerHandle::IsSet()) { base::trace_event::MemoryDumpManager::GetInstance()->RegisterDumpProvider( this, "RasterDecoderContextState", base::ThreadTaskRunnerHandle::Get()); @@ -161,6 +163,9 @@ } bool RasterDecoderContextState::MakeCurrent(gl::GLSurface* surface) { + if (use_vulkan_gr_context) + return true; + if (context_lost_) return false; @@ -183,6 +188,8 @@ } bool RasterDecoderContextState::IsCurrent(gl::GLSurface* surface) { + if (use_vulkan_gr_context) + return true; return context_->IsCurrent(surface); }
diff --git a/gpu/command_buffer/service/raster_decoder_unittest.cc b/gpu/command_buffer/service/raster_decoder_unittest.cc index efce9b9..620842ab 100644 --- a/gpu/command_buffer/service/raster_decoder_unittest.cc +++ b/gpu/command_buffer/service/raster_decoder_unittest.cc
@@ -8,7 +8,6 @@ #include "base/command_line.h" #include "base/memory/ptr_util.h" -#include "build/build_config.h" #include "gpu/command_buffer/common/gles2_cmd_utils.h" #include "gpu/command_buffer/common/mailbox.h" #include "gpu/command_buffer/common/raster_cmd_format.h" @@ -197,9 +196,6 @@ } TEST_P(RasterDecoderTest, YieldAfterEndRasterCHROMIUM) { -#if defined(OS_MACOSX) - EXPECT_CALL(*gl_, Flush()).RetiresOnSaturation(); -#endif GetDecoder()->SetUpForRasterCHROMIUMForTest(); cmds::EndRasterCHROMIUM end_raster_cmd; end_raster_cmd.Init();
diff --git a/infra/config/global/cr-buildbucket.cfg b/infra/config/global/cr-buildbucket.cfg index dd426976..937fcb85 100644 --- a/infra/config/global/cr-buildbucket.cfg +++ b/infra/config/global/cr-buildbucket.cfg
@@ -616,7 +616,7 @@ } buckets { - name: "luci.chromium.ci" + name: "ci" acl_sets: "ci" swarming { @@ -1155,6 +1155,12 @@ } builders { + name: "linux-autofill-captured-sites-rel" + mixins: "fyi-ci" + mixins: "linux" + } + + builders { name: "linux-blink-animation-use-time-delta" dimensions: "os:Ubuntu-14.04" mixins: "fyi-ci" @@ -1353,6 +1359,11 @@ # Mac bots. builders { + name: "mac-autofill-captured-sites-rel" + mixins: "fyi-ci" + mixins: "mac-ci" + } + builders { name: "mac-jumbo-rel" mixins: "mac-ci" dimensions: "cores:4" @@ -1541,6 +1552,11 @@ mixins: "memory-ci" } builders { + name: "win-autofill-captured-sites-rel" + mixins: "fyi-ci" + mixins: "win-ci" + } + builders { name: "win-jumbo-rel" mixins: "win-ci" } @@ -2789,7 +2805,7 @@ } buckets { - name: "luci.chromium.findit" + name: "findit" acls { role: SCHEDULER group: "findit-tryjob-access" @@ -2836,7 +2852,7 @@ # Findit will add appropriate dimensions and properties as needed based on # the waterfall builder being analyzed. # - # TODO(robertocn): Remove _variable trybot builders from luci.chromium.try + # TODO(robertocn): Remove _variable trybot builders from "try" bucket # after they have been configured to use this generic builder, as well as # the findit 'mixin'. builders { name: "findit_variable" } @@ -2853,7 +2869,7 @@ } buckets { - name: "luci.chromium.try" + name: "try" # NOTE: these ACLs should be kept in sync with those in the other # "master.tryserver.chromium.*" buckets. @@ -3410,7 +3426,7 @@ } buckets { - name: "luci.chromium.webrtc" + name: "webrtc" acl_sets: "ci" swarming { @@ -3461,7 +3477,7 @@ } buckets { - name: "luci.chromium.webrtc.fyi" + name: "webrtc.fyi" acl_sets: "ci" swarming {
diff --git a/ios/chrome/app/main_controller.mm b/ios/chrome/app/main_controller.mm index c8def7f..e2ac89f 100644 --- a/ios/chrome/app/main_controller.mm +++ b/ios/chrome/app/main_controller.mm
@@ -2155,10 +2155,15 @@ // is not invoked) and has undesired side-effect (cause all regular tabs // to reload, see http://crbug.com/821753 for details). - const BOOL disableWebUsageDuringRemoval = + BOOL disableWebUsageDuringRemoval = !browserState->IsOffTheRecord() && IsRemoveDataMaskSet(removeMask, BrowsingDataRemoveMask::REMOVE_SITE_DATA); + if (@available(iOS 12, *)) { + // TODO(crbug.com/632772): https://bugs.webkit.org/show_bug.cgi?id=149079 is + // fixed for iOS 12. Stop disabling web usage once iOS 11 is not supported. + disableWebUsageDuringRemoval = NO; + } ProceduralBlock removeBrowsingDataBlock = ^{ if (disableWebUsageDuringRemoval) { // Disables browsing and purges web views. @@ -2166,6 +2171,10 @@ DCHECK([NSThread isMainThread]); [self.mainBrowserCoordinator setActive:NO]; [self.incognitoBrowserCoordinator setActive:NO]; + } else { + // Show activity overlay so users know that clear browsing data is in + // progress. + [self.mainBVC showActivityOverlay]; } BrowsingDataRemoverFactory::GetForBrowserState(browserState) @@ -2173,6 +2182,14 @@ // Activates browsing and enables web views. // Must be called only on the main thread. DCHECK([NSThread isMainThread]); + if (!disableWebUsageDuringRemoval) { + // Force NTP to reset so most visited tiles are updated. + // TODO(crbug.com/906199): NewTabPageTabHelper should use + // an observer to listen to browsing data changes. + [self.mainBVC resetNTP]; + [self.otrBVC resetNTP]; + [self.mainBVC dismissActivityOverlay]; + } [self.mainBrowserCoordinator setActive:YES]; [self.incognitoBrowserCoordinator setActive:YES]; [self.currentBVC setPrimary:YES];
diff --git a/ios/chrome/browser/download/ar_quick_look_tab_helper.h b/ios/chrome/browser/download/ar_quick_look_tab_helper.h index 1bb0381..0363bf8 100644 --- a/ios/chrome/browser/download/ar_quick_look_tab_helper.h +++ b/ios/chrome/browser/download/ar_quick_look_tab_helper.h
@@ -60,14 +60,18 @@ public web::DownloadTaskObserver, public web::WebStateUserData<ARQuickLookTabHelper> { public: - ARQuickLookTabHelper(web::WebState* web_state, - id<ARQuickLookTabHelperDelegate> delegate); + ARQuickLookTabHelper(web::WebState* web_state); ~ARQuickLookTabHelper() override; // Creates TabHelper. |delegate| is not retained by this instance. |web_state| // must not be null. - static void CreateForWebState(web::WebState* web_state, - id<ARQuickLookTabHelperDelegate> delegate); + static void CreateForWebState(web::WebState* web_state); + + id<ARQuickLookTabHelperDelegate> delegate() { return delegate_; } + + void set_delegate(id<ARQuickLookTabHelperDelegate> delegate) { + delegate_ = delegate; + } // Downloads and previews the USDZ file given by |download_task|. Takes // ownership of |download_task|.
diff --git a/ios/chrome/browser/download/ar_quick_look_tab_helper.mm b/ios/chrome/browser/download/ar_quick_look_tab_helper.mm index 901e35a..a6b8a0c 100644 --- a/ios/chrome/browser/download/ar_quick_look_tab_helper.mm +++ b/ios/chrome/browser/download/ar_quick_look_tab_helper.mm
@@ -73,10 +73,8 @@ } // namespace -ARQuickLookTabHelper::ARQuickLookTabHelper( - web::WebState* web_state, - id<ARQuickLookTabHelperDelegate> delegate) - : web_state_(web_state), delegate_(delegate) { +ARQuickLookTabHelper::ARQuickLookTabHelper(web::WebState* web_state) + : web_state_(web_state) { DCHECK(web_state_); } @@ -86,14 +84,11 @@ } } -void ARQuickLookTabHelper::CreateForWebState( - web::WebState* web_state, - id<ARQuickLookTabHelperDelegate> delegate) { +void ARQuickLookTabHelper::CreateForWebState(web::WebState* web_state) { DCHECK(web_state); if (!FromWebState(web_state)) { - web_state->SetUserData( - UserDataKey(), - std::make_unique<ARQuickLookTabHelper>(web_state, delegate)); + web_state->SetUserData(UserDataKey(), + std::make_unique<ARQuickLookTabHelper>(web_state)); } }
diff --git a/ios/chrome/browser/download/ar_quick_look_tab_helper_unittest.mm b/ios/chrome/browser/download/ar_quick_look_tab_helper_unittest.mm index 2bafadd6..5332eb27 100644 --- a/ios/chrome/browser/download/ar_quick_look_tab_helper_unittest.mm +++ b/ios/chrome/browser/download/ar_quick_look_tab_helper_unittest.mm
@@ -44,7 +44,8 @@ protected: ARQuickLookTabHelperTest() : delegate_([[FakeARQuickLookTabHelperDelegate alloc] init]) { - ARQuickLookTabHelper::CreateForWebState(&web_state_, delegate_); + ARQuickLookTabHelper::CreateForWebState(&web_state_); + ARQuickLookTabHelper::FromWebState(&web_state_)->set_delegate(delegate_); } ARQuickLookTabHelper* tab_helper() {
diff --git a/ios/chrome/browser/download/browser_download_service_unittest.mm b/ios/chrome/browser/download/browser_download_service_unittest.mm index 59329ad..a9a69d7 100644 --- a/ios/chrome/browser/download/browser_download_service_unittest.mm +++ b/ios/chrome/browser/download/browser_download_service_unittest.mm
@@ -58,6 +58,33 @@ DISALLOW_COPY_AND_ASSIGN(StubTabHelper); }; +// Substitutes ARQuickLookTabHelper for testing. +class TestARQuickLookTabHelper : public ARQuickLookTabHelper { + public: + static void CreateForWebState(web::WebState* web_state) { + web_state->SetUserData( + ARQuickLookTabHelper::UserDataKey(), + base::WrapUnique(new TestARQuickLookTabHelper(web_state))); + } + + // Adds the given task to tasks() lists. + void Download(std::unique_ptr<web::DownloadTask> task) override { + tasks_.push_back(std::move(task)); + } + + // Tasks added via Download() call. + using DownloadTasks = std::vector<std::unique_ptr<web::DownloadTask>>; + const DownloadTasks& tasks() const { return tasks_; } + + private: + TestARQuickLookTabHelper(web::WebState* web_state) + : ARQuickLookTabHelper(web_state) {} + + DownloadTasks tasks_; + + DISALLOW_COPY_AND_ASSIGN(TestARQuickLookTabHelper); +}; + } // namespace // Test fixture for testing BrowserDownloadService class. @@ -68,7 +95,7 @@ scoped_feature_list_.InitAndEnableFeature(download::kUsdzPreview); StubTabHelper<PassKitTabHelper>::CreateForWebState(&web_state_); - StubTabHelper<ARQuickLookTabHelper>::CreateForWebState(&web_state_); + TestARQuickLookTabHelper::CreateForWebState(&web_state_); StubTabHelper<DownloadManagerTabHelper>::CreateForWebState(&web_state_); // BrowserDownloadServiceFactory sets its service as @@ -96,8 +123,8 @@ PassKitTabHelper::FromWebState(&web_state_)); } - StubTabHelper<ARQuickLookTabHelper>* ar_quick_look_tab_helper() { - return static_cast<StubTabHelper<ARQuickLookTabHelper>*>( + TestARQuickLookTabHelper* ar_quick_look_tab_helper() { + return static_cast<TestARQuickLookTabHelper*>( ARQuickLookTabHelper::FromWebState(&web_state_)); }
diff --git a/ios/chrome/browser/sessions/session_service_ios.mm b/ios/chrome/browser/sessions/session_service_ios.mm index 9e40233..3cd03f2 100644 --- a/ios/chrome/browser/sessions/session_service_ios.mm +++ b/ios/chrome/browser/sessions/session_service_ios.mm
@@ -16,7 +16,7 @@ #include "base/sequenced_task_runner.h" #include "base/strings/sys_string_conversions.h" #include "base/task/post_task.h" -#include "base/threading/thread_restrictions.h" +#include "base/threading/scoped_blocking_call.h" #import "ios/chrome/browser/sessions/session_ios.h" #import "ios/chrome/browser/sessions/session_window_ios.h" #import "ios/web/public/crw_navigation_item_storage.h" @@ -169,7 +169,8 @@ NSString* sessionPath = [[self class] sessionPathForDirectory:directory]; _taskRunner->PostTaskAndReply( FROM_HERE, base::BindOnce(^{ - base::AssertBlockingAllowedDeprecated(); + base::ScopedBlockingCall scoped_blocking_call( + base::BlockingType::MAY_BLOCK); NSFileManager* fileManager = [NSFileManager defaultManager]; if (![fileManager fileExistsAtPath:sessionPath]) return; @@ -220,7 +221,8 @@ - (void)performSaveSessionData:(NSData*)sessionData sessionPath:(NSString*)sessionPath { - base::AssertBlockingAllowedDeprecated(); + base::ScopedBlockingCall scoped_blocking_call( + base::BlockingType::MAY_BLOCK); NSFileManager* fileManager = [NSFileManager defaultManager]; NSString* directory = [sessionPath stringByDeletingLastPathComponent];
diff --git a/ios/chrome/browser/tabs/BUILD.gn b/ios/chrome/browser/tabs/BUILD.gn index c75639d8..70c13aa 100644 --- a/ios/chrome/browser/tabs/BUILD.gn +++ b/ios/chrome/browser/tabs/BUILD.gn
@@ -95,6 +95,7 @@ "//ios/chrome/browser/browser_state", "//ios/chrome/browser/content_settings", "//ios/chrome/browser/download", + "//ios/chrome/browser/download:features", "//ios/chrome/browser/favicon", "//ios/chrome/browser/find_in_page", "//ios/chrome/browser/geolocation:geolocation_internal",
diff --git a/ios/chrome/browser/tabs/tab_helper_util.mm b/ios/chrome/browser/tabs/tab_helper_util.mm index cdbdb4d..2ecffd9 100644 --- a/ios/chrome/browser/tabs/tab_helper_util.mm +++ b/ios/chrome/browser/tabs/tab_helper_util.mm
@@ -17,6 +17,8 @@ #import "ios/chrome/browser/autofill/autofill_tab_helper.h" #import "ios/chrome/browser/autofill/form_suggestion_tab_helper.h" #include "ios/chrome/browser/browser_state/chrome_browser_state.h" +#import "ios/chrome/browser/download/ar_quick_look_tab_helper.h" +#import "ios/chrome/browser/download/features.h" #include "ios/chrome/browser/favicon/favicon_service_factory.h" #import "ios/chrome/browser/find_in_page/find_tab_helper.h" #include "ios/chrome/browser/history/history_service_factory.h" @@ -131,6 +133,10 @@ ukm::InitializeSourceUrlRecorderForWebState(web_state); + if (download::IsUsdzPreviewEnabled()) { + ARQuickLookTabHelper::CreateForWebState(web_state); + } + // TODO(crbug.com/794115): pre-rendered WebState have lots of unnecessary // tab helpers for historical reasons. For the moment, AttachTabHelpers // allows to inhibit the creation of some of them. Once PreloadController
diff --git a/ios/chrome/browser/ui/browser_view_controller.h b/ios/chrome/browser/ui/browser_view_controller.h index 740d3584..b0a2b96 100644 --- a/ios/chrome/browser/ui/browser_view_controller.h +++ b/ios/chrome/browser/ui/browser_view_controller.h
@@ -139,6 +139,20 @@ // controller to the tab switcher. - (UIView<TabStripFoldAnimation>*)tabStripPlaceholderView; +// Shows the activity overlay to inform users and prevent users from +// interacting. This method should only be used for clear browsing data. +// TODO(crbug.com/913338): Remove after clear browsing data coordinator is +// created. +- (void)showActivityOverlay; + +// Dismisses the activity overlay if it was started. +- (void)dismissActivityOverlay; + +// Reset all New Tab Page coordinators to force them to reload their content. +// TODO(crbug.com/906199): NewTabPageTabHelper should use an observer to listen +// to browsing data changes. +- (void)resetNTP; + // Called before the instance is deallocated. - (void)shutdown;
diff --git a/ios/chrome/browser/ui/browser_view_controller.mm b/ios/chrome/browser/ui/browser_view_controller.mm index 047b967..8c6ff5d 100644 --- a/ios/chrome/browser/ui/browser_view_controller.mm +++ b/ios/chrome/browser/ui/browser_view_controller.mm
@@ -1005,6 +1005,19 @@ return _dialogPresenter; } +- (void)showActivityOverlay { + if (!self.activityOverlayCoordinator) { + self.activityOverlayCoordinator = + [[ActivityOverlayCoordinator alloc] initWithBaseViewController:self]; + [self.activityOverlayCoordinator start]; + } +} + +- (void)dismissActivityOverlay { + [self.activityOverlayCoordinator stop]; + self.activityOverlayCoordinator = nil; +} + - (KeyCommandsProvider*)keyCommandsProvider { if (!_keyCommandsProvider) { _keyCommandsProvider = [_dependencyFactory newKeyCommandsProvider]; @@ -1439,6 +1452,14 @@ return [self.tabStripCoordinator placeholderView]; } +- (void)resetNTP { + for (const auto& element : _ntpCoordinatorsForWebStates) + [element.second stop]; + [self loadViewIfNeeded]; + if (self.tabModel.currentTab) + [self displayTab:self.tabModel.currentTab]; +} + - (void)shutdown { DCHECK(!_isShutdown); _isShutdown = YES; @@ -4055,11 +4076,11 @@ } - (BOOL)canGoBack { - return self.tabModel.currentTab.canGoBack; + return self.currentWebState->GetNavigationManager()->CanGoBack(); } - (BOOL)canGoForward { - return self.tabModel.currentTab.canGoForward; + return self.currentWebState->GetNavigationManager()->CanGoForward(); } - (void)focusTabAtIndex:(NSUInteger)index { @@ -4426,11 +4447,11 @@ #pragma mark - BrowserCommands - (void)goBack { - [self.tabModel.currentTab goBack]; + self.currentWebState->GetNavigationManager()->GoBack(); } - (void)goForward { - [self.tabModel.currentTab goForward]; + self.currentWebState->GetNavigationManager()->GoForward(); } - (void)stopLoading { @@ -5259,7 +5280,7 @@ // neeeded. The current solution is to go back in history. This has the // advantage of keeping the current browsing session and give a good user // experience when the user comes back from incognito. - [self.tabModel.currentTab goBack]; + [self goBack]; if (url.is_valid()) { OpenNewTabCommand* command = [[OpenNewTabCommand alloc]
diff --git a/ios/chrome/browser/ui/download/ar_quick_look_coordinator.h b/ios/chrome/browser/ui/download/ar_quick_look_coordinator.h index 244aecb..dfc6e97 100644 --- a/ios/chrome/browser/ui/download/ar_quick_look_coordinator.h +++ b/ios/chrome/browser/ui/download/ar_quick_look_coordinator.h
@@ -5,7 +5,6 @@ #ifndef IOS_CHROME_BROWSER_UI_DOWNLOAD_AR_QUICK_LOOK_COORDINATOR_H_ #define IOS_CHROME_BROWSER_UI_DOWNLOAD_AR_QUICK_LOOK_COORDINATOR_H_ -#import "ios/chrome/browser/download/ar_quick_look_tab_helper_delegate.h" #import "ios/chrome/browser/ui/coordinators/chrome_coordinator.h" // The UMA IOSPresentQLPreviewController histogram name. @@ -28,9 +27,23 @@ kMaxValue = kAnotherViewControllerIsPresented, }; +class WebStateList; + // Presents QLPreviewController in order to display USDZ format 3D models. -@interface ARQuickLookCoordinator - : ChromeCoordinator <ARQuickLookTabHelperDelegate> +@interface ARQuickLookCoordinator : ChromeCoordinator + +// Creates a coordinator that uses a |viewController| a |browserState| and +// a |webStateList|. +- (instancetype)initWithBaseViewController:(UIViewController*)viewController + browserState: + (ios::ChromeBrowserState*)browserState + webStateList:(WebStateList*)webStateList; + +// Unavailable, use -initWithBaseViewController:browserState:webStateList:. +- (instancetype)initWithBaseViewController:(UIViewController*)viewController + browserState: + (ios::ChromeBrowserState*)browserState + NS_UNAVAILABLE; @end
diff --git a/ios/chrome/browser/ui/download/ar_quick_look_coordinator.mm b/ios/chrome/browser/ui/download/ar_quick_look_coordinator.mm index a8635b5..893b950 100644 --- a/ios/chrome/browser/ui/download/ar_quick_look_coordinator.mm +++ b/ios/chrome/browser/ui/download/ar_quick_look_coordinator.mm
@@ -6,8 +6,15 @@ #import <QuickLook/QuickLook.h> +#include <memory> + #include "base/logging.h" #include "base/metrics/histogram_macros.h" +#include "base/scoped_observer.h" +#import "ios/chrome/browser/download/ar_quick_look_tab_helper.h" +#import "ios/chrome/browser/download/ar_quick_look_tab_helper_delegate.h" +#import "ios/chrome/browser/web_state_list/web_state_list.h" +#import "ios/chrome/browser/web_state_list/web_state_list_observer_bridge.h" #if !defined(__has_feature) || !__has_feature(objc_arc) #error "This file requires ARC support." @@ -40,8 +47,21 @@ } // namespace -@interface ARQuickLookCoordinator () <QLPreviewControllerDataSource, - QLPreviewControllerDelegate> +@interface ARQuickLookCoordinator () <WebStateListObserving, + ARQuickLookTabHelperDelegate, + QLPreviewControllerDataSource, + QLPreviewControllerDelegate> { + // WebStateList observers. + std::unique_ptr<WebStateListObserverBridge> _webStateListObserverBridge; + std::unique_ptr<ScopedObserver<WebStateList, WebStateListObserver>> + _scopedWebStateListObserver; +} + +// The WebStateList being observed. +@property(nonatomic, assign) WebStateList* webStateList; + +// Whether the coordinator is started. +@property(nonatomic, assign) BOOL started; // The file URL pointing to the downloaded USDZ format file. @property(nonatomic, copy) NSURL* fileURL; @@ -53,18 +73,119 @@ @implementation ARQuickLookCoordinator -- (void)stop { - [self.viewController dismissViewControllerAnimated:YES completion:nil]; - self.viewController = nil; - self.fileURL = nil; +- (instancetype)initWithBaseViewController:(UIViewController*)viewController + browserState: + (ios::ChromeBrowserState*)browserState + webStateList:(WebStateList*)webStateList { + DCHECK(webStateList); + self = [super initWithBaseViewController:viewController + browserState:browserState]; + if (self) { + _webStateList = webStateList; + } + return self; } - (void)start { + if (self.started) + return; + + // Install delegates for each WebState in WebStateList. + for (int i = 0; i < self.webStateList->count(); i++) { + web::WebState* webState = self.webStateList->GetWebStateAt(i); + [self installDelegatesForWebState:webState]; + } + + [self addWebStateListObserver]; + self.started = YES; +} + +- (void)stop { + if (!self.started) + return; + + [self removeWebStateListObserver]; + + // Uninstall delegates for each WebState in WebStateList. + for (int i = 0; i < self.webStateList->count(); i++) { + web::WebState* webState = self.webStateList->GetWebStateAt(i); + [self uninstallDelegatesForWebState:webState]; + } + + [self.viewController dismissViewControllerAnimated:YES completion:nil]; + self.viewController = nil; + self.fileURL = nil; + self.started = NO; +} + +#pragma mark - Private + +// Adds observer for WebStateList. +- (void)addWebStateListObserver { + _webStateListObserverBridge = + std::make_unique<WebStateListObserverBridge>(self); + _scopedWebStateListObserver = + std::make_unique<ScopedObserver<WebStateList, WebStateListObserver>>( + _webStateListObserverBridge.get()); + _scopedWebStateListObserver->Add(self.webStateList); +} + +// Removes observer for WebStateList. +- (void)removeWebStateListObserver { + _scopedWebStateListObserver.reset(); + _webStateListObserverBridge.reset(); +} + +// Installs delegates for |webState|. +- (void)installDelegatesForWebState:(web::WebState*)webState { + if (ARQuickLookTabHelper::FromWebState(webState)) { + ARQuickLookTabHelper::FromWebState(webState)->set_delegate(self); + } +} + +// Uninstalls delegates for |webState|. +- (void)uninstallDelegatesForWebState:(web::WebState*)webState { + if (ARQuickLookTabHelper::FromWebState(webState)) { + ARQuickLookTabHelper::FromWebState(webState)->set_delegate(nil); + } +} + +#pragma mark - WebStateListObserving + +- (void)webStateList:(WebStateList*)webStateList + didInsertWebState:(web::WebState*)webState + atIndex:(int)index + activating:(BOOL)activating { + [self installDelegatesForWebState:webState]; +} + +- (void)webStateList:(WebStateList*)webStateList + didReplaceWebState:(web::WebState*)oldWebState + withWebState:(web::WebState*)newWebState + atIndex:(int)index { + [self uninstallDelegatesForWebState:oldWebState]; + [self installDelegatesForWebState:newWebState]; +} + +- (void)webStateList:(WebStateList*)webStateList + didDetachWebState:(web::WebState*)webState + atIndex:(int)index { + [self uninstallDelegatesForWebState:webState]; +} + +#pragma mark - ARQuickLookTabHelperDelegate + +- (void)ARQuickLookTabHelper:(ARQuickLookTabHelper*)tabHelper + didFinishDowloadingFileWithURL:(NSURL*)fileURL { + self.fileURL = fileURL; + UMA_HISTOGRAM_ENUMERATION( kIOSPresentQLPreviewControllerHistogram, - GetHistogramEnum(self.baseViewController, !!self.fileURL)); + GetHistogramEnum(self.baseViewController, self.fileURL)); - if (self.viewController || !self.fileURL) { + // QLPreviewController should not be presented if there is already a view + // controller presented by the base view controller or the file URL is nil. + if (self.baseViewController.presentedViewController || !self.fileURL) { return; } @@ -76,14 +197,6 @@ completion:nil]; } -#pragma mark - ARQuickLookTabHelperDelegate - -- (void)ARQuickLookTabHelper:(ARQuickLookTabHelper*)tabHelper - didFinishDowloadingFileWithURL:(NSURL*)fileURL { - self.fileURL = fileURL; - [self start]; -} - #pragma mark - QLPreviewControllerDataSource - (NSInteger)numberOfPreviewItemsInPreviewController: @@ -99,7 +212,8 @@ #pragma mark - QLPreviewControllerDelegate - (void)previewControllerDidDismiss:(QLPreviewController*)controller { - [self stop]; + self.viewController = nil; + self.fileURL = nil; } @end
diff --git a/ios/chrome/browser/ui/download/ar_quick_look_coordinator_unittest.mm b/ios/chrome/browser/ui/download/ar_quick_look_coordinator_unittest.mm index 1830c625..5e584b6 100644 --- a/ios/chrome/browser/ui/download/ar_quick_look_coordinator_unittest.mm +++ b/ios/chrome/browser/ui/download/ar_quick_look_coordinator_unittest.mm
@@ -6,15 +6,23 @@ #import <QuickLook/QuickLook.h> +#import <memory> + #include "base/base_paths.h" #include "base/files/file_path.h" #include "base/path_service.h" #include "base/strings/sys_string_conversions.h" #import "base/test/ios/wait_util.h" #include "base/test/metrics/histogram_tester.h" +#import "ios/chrome/browser/download/ar_quick_look_tab_helper.h" +#import "ios/chrome/browser/download/ar_quick_look_tab_helper_delegate.h" #include "ios/chrome/browser/download/download_test_util.h" #include "ios/chrome/browser/ui/util/ui_util.h" +#import "ios/chrome/browser/web_state_list/fake_web_state_list_delegate.h" +#import "ios/chrome/browser/web_state_list/web_state_list.h" +#import "ios/chrome/browser/web_state_list/web_state_opener.h" #import "ios/chrome/test/scoped_key_window.h" +#import "ios/web/public/test/fakes/test_web_state.h" #include "testing/gtest/include/gtest/gtest.h" #include "testing/platform_test.h" @@ -41,35 +49,86 @@ protected: ARQuickLookCoordinatorTest() : base_view_controller_([[UIViewController alloc] init]), + web_state_list_( + std::make_unique<WebStateList>(&web_state_list_delegate_)), coordinator_([[ARQuickLookCoordinator alloc] - initWithBaseViewController:base_view_controller_]) { + initWithBaseViewController:base_view_controller_ + browserState:nullptr + webStateList:web_state_list_.get()]) { [scoped_key_window_.Get() setRootViewController:base_view_controller_]; + + // The Coordinator should install itself as delegate for the existing + // ARQuickLookTabHelper instances once started. + auto web_state = std::make_unique<web::TestWebState>(); + auto* web_state_ptr = web_state.get(); + ARQuickLookTabHelper::CreateForWebState(web_state_ptr); + web_state_list_->InsertWebState(0, std::move(web_state), + WebStateList::INSERT_NO_FLAGS, + WebStateOpener()); + [coordinator_ start]; + } + + ~ARQuickLookCoordinatorTest() override { [coordinator_ stop]; } + + ARQuickLookTabHelper* tab_helper() { + return ARQuickLookTabHelper::FromWebState( + web_state_list_->GetWebStateAt(0)); } UIViewController* base_view_controller_; + FakeWebStateListDelegate web_state_list_delegate_; + std::unique_ptr<WebStateList> web_state_list_; ARQuickLookCoordinator* coordinator_; ScopedKeyWindow scoped_key_window_; base::HistogramTester histogram_tester_; }; +// Tests that the coordinator installs itself as a ARQuickLookTabHelper +// delegate when ARQuickLookTabHelper instances become available. +TEST_F(ARQuickLookCoordinatorTest, InstallDelegates) { + WebStateList web_state_list(&web_state_list_delegate_); + ARQuickLookCoordinator* coordinator = [[ARQuickLookCoordinator alloc] + initWithBaseViewController:base_view_controller_ + browserState:nullptr + webStateList:&web_state_list]; + [coordinator start]; + + // Coordinator should install itself as delegate for a new web state. + auto web_state2 = std::make_unique<web::TestWebState>(); + auto* web_state_ptr2 = web_state2.get(); + ARQuickLookTabHelper::CreateForWebState(web_state_ptr2); + EXPECT_FALSE(ARQuickLookTabHelper::FromWebState(web_state_ptr2)->delegate()); + web_state_list.InsertWebState(0, std::move(web_state2), + WebStateList::INSERT_NO_FLAGS, + WebStateOpener()); + EXPECT_TRUE(ARQuickLookTabHelper::FromWebState(web_state_ptr2)->delegate()); + + // Coordinator should install itself as delegate for a web state replacing an + // existing one. + auto web_state3 = std::make_unique<web::TestWebState>(); + auto* web_state_ptr3 = web_state3.get(); + ARQuickLookTabHelper::CreateForWebState(web_state_ptr3); + EXPECT_FALSE(ARQuickLookTabHelper::FromWebState(web_state_ptr3)->delegate()); + web_state_list.ReplaceWebStateAt(0, std::move(web_state3)); + EXPECT_TRUE(ARQuickLookTabHelper::FromWebState(web_state_ptr3)->delegate()); + + [coordinator stop]; +} + // Tests presenting a valid USDZ file. TEST_F(ARQuickLookCoordinatorTest, ValidUSDZFile) { base::FilePath path = GetTestFilePath(); NSURL* fileURL = [NSURL fileURLWithPath:base::SysUTF8ToNSString(path.value())]; - [coordinator_ ARQuickLookTabHelper:nil - didFinishDowloadingFileWithURL:fileURL]; + + [tab_helper()->delegate() ARQuickLookTabHelper:tab_helper() + didFinishDowloadingFileWithURL:fileURL]; EXPECT_TRUE(WaitUntilConditionOrTimeout(kWaitForUIElementTimeout, ^{ return [base_view_controller_.presentedViewController class] == [QLPreviewController class]; })); - [coordinator_ stop]; - EXPECT_TRUE(WaitUntilConditionOrTimeout(kWaitForUIElementTimeout, ^{ - return base_view_controller_.presentedViewController == nil; - })); - histogram_tester_.ExpectUniqueSample( kIOSPresentQLPreviewControllerHistogram, static_cast<base::HistogramBase::Sample>( @@ -79,7 +138,8 @@ // Tests attempting to present an invalid USDZ file. TEST_F(ARQuickLookCoordinatorTest, InvalidUSDZFile) { - [coordinator_ ARQuickLookTabHelper:nil didFinishDowloadingFileWithURL:nil]; + [tab_helper()->delegate() ARQuickLookTabHelper:tab_helper() + didFinishDowloadingFileWithURL:nil]; EXPECT_FALSE(WaitUntilConditionOrTimeout(kWaitForUIElementTimeout, ^{ return [base_view_controller_.presentedViewController class] == @@ -98,8 +158,8 @@ base::FilePath path = GetTestFilePath(); NSURL* fileURL = [NSURL fileURLWithPath:base::SysUTF8ToNSString(path.value())]; - [coordinator_ ARQuickLookTabHelper:nil - didFinishDowloadingFileWithURL:fileURL]; + [tab_helper()->delegate() ARQuickLookTabHelper:tab_helper() + didFinishDowloadingFileWithURL:fileURL]; EXPECT_TRUE(WaitUntilConditionOrTimeout(kWaitForUIElementTimeout, ^{ return [base_view_controller_.presentedViewController class] == @@ -116,8 +176,8 @@ UIViewController* presented_view_controller = base_view_controller_.presentedViewController; - [coordinator_ ARQuickLookTabHelper:nil - didFinishDowloadingFileWithURL:fileURL]; + [tab_helper()->delegate() ARQuickLookTabHelper:tab_helper() + didFinishDowloadingFileWithURL:fileURL]; // The attempt is ignored. EXPECT_EQ(presented_view_controller, @@ -128,11 +188,6 @@ static_cast<base::HistogramBase::Sample>( PresentQLPreviewController::kAnotherQLPreviewControllerIsPresented), 1); - - [coordinator_ stop]; - EXPECT_TRUE(WaitUntilConditionOrTimeout(kWaitForUIElementTimeout, ^{ - return base_view_controller_.presentedViewController == nil; - })); } // Tests presenting a valid USDZ file while a view controller is presented. @@ -152,8 +207,8 @@ base::FilePath path = GetTestFilePath(); NSURL* fileURL = [NSURL fileURLWithPath:base::SysUTF8ToNSString(path.value())]; - [coordinator_ ARQuickLookTabHelper:nil - didFinishDowloadingFileWithURL:fileURL]; + [tab_helper()->delegate() ARQuickLookTabHelper:tab_helper() + didFinishDowloadingFileWithURL:fileURL]; // The attempt is ignored. EXPECT_EQ(presented_view_controller,
diff --git a/ios/chrome/browser/ui/main/browser_coordinator.mm b/ios/chrome/browser/ui/main/browser_coordinator.mm index 0bfd6ab..14f9e80 100644 --- a/ios/chrome/browser/ui/main/browser_coordinator.mm +++ b/ios/chrome/browser/ui/main/browser_coordinator.mm
@@ -10,7 +10,6 @@ #import "ios/chrome/browser/app_launcher/app_launcher_abuse_detector.h" #import "ios/chrome/browser/app_launcher/app_launcher_tab_helper.h" #include "ios/chrome/browser/browser_state/chrome_browser_state.h" -#import "ios/chrome/browser/download/ar_quick_look_tab_helper.h" #import "ios/chrome/browser/download/features.h" #import "ios/chrome/browser/download/pass_kit_tab_helper.h" #import "ios/chrome/browser/store_kit/store_kit_coordinator.h" @@ -60,6 +59,9 @@ // Coordinator for UI related to launching external apps. @property(nonatomic, strong) AppLauncherCoordinator* appLauncherCoordinator; +// Presents a QLPreviewController in order to display USDZ format 3D models. +@property(nonatomic, strong) ARQuickLookCoordinator* ARQuickLookCoordinator; + // Coordinator in charge of the presenting autofill options above the // keyboard. @property(nonatomic, strong) @@ -68,9 +70,6 @@ // Coordinator for Page Info UI. @property(nonatomic, strong) PageInfoLegacyCoordinator* pageInfoCoordinator; -// Coordinator to present a QLPreviewController for AR models. -@property(nonatomic, strong) ARQuickLookCoordinator* ARQuickLookCoordinator; - // Coordinator for the PassKit UI presentation. @property(nonatomic, strong) PassKitCoordinator* passKitCoordinator; @@ -193,6 +192,14 @@ self.appLauncherCoordinator = [[AppLauncherCoordinator alloc] initWithBaseViewController:self.viewController]; + if (download::IsUsdzPreviewEnabled()) { + self.ARQuickLookCoordinator = [[ARQuickLookCoordinator alloc] + initWithBaseViewController:self.viewController + browserState:self.browserState + webStateList:self.tabModel.webStateList]; + [self.ARQuickLookCoordinator start]; + } + self.formInputAccessoryCoordinator = [[FormInputAccessoryCoordinator alloc] initWithBaseViewController:self.viewController browserState:self.browserState @@ -208,11 +215,6 @@ self.pageInfoCoordinator.presentationProvider = self.viewController; self.pageInfoCoordinator.tabModel = self.tabModel; - if (download::IsUsdzPreviewEnabled()) { - self.ARQuickLookCoordinator = [[ARQuickLookCoordinator alloc] - initWithBaseViewController:self.viewController]; - } - self.passKitCoordinator = [[PassKitCoordinator alloc] initWithBaseViewController:self.viewController]; @@ -242,6 +244,9 @@ // ChromeCoordinator, and does not have a |-stop| method. self.appLauncherCoordinator = nil; + [self.ARQuickLookCoordinator stop]; + self.ARQuickLookCoordinator = nil; + [self.formInputAccessoryCoordinator stop]; self.formInputAccessoryCoordinator = nil; @@ -420,11 +425,6 @@ webState, [[AppLauncherAbuseDetector alloc] init], self.appLauncherCoordinator); - if (download::IsUsdzPreviewEnabled()) { - ARQuickLookTabHelper::CreateForWebState(webState, - self.ARQuickLookCoordinator); - } - PassKitTabHelper::CreateForWebState(webState, self.passKitCoordinator); RepostFormTabHelper::CreateForWebState(webState, self);
diff --git a/ios/web/web_state/web_state_observer_inttest.mm b/ios/web/web_state/web_state_observer_inttest.mm index eab420f8..ed14852 100644 --- a/ios/web/web_state/web_state_observer_inttest.mm +++ b/ios/web/web_state/web_state_observer_inttest.mm
@@ -945,10 +945,6 @@ // Tests user-initiated hash change. TEST_P(WebStateObserverTest, UserInitiatedHashChangeNavigation) { - // TODO(crbug.com/851119): temporarily disable this failing test. - if (GetParam() == TEST_WK_BASED_NAVIGATION_MANAGER) { - return; - } const GURL url = test_server_->GetURL("/echoall"); // Perform new page navigation. @@ -990,6 +986,9 @@ *decider_, ShouldAllowRequest(_, RequestInfoMatch(hash_url_expected_request_info))) .WillOnce(Return(true)); + if (GetWebClient()->IsSlimNavigationManagerEnabled()) { + EXPECT_CALL(observer_, DidChangeBackForwardState(web_state())); + } EXPECT_CALL(observer_, DidStartNavigation(web_state(), _)) .WillOnce(VerifySameDocumentStartedContext( web_state(), hash_url, /*has_user_gesture=*/true, &context, &nav_id, @@ -1008,19 +1007,32 @@ // Perform same-document navigation by going back. // No ShouldAllowRequest callback for same-document back-forward navigations. + if (GetWebClient()->IsSlimNavigationManagerEnabled()) { + EXPECT_CALL(observer_, DidChangeBackForwardState(web_state())).Times(2); + } EXPECT_CALL(observer_, DidStartLoading(web_state())); + + bool has_user_gesture = true; + ui::PageTransition expected_transition = + ui::PageTransition::PAGE_TRANSITION_FORWARD_BACK; + if (GetWebClient()->IsSlimNavigationManagerEnabled()) { + // TODO(crbug.com/913052): propagate |has_user_gesture| on back/forward + // navigation in slim nav. + has_user_gesture = false; + // TODO(crbug.com/851119): back/forward navigation between hash-only changes + // should have the PAGE_TRANSITION_FORWARD_BACK qualifier. + expected_transition = ui::PageTransition::PAGE_TRANSITION_CLIENT_REDIRECT; + } EXPECT_CALL(observer_, DidStartNavigation(web_state(), _)) .WillOnce(VerifySameDocumentStartedContext( - web_state(), url, /*has_user_gesture=*/true, &context, &nav_id, - ui::PageTransition::PAGE_TRANSITION_FORWARD_BACK, - /*renderer_initiated=*/false)); + web_state(), url, has_user_gesture, &context, &nav_id, + expected_transition, /*renderer_initiated=*/false)); // No ShouldAllowResponse callbacks for same-document back-forward // navigations. EXPECT_CALL(observer_, DidFinishNavigation(web_state(), _)) .WillOnce(VerifySameDocumentFinishedContext( - web_state(), url, /*has_user_gesture=*/true, &context, &nav_id, - ui::PageTransition::PAGE_TRANSITION_FORWARD_BACK, - /*renderer_initiated=*/false)); + web_state(), url, has_user_gesture, &context, &nav_id, + expected_transition, /*renderer_initiated=*/false)); EXPECT_CALL(observer_, DidStopLoading(web_state())); EXPECT_CALL(observer_, PageLoaded(web_state(), PageLoadCompletionStatus::SUCCESS)); @@ -1887,11 +1899,6 @@ if (!GetWebClient()->IsSlimNavigationManagerEnabled()) return; - // TODO(crbug.com/851119): temporarily disable this failing test. - if (GetParam() == TEST_WK_BASED_NAVIGATION_MANAGER) { - return; - } - GURL url = test_server_->GetURL("/iframe_host.html"); // Callbacks due to loading of the main frame. @@ -1906,10 +1913,12 @@ EXPECT_CALL(*decider_, ShouldAllowResponse(_, /*for_main_frame=*/true)) .WillOnce(Return(true)); EXPECT_CALL(observer_, DidFinishNavigation(web_state(), _)); + EXPECT_CALL(observer_, TitleWasSet(web_state())); + // Callbacks due to initial loading of iframe. WebStatePolicyDecider::RequestInfo iframe_request_info( ui::PageTransition::PAGE_TRANSITION_CLIENT_REDIRECT, - /*target_main_frame=*/false, /*has_user_gesture=*/true); + /*target_main_frame=*/false, /*has_user_gesture=*/false); EXPECT_CALL(*decider_, ShouldAllowRequest(_, RequestInfoMatch(iframe_request_info))) .WillOnce(Return(true)); @@ -1923,37 +1932,47 @@ ASSERT_TRUE(test::WaitForPageToFinishLoading(web_state())); // Trigger different-document load in iframe. - EXPECT_CALL(*decider_, - ShouldAllowRequest(_, RequestInfoMatch(iframe_request_info))) + WebStatePolicyDecider::RequestInfo link_clicked_request_info( + ui::PageTransition::PAGE_TRANSITION_LINK, + /*target_main_frame=*/false, /*has_user_gesture=*/true); + EXPECT_CALL(*decider_, ShouldAllowRequest( + _, RequestInfoMatch(link_clicked_request_info))) .WillOnce(Return(true)); EXPECT_CALL(*decider_, ShouldAllowResponse(_, /*for_main_frame=*/false)) .WillOnce(Return(true)); EXPECT_CALL(observer_, DidChangeBackForwardState(web_state())); test::TapWebViewElementWithIdInIframe(web_state(), "normal-link"); - EXPECT_TRUE(WaitUntilConditionOrTimeout(kWaitForPageLoadTimeout, ^{ - return web_state()->GetNavigationManager()->CanGoBack(); + EXPECT_TRUE(WaitUntilConditionOrTimeout(kWaitForPageLoadTimeout, ^bool { + id URL = ExecuteJavaScript(@"window.frames[0].location.pathname;"); + return [@"/pony.html" isEqual:URL] == YES; })); + ASSERT_TRUE(web_state()->GetNavigationManager()->CanGoBack()); + ASSERT_FALSE(web_state()->GetNavigationManager()->CanGoForward()); id history_length = ExecuteJavaScript(@"history.length;"); ASSERT_NSEQ(@2, history_length); - EXPECT_FALSE(web_state()->GetNavigationManager()->CanGoForward()); // Go back to top. + WebStatePolicyDecider::RequestInfo forward_back_request_info( + ui::PageTransition::PAGE_TRANSITION_FORWARD_BACK, + /*target_main_frame=*/false, /*has_user_gesture=*/true); EXPECT_CALL(observer_, DidChangeBackForwardState(web_state())) .Times(2); // called once each for canGoBack and canGoForward - EXPECT_CALL(*decider_, - ShouldAllowRequest(_, RequestInfoMatch(iframe_request_info))) + EXPECT_CALL(*decider_, ShouldAllowRequest( + _, RequestInfoMatch(forward_back_request_info))) .WillOnce(Return(true)); EXPECT_CALL(*decider_, ShouldAllowResponse(_, /*for_main_frame=*/false)) .WillOnce(Return(true)); web_state()->GetNavigationManager()->GoBack(); - EXPECT_TRUE(WaitUntilConditionOrTimeout(kWaitForPageLoadTimeout, ^{ - return web_state()->GetNavigationManager()->CanGoForward(); + EXPECT_TRUE(WaitUntilConditionOrTimeout(kWaitForPageLoadTimeout, ^bool { + id URL = ExecuteJavaScript(@"window.frames[0].location.pathname;"); + return [@"/links.html" isEqual:URL] == YES; })); - EXPECT_FALSE(web_state()->GetNavigationManager()->CanGoBack()); + ASSERT_TRUE(web_state()->GetNavigationManager()->CanGoForward()); + ASSERT_FALSE(web_state()->GetNavigationManager()->CanGoBack()); // Trigger same-document load in iframe. - EXPECT_CALL(*decider_, - ShouldAllowRequest(_, RequestInfoMatch(iframe_request_info))) + EXPECT_CALL(*decider_, ShouldAllowRequest( + _, RequestInfoMatch(link_clicked_request_info))) .WillOnce(Return(true)); // ShouldAllowResponse() is not called for same-document navigation. EXPECT_CALL(observer_, DidChangeBackForwardState(web_state()))
diff --git a/media/formats/mp4/avc.cc b/media/formats/mp4/avc.cc index 31f4df2..5a0bb69 100644 --- a/media/formats/mp4/avc.cc +++ b/media/formats/mp4/avc.cc
@@ -134,10 +134,21 @@ RCHECK(AVC::ConvertConfigToAnnexB(avc_config, ¶m_sets)); if (subsamples && !subsamples->empty()) { - int subsample_index = FindSubsampleIndex(*buffer, subsamples, - &(*config_insert_point)); - // Update the size of the subsample where SPS/PPS is to be inserted. - (*subsamples)[subsample_index].clear_bytes += param_sets.size(); + if (config_insert_point != buffer->end()) { + int subsample_index = + FindSubsampleIndex(*buffer, subsamples, &(*config_insert_point)); + // Update the size of the subsample where SPS/PPS is to be inserted. + (*subsamples)[subsample_index].clear_bytes += param_sets.size(); + } else { + int subsample_index = (*subsamples).size() - 1; + if ((*subsamples)[subsample_index].cypher_bytes == 0) { + // Extend the last clear range to include the inserted data. + (*subsamples)[subsample_index].clear_bytes += param_sets.size(); + } else { + // Append a new subsample to cover the inserted data. + (*subsamples).emplace_back(param_sets.size(), 0); + } + } } buffer->insert(config_insert_point,
diff --git a/media/gpu/ipc/service/picture_buffer_manager.cc b/media/gpu/ipc/service/picture_buffer_manager.cc index 721b406..f7002d0 100644 --- a/media/gpu/ipc/service/picture_buffer_manager.cc +++ b/media/gpu/ipc/service/picture_buffer_manager.cc
@@ -135,8 +135,6 @@ bool DismissPictureBuffer(int32_t picture_buffer_id) override { DVLOG(2) << __func__ << "(" << picture_buffer_id << ")"; - DCHECK(gpu_task_runner_); - DCHECK(gpu_task_runner_->BelongsToCurrentThread()); base::AutoLock lock(picture_buffers_lock_); @@ -165,6 +163,20 @@ return true; } + void DismissAllPictureBuffers() override { + DVLOG(2) << __func__; + + std::vector<int32_t> assigned_picture_buffer_ids; + { + base::AutoLock lock(picture_buffers_lock_); + for (const auto& it : picture_buffers_) + assigned_picture_buffer_ids.push_back(it.first); + } + + for (int32_t picture_buffer_id : assigned_picture_buffer_ids) + DismissPictureBuffer(picture_buffer_id); + } + scoped_refptr<VideoFrame> CreateVideoFrame(Picture picture, base::TimeDelta timestamp, gfx::Rect visible_rect,
diff --git a/media/gpu/ipc/service/picture_buffer_manager.h b/media/gpu/ipc/service/picture_buffer_manager.h index 8bc93a5a..fe03190 100644 --- a/media/gpu/ipc/service/picture_buffer_manager.h +++ b/media/gpu/ipc/service/picture_buffer_manager.h
@@ -83,10 +83,11 @@ // // A picture buffer may be dismissed even if it is bound to a VideoFrame; its // backing textures will be maintained until the VideoFrame is destroyed. - // - // Must be called on the GPU thread. virtual bool DismissPictureBuffer(int32_t picture_buffer_id) = 0; + // Dismisses all picture buffers from the pool. + virtual void DismissAllPictureBuffers() = 0; + // Creates and returns a VideoFrame bound to a picture buffer, or nullptr on // failure. //
diff --git a/media/gpu/ipc/service/vda_video_decoder.cc b/media/gpu/ipc/service/vda_video_decoder.cc index b6b7ce5..e8824ab 100644 --- a/media/gpu/ipc/service/vda_video_decoder.cc +++ b/media/gpu/ipc/service/vda_video_decoder.cc
@@ -187,6 +187,10 @@ vda_ = nullptr; media_log_ = nullptr; + // Because |parent_weak_this_| was invalidated in Destroy(), picture buffer + // dismissals since then have been dropped on the floor. + picture_buffer_manager_->DismissAllPictureBuffers(); + delete this; } @@ -500,12 +504,26 @@ DCHECK(gpu_task_runner_->BelongsToCurrentThread()); DCHECK(vda_initialized_); - if (!picture_buffer_manager_->DismissPictureBuffer(picture_buffer_id)) { - parent_task_runner_->PostTask( - FROM_HERE, - base::BindOnce(&VdaVideoDecoder::EnterErrorState, parent_weak_this_)); + if (parent_task_runner_->BelongsToCurrentThread()) { + if (!parent_weak_this_) + return; + DismissPictureBufferOnParentThread(picture_buffer_id); return; } + + parent_task_runner_->PostTask( + FROM_HERE, + base::BindOnce(&VdaVideoDecoder::DismissPictureBufferOnParentThread, + parent_weak_this_, picture_buffer_id)); +} + +void VdaVideoDecoder::DismissPictureBufferOnParentThread( + int32_t picture_buffer_id) { + DVLOG(2) << __func__ << "(" << picture_buffer_id << ")"; + DCHECK(parent_task_runner_->BelongsToCurrentThread()); + + if (!picture_buffer_manager_->DismissPictureBuffer(picture_buffer_id)) + EnterErrorState(); } void VdaVideoDecoder::PictureReady(const Picture& picture) {
diff --git a/media/gpu/ipc/service/vda_video_decoder.h b/media/gpu/ipc/service/vda_video_decoder.h index 6eacc05..062d600 100644 --- a/media/gpu/ipc/service/vda_video_decoder.h +++ b/media/gpu/ipc/service/vda_video_decoder.h
@@ -142,6 +142,7 @@ void InitializeDone(bool status); void DecodeOnGpuThread(scoped_refptr<DecoderBuffer> buffer, int32_t bitstream_id); + void DismissPictureBufferOnParentThread(int32_t picture_buffer_id); void PictureReadyOnParentThread(Picture picture); void NotifyEndOfBitstreamBufferOnParentThread(int32_t bitstream_buffer_id); void NotifyFlushDoneOnParentThread();
diff --git a/media/gpu/ipc/service/vda_video_decoder_unittest.cc b/media/gpu/ipc/service/vda_video_decoder_unittest.cc index edb0e1ff..35a110d 100644 --- a/media/gpu/ipc/service/vda_video_decoder_unittest.cc +++ b/media/gpu/ipc/service/vda_video_decoder_unittest.cc
@@ -202,7 +202,7 @@ RunUntilIdle(); } - scoped_refptr<VideoFrame> PictureReady( + scoped_refptr<VideoFrame> PictureReady_NoRunUntilIdle( int32_t bitstream_buffer_id, int32_t picture_buffer_id, gfx::Rect visible_rect = gfx::Rect(1920, 1080)) { @@ -221,6 +221,15 @@ base::BindOnce(&VideoDecodeAccelerator::Client::PictureReady, base::Unretained(client_), picture)); } + return frame; + } + + scoped_refptr<VideoFrame> PictureReady( + int32_t bitstream_buffer_id, + int32_t picture_buffer_id, + gfx::Rect visible_rect = gfx::Rect(1920, 1080)) { + scoped_refptr<VideoFrame> frame = PictureReady_NoRunUntilIdle( + bitstream_buffer_id, picture_buffer_id, visible_rect); RunUntilIdle(); return frame; } @@ -414,7 +423,7 @@ NotifyEndOfBitstreamBuffer(bitstream_id); int32_t picture_buffer_id = ProvidePictureBuffer(); scoped_refptr<VideoFrame> frame = - PictureReady(bitstream_id, picture_buffer_id); + PictureReady_NoRunUntilIdle(bitstream_id, picture_buffer_id); DismissPictureBuffer(picture_buffer_id); // Dropping the frame still requires a SyncPoint to wait on.
diff --git a/net/OWNERS b/net/OWNERS index 5956672..08065b9 100644 --- a/net/OWNERS +++ b/net/OWNERS
@@ -2,6 +2,7 @@ asanka@chromium.org bnc@chromium.org davidben@chromium.org +ericorth@chromium.org eroman@chromium.org jkarlin@chromium.org mattm@chromium.org
diff --git a/net/base/OWNERS b/net/base/OWNERS index bfe3f50..db674072 100644 --- a/net/base/OWNERS +++ b/net/base/OWNERS
@@ -1,4 +1,4 @@ -per-file *_fuchsia.*=file://build/fuchsia/OWNERS +per-file *_fuchsia*=file://build/fuchsia/OWNERS # For security review of MIME sniffing to avoid introducing security bugs per-file mime_sniffer*=set noparent
diff --git a/net/base/features.cc b/net/base/features.cc index f563ef7..71fdd851 100644 --- a/net/base/features.cc +++ b/net/base/features.cc
@@ -22,5 +22,8 @@ const base::Feature kEnforceTLS13Downgrade{"EnforceTLS13Downgrade", base::FEATURE_DISABLED_BY_DEFAULT}; +const base::Feature kSplitCacheByTopFrameOrigin{ + "SplitCacheByTopFrameOrigin", base::FEATURE_DISABLED_BY_DEFAULT}; + } // namespace features } // namespace net
diff --git a/net/base/features.h b/net/base/features.h index cdf4b4c..311f609 100644 --- a/net/base/features.h +++ b/net/base/features.h
@@ -24,6 +24,9 @@ // with some buggy non-compliant TLS-terminating proxies. NET_EXPORT extern const base::Feature kEnforceTLS13Downgrade; +// Splits cache entries by the request's top frame's origin if one is available. +NET_EXPORT extern const base::Feature kSplitCacheByTopFrameOrigin; + } // namespace features } // namespace net
diff --git a/net/base/network_change_notifier_fuchsia.cc b/net/base/network_change_notifier_fuchsia.cc index e4ef84b..6698ec6 100644 --- a/net/base/network_change_notifier_fuchsia.cc +++ b/net/base/network_change_notifier_fuchsia.cc
@@ -94,8 +94,8 @@ auto default_route_interface = std::find_if( route_table->begin(), route_table->end(), [](const fuchsia::netstack::RouteTableEntry& rt) { - return MaskPrefixLength(internal::NetAddressToIPAddress(rt.netmask)) == - 0; + return MaskPrefixLength( + internal::FuchsiaIpAddressToIPAddress(rt.netmask)) == 0; }); // Find the default interface in the NetInterface list.
diff --git a/net/base/network_change_notifier_fuchsia_unittest.cc b/net/base/network_change_notifier_fuchsia_unittest.cc index 1ecfc2a..0c4158c7 100644 --- a/net/base/network_change_notifier_fuchsia_unittest.cc +++ b/net/base/network_change_notifier_fuchsia_unittest.cc
@@ -20,35 +20,31 @@ const int kDefaultNic = 1; const int kSecondaryNic = kDefaultNic + 1; -fuchsia::netstack::NetAddress CreateIPv6Address(std::vector<uint8_t> addr) { - fuchsia::netstack::NetAddress output; - output.family = fuchsia::netstack::NetAddressFamily::IPV6; - output.ipv6 = fuchsia::netstack::Ipv6Address::New(); +fuchsia::net::IpAddress CreateIPv6Address(std::vector<uint8_t> addr) { + fuchsia::net::IpAddress output; for (size_t i = 0; i < addr.size(); ++i) { - output.ipv6->addr[i] = addr[i]; + output.ipv6().addr[i] = addr[i]; } return output; } -fuchsia::netstack::Subnet CreateSubnet(const std::vector<uint8_t>& addr, - uint8_t prefix) { - fuchsia::netstack::Subnet output; +fuchsia::net::Subnet CreateSubnet(const std::vector<uint8_t>& addr, + uint8_t prefix) { + fuchsia::net::Subnet output; output.addr = CreateIPv6Address(addr); output.prefix_len = prefix; return output; } -fuchsia::netstack::NetAddress CreateIPv4Address(uint8_t a0, - uint8_t a1, - uint8_t a2, - uint8_t a3) { - fuchsia::netstack::NetAddress output; - output.family = fuchsia::netstack::NetAddressFamily::IPV4; - output.ipv4 = std::make_unique<fuchsia::netstack::Ipv4Address>(); - output.ipv4->addr[0] = a0; - output.ipv4->addr[1] = a1; - output.ipv4->addr[2] = a2; - output.ipv4->addr[3] = a3; +fuchsia::net::IpAddress CreateIPv4Address(uint8_t a0, + uint8_t a1, + uint8_t a2, + uint8_t a3) { + fuchsia::net::IpAddress output; + output.ipv4().addr[0] = a0; + output.ipv4().addr[1] = a1; + output.ipv4().addr[2] = a2; + output.ipv4().addr[3] = a3; return output; } @@ -59,8 +55,12 @@ if (is_default) { output.netmask = CreateIPv4Address(0, 0, 0, 0); + output.destination = CreateIPv4Address(192, 168, 42, 0); + output.gateway = CreateIPv4Address(192, 168, 42, 1); } else { output.netmask = CreateIPv4Address(255, 255, 255, 0); + output.destination = CreateIPv4Address(192, 168, 43, 0); + output.gateway = CreateIPv4Address(192, 168, 43, 1); } return output; @@ -70,20 +70,21 @@ uint32_t id, uint32_t flags, uint32_t features, - fuchsia::netstack::NetAddress address, - fuchsia::netstack::NetAddress netmask, - std::vector<fuchsia::netstack::Subnet> ipv6) { + fuchsia::net::IpAddress address, + fuchsia::net::IpAddress netmask, + std::vector<fuchsia::net::Subnet> ipv6) { fuchsia::netstack::NetInterface output; output.name = "foo"; output.id = id; output.flags = flags; output.features = features; - address.Clone(&output.addr); - netmask.Clone(&output.netmask); + output.addr = std::move(address); + output.netmask = std::move(netmask); output.hwaddr = fidl::VectorPtr<uint8_t>::New(0); - output.ipv6addrs = - fidl::VectorPtr<fuchsia::netstack::Subnet>::New(ipv6.size()); + output.addr.Clone(&output.broadaddr); + + output.ipv6addrs = fidl::VectorPtr<fuchsia::net::Subnet>::New(0); for (auto& x : ipv6) { output.ipv6addrs.push_back(std::move(x)); } @@ -128,10 +129,8 @@ void GetRouteTable(GetRouteTableCallback callback) override { fidl::VectorPtr<fuchsia::netstack::RouteTableEntry> table = fidl::VectorPtr<fuchsia::netstack::RouteTableEntry>::New(2); - (*table)[0].nicid = kDefaultNic; - (*table)[0].netmask = CreateIPv4Address(0, 0, 0, 0); - (*table)[1].nicid = kSecondaryNic; - (*table)[1].netmask = CreateIPv4Address(255, 255, 255, 0); + (*table)[0] = CreateRouteTableEntry(kDefaultNic, true); + (*table)[1] = CreateRouteTableEntry(kSecondaryNic, true); callback(std::move(table)); } @@ -147,12 +146,12 @@ void GetAggregateStats(GetAggregateStatsCallback callback) override {} void SetInterfaceStatus(uint32_t nicid, bool enabled) override {} void SetInterfaceAddress(uint32_t nicid, - fuchsia::netstack::NetAddress addr, + fuchsia::net::IpAddress addr, uint8_t prefixLen, SetInterfaceAddressCallback callback) override {} void RemoveInterfaceAddress( uint32_t nicid, - fuchsia::netstack::NetAddress addr, + fuchsia::net::IpAddress addr, uint8_t prefixLen, RemoveInterfaceAddressCallback callback) override {} void SetDhcpClientStatus(uint32_t nicid, @@ -161,7 +160,7 @@ void BridgeInterfaces(::fidl::VectorPtr<uint32_t> nicids, BridgeInterfacesCallback callback) override {} void SetNameServers( - ::fidl::VectorPtr<::fuchsia::netstack::NetAddress> servers) override {} + ::fidl::VectorPtr<::fuchsia::net::IpAddress> servers) override {} void AddEthernetDevice( ::fidl::StringPtr topological_path, fuchsia::netstack::InterfaceConfig interfaceConfig, @@ -284,7 +283,7 @@ } TEST_F(NetworkChangeNotifierFuchsiaTest, MultiV6IPNoChange) { - std::vector<fuchsia::netstack::Subnet> addresses; + std::vector<fuchsia::net::Subnet> addresses; addresses.push_back(CreateSubnet({0xfe, 0x80, 0x01}, 2)); netstack_.PushInterface(CreateNetInterface( kDefaultNic, fuchsia::netstack::NetInterfaceFlagUp, 0, @@ -342,7 +341,7 @@ } TEST_F(NetworkChangeNotifierFuchsiaTest, MultiV6IPChanged) { - std::vector<fuchsia::netstack::Subnet> addresses; + std::vector<fuchsia::net::Subnet> addresses; addresses.push_back(CreateSubnet({0xfe, 0x80, 0x01}, 2)); netstack_.PushInterface(CreateNetInterface( kDefaultNic, fuchsia::netstack::NetInterfaceFlagUp, 0, @@ -376,7 +375,7 @@ OnNetworkChanged(NetworkChangeNotifier::CONNECTION_NONE)); EXPECT_CALL(observer_, OnNetworkChanged(NetworkChangeNotifier::CONNECTION_UNKNOWN)); - std::vector<fuchsia::netstack::Subnet> addresses; + std::vector<fuchsia::net::Subnet> addresses; addresses.push_back(CreateSubnet({0xfe, 0x80, 0x01}, 2)); netstack_.PushInterface(CreateNetInterface( kDefaultNic, fuchsia::netstack::NetInterfaceFlagUp, 0,
diff --git a/net/base/network_interfaces_fuchsia.cc b/net/base/network_interfaces_fuchsia.cc index de08376..52d4c4e 100644 --- a/net/base/network_interfaces_fuchsia.cc +++ b/net/base/network_interfaces_fuchsia.cc
@@ -4,6 +4,7 @@ #include "net/base/network_interfaces_fuchsia.h" +#include <fuchsia/net/cpp/fidl.h> #include <fuchsia/netstack/cpp/fidl.h> #include <zircon/ethernet/cpp/fidl.h> @@ -47,12 +48,13 @@ IPAddress address; uint8_t prefix_length; if (address_index == 0) { - address = NetAddressToIPAddress(interface.addr); - prefix_length = MaskPrefixLength(NetAddressToIPAddress(interface.netmask)); + address = FuchsiaIpAddressToIPAddress(interface.addr); + prefix_length = + MaskPrefixLength(FuchsiaIpAddressToIPAddress(interface.netmask)); } else { CHECK_LE(address_index, interface.ipv6addrs->size()); - address = - NetAddressToIPAddress(interface.ipv6addrs->at(address_index - 1).addr); + address = FuchsiaIpAddressToIPAddress( + interface.ipv6addrs->at(address_index - 1).addr); prefix_length = interface.ipv6addrs->at(address_index - 1).prefix_len; } @@ -63,12 +65,12 @@ } // namespace -IPAddress NetAddressToIPAddress(const fuchsia::netstack::NetAddress& addr) { - if (addr.ipv4) { - return IPAddress(addr.ipv4->addr.data(), addr.ipv4->addr.count()); +IPAddress FuchsiaIpAddressToIPAddress(const fuchsia::net::IpAddress& addr) { + if (addr.is_ipv4()) { + return IPAddress(addr.ipv4().addr.data(), addr.ipv4().addr.count()); } - if (addr.ipv6) { - return IPAddress(addr.ipv6->addr.data(), addr.ipv6->addr.count()); + if (addr.is_ipv6()) { + return IPAddress(addr.ipv6().addr.data(), addr.ipv6().addr.count()); } return IPAddress(); }
diff --git a/net/base/network_interfaces_fuchsia.h b/net/base/network_interfaces_fuchsia.h index 7883408b..06dbd95 100644 --- a/net/base/network_interfaces_fuchsia.h +++ b/net/base/network_interfaces_fuchsia.h
@@ -8,8 +8,10 @@ #include <vector> namespace fuchsia { +namespace net { +class IpAddress; +} namespace netstack { -class NetAddress; class NetInterface; } // namespace netstack } // namespace fuchsia @@ -29,7 +31,7 @@ const fuchsia::netstack::NetInterface& iface_in); // Converts a Fuchsia IPv4/IPv6 address to a Chromium IPAddress. -IPAddress NetAddressToIPAddress(const fuchsia::netstack::NetAddress& addr); +IPAddress FuchsiaIpAddressToIPAddress(const fuchsia::net::IpAddress& addr); } // namespace internal } // namespace net
diff --git a/net/dns/OWNERS b/net/dns/OWNERS index 52b51f2..d3da14c 100644 --- a/net/dns/OWNERS +++ b/net/dns/OWNERS
@@ -1,4 +1,3 @@ -per-file *_struct_traits*.*=set noparent -per-file *_struct_traits*.*=file://ipc/SECURITY_OWNERS +ericorth@chromium.org # COMPONENT: Internals>Network>DNS
diff --git a/net/http/http_cache.cc b/net/http/http_cache.cc index 2f285fef1..f277618 100644 --- a/net/http/http_cache.cc +++ b/net/http/http_cache.cc
@@ -21,6 +21,7 @@ #include "base/metrics/histogram_macros.h" #include "base/pickle.h" #include "base/single_thread_task_runner.h" +#include "base/strings/strcat.h" #include "base/strings/string_number_conversions.h" #include "base/strings/string_util.h" #include "base/strings/stringprintf.h" @@ -31,6 +32,7 @@ #include "base/trace_event/memory_usage_estimator.h" #include "base/trace_event/process_memory_dump.h" #include "net/base/cache_type.h" +#include "net/base/features.h" #include "net/base/io_buffer.h" #include "net/base/load_flags.h" #include "net/base/net_errors.h" @@ -580,7 +582,21 @@ // Generate a key that can be used inside the cache. std::string HttpCache::GenerateCacheKey(const HttpRequestInfo* request) { // Strip out the reference, username, and password sections of the URL. - std::string url = HttpUtil::SpecForRequest(request->url); + std::string url; + + // If we're splitting the cache by top frame origin, then prefix the key with + // the origin. + if (request->top_frame_origin && + base::FeatureList::IsEnabled(features::kSplitCacheByTopFrameOrigin)) { + // Prepend the key with "_dk_" to mark it as double keyed (and makes it an + // invalid url so that it doesn't get confused with a single-keyed + // entry). Separate the origin and url with invalid whitespace and control + // characters. + url = base::StrCat({"_dk_", request->top_frame_origin->Serialize(), " \n", + HttpUtil::SpecForRequest(request->url)}); + } else { + url = HttpUtil::SpecForRequest(request->url); + } DCHECK_NE(DISABLE, mode_); // No valid URL can begin with numerals, so we should not have to worry @@ -591,6 +607,7 @@ base::StringPrintf("%" PRId64 "/", request->upload_data_stream->identifier())); } + return url; }
diff --git a/net/http/http_cache_unittest.cc b/net/http/http_cache_unittest.cc index eed5c754..4102de8 100644 --- a/net/http/http_cache_unittest.cc +++ b/net/http/http_cache_unittest.cc
@@ -9405,6 +9405,100 @@ RemoveMockTransaction(&mock_network_response); } +TEST_F(HttpCacheTest, SplitCache) { + base::test::ScopedFeatureList feature_list; + feature_list.InitAndEnableFeature(net::features::kSplitCacheByTopFrameOrigin); + + MockHttpCache cache; + HttpResponseInfo response; + + url::Origin origin_a = url::Origin::Create(GURL("http://a.com")); + url::Origin origin_b = url::Origin::Create(GURL("http://b.com")); + + // A request without a top frame origin is cached normally. + MockHttpRequest trans_info = MockHttpRequest(kSimpleGET_Transaction); + RunTransactionTestWithRequest(cache.http_cache(), kSimpleGET_Transaction, + trans_info, &response); + EXPECT_FALSE(response.was_cached); + + RunTransactionTestWithRequest(cache.http_cache(), kSimpleGET_Transaction, + trans_info, &response); + EXPECT_TRUE(response.was_cached); + + // Now request with a.com as the top frame origin. It shouldn't be cached + // since the cached resource has a different top frame origin. + trans_info.top_frame_origin = origin_a; + RunTransactionTestWithRequest(cache.http_cache(), kSimpleGET_Transaction, + trans_info, &response); + EXPECT_FALSE(response.was_cached); + + // The second request should be cached. + RunTransactionTestWithRequest(cache.http_cache(), kSimpleGET_Transaction, + trans_info, &response); + EXPECT_TRUE(response.was_cached); + + // Now request with b.com as the top frame origin. It shouldn't be cached. + trans_info.top_frame_origin = origin_b; + RunTransactionTestWithRequest(cache.http_cache(), kSimpleGET_Transaction, + trans_info, &response); + EXPECT_FALSE(response.was_cached); + + // The second request should be cached. + RunTransactionTestWithRequest(cache.http_cache(), kSimpleGET_Transaction, + trans_info, &response); + EXPECT_TRUE(response.was_cached); + + // a.com should still be cached. + trans_info.top_frame_origin = origin_a; + RunTransactionTestWithRequest(cache.http_cache(), kSimpleGET_Transaction, + trans_info, &response); + EXPECT_TRUE(response.was_cached); + + // Verify that a post transaction with a data stream uses a separate key. + const int64_t kUploadId = 1; // Just a dummy value. + + std::vector<std::unique_ptr<UploadElementReader>> element_readers; + element_readers.push_back( + std::make_unique<UploadBytesElementReader>("hello", 5)); + ElementsUploadDataStream upload_data_stream(std::move(element_readers), + kUploadId); + + MockHttpRequest post_info = MockHttpRequest(kSimplePOST_Transaction); + post_info.top_frame_origin = origin_a; + post_info.upload_data_stream = &upload_data_stream; + + RunTransactionTestWithRequest(cache.http_cache(), kSimplePOST_Transaction, + post_info, &response); + EXPECT_FALSE(response.was_cached); +} + +TEST_F(HttpCacheTest, NonSplitCache) { + base::test::ScopedFeatureList feature_list; + feature_list.InitAndDisableFeature( + net::features::kSplitCacheByTopFrameOrigin); + + MockHttpCache cache; + HttpResponseInfo response; + + // A request without a top frame is cached normally. + MockHttpRequest trans_info = MockHttpRequest(kSimpleGET_Transaction); + RunTransactionTestWithRequest(cache.http_cache(), kSimpleGET_Transaction, + trans_info, &response); + EXPECT_FALSE(response.was_cached); + + // The second request comes from cache. + RunTransactionTestWithRequest(cache.http_cache(), kSimpleGET_Transaction, + trans_info, &response); + EXPECT_TRUE(response.was_cached); + + // Now request with a.com as the top frame origin. It should use the same + // cached object. + trans_info.top_frame_origin = url::Origin::Create(GURL("http://a.com/")); + RunTransactionTestWithRequest(cache.http_cache(), kSimpleGET_Transaction, + trans_info, &response); + EXPECT_TRUE(response.was_cached); +} + // Tests that we can write metadata to an entry. TEST_F(HttpCacheTest, WriteMetadata_OK) { base::test::ScopedFeatureList feature_list;
diff --git a/net/http/http_request_info.h b/net/http/http_request_info.h index ab26109..3ebd61b 100644 --- a/net/http/http_request_info.h +++ b/net/http/http_request_info.h
@@ -7,12 +7,14 @@ #include <string> +#include "base/optional.h" #include "net/base/net_export.h" #include "net/base/privacy_mode.h" #include "net/http/http_request_headers.h" #include "net/socket/socket_tag.h" #include "net/traffic_annotation/network_traffic_annotation.h" #include "url/gurl.h" +#include "url/origin.h" namespace net { @@ -29,6 +31,9 @@ // The method to use (GET, POST, etc.). std::string method; + // The URL of the top frame of the request (if applicable) + base::Optional<url::Origin> top_frame_origin; + // Any extra request headers (including User-Agent). HttpRequestHeaders extra_headers;
diff --git a/net/http/mock_http_cache.cc b/net/http/mock_http_cache.cc index c9f416cf..bf17e11 100644 --- a/net/http/mock_http_cache.cc +++ b/net/http/mock_http_cache.cc
@@ -35,21 +35,28 @@ int g_test_mode = 0; int GetTestModeForEntry(const std::string& key) { + std::string url = key; + // 'key' is prefixed with an identifier if it corresponds to a cached POST. // Skip past that to locate the actual URL. // // TODO(darin): It breaks the abstraction a bit that we assume 'key' is an // URL corresponding to a registered MockTransaction. It would be good to // have another way to access the test_mode. - GURL url; if (isdigit(key[0])) { size_t slash = key.find('/'); DCHECK(slash != std::string::npos); - url = GURL(key.substr(slash + 1)); - } else { - url = GURL(key); + url = url.substr(slash + 1); } - const MockTransaction* t = FindMockTransaction(url); + + // If we split the cache by top frame origin, then the origin is prepended to + // the key. Skip to the second url in the key. + if (base::StartsWith(url, "_dk_", base::CompareCase::SENSITIVE)) { + auto const pos = url.find("\nhttp"); + url = url.substr(pos + 1); + } + + const MockTransaction* t = FindMockTransaction(GURL(url)); DCHECK(t); return t->test_mode; }
diff --git a/net/quic/quic_flags_list.h b/net/quic/quic_flags_list.h index 8e36533..621c9a9 100644 --- a/net/quic/quic_flags_list.h +++ b/net/quic/quic_flags_list.h
@@ -313,3 +313,9 @@ // If true, disables key share caching for QUIC key exchange QUIC_FLAG(bool, FLAGS_quic_restart_flag_quic_no_ephemeral_key_source, true) + +// If true, QuicDispatcher will not assume all blocked writers share the same +// opinion about whether their packet writers are blocked. +QUIC_FLAG(bool, + FLAGS_quic_restart_flag_quic_check_blocked_writer_for_blockage, + false)
diff --git a/net/third_party/quic/core/quic_blocked_writer_interface.h b/net/third_party/quic/core/quic_blocked_writer_interface.h index ce02b0ae..335a3dd 100644 --- a/net/third_party/quic/core/quic_blocked_writer_interface.h +++ b/net/third_party/quic/core/quic_blocked_writer_interface.h
@@ -20,6 +20,8 @@ // Called by the PacketWriter when the underlying socket becomes writable // so that the BlockedWriter can go ahead and try writing. virtual void OnBlockedWriterCanWrite() = 0; + + virtual bool IsWriterBlocked() const = 0; }; } // namespace quic
diff --git a/net/third_party/quic/core/quic_connection.cc b/net/third_party/quic/core/quic_connection.cc index efcf3eb2..839140b 100644 --- a/net/third_party/quic/core/quic_connection.cc +++ b/net/third_party/quic/core/quic_connection.cc
@@ -1788,6 +1788,10 @@ } void QuicConnection::OnBlockedWriterCanWrite() { + if (GetQuicRestartFlag(quic_check_blocked_writer_for_blockage)) { + QUIC_RESTART_FLAG_COUNT_N(quic_check_blocked_writer_for_blockage, 3, 4); + writer_->SetWritable(); + } OnCanWrite(); }
diff --git a/net/third_party/quic/core/quic_connection.h b/net/third_party/quic/core/quic_connection.h index abed93d..98417f4 100644 --- a/net/third_party/quic/core/quic_connection.h +++ b/net/third_party/quic/core/quic_connection.h
@@ -418,6 +418,10 @@ // writes to happen. void OnBlockedWriterCanWrite() override; + bool IsWriterBlocked() const override { + return writer_ != nullptr && writer_->IsWriteBlocked(); + } + // Called when the caller thinks it's worth a try to write. virtual void OnCanWrite();
diff --git a/net/third_party/quic/core/quic_dispatcher.cc b/net/third_party/quic/core/quic_dispatcher.cc index e60e140..72d1bcc 100644 --- a/net/third_party/quic/core/quic_dispatcher.cc +++ b/net/third_party/quic/core/quic_dispatcher.cc
@@ -283,7 +283,9 @@ Perspective::IS_SERVER), last_error_(QUIC_NO_ERROR), new_sessions_allowed_per_event_loop_(0u), - accept_new_connections_(true) { + accept_new_connections_(true), + check_blocked_writer_for_blockage_( + GetQuicRestartFlag(quic_check_blocked_writer_for_blockage)) { framer_.set_visitor(this); } @@ -574,6 +576,33 @@ // The socket is now writable. writer_->SetWritable(); + if (check_blocked_writer_for_blockage_) { + QUIC_RESTART_FLAG_COUNT_N(quic_check_blocked_writer_for_blockage, 2, 4); + // Move every blocked writer in |write_blocked_list_| to a temporary list. + const size_t num_blocked_writers_before = write_blocked_list_.size(); + WriteBlockedList temp_list; + temp_list.swap(write_blocked_list_); + DCHECK(write_blocked_list_.empty()); + + // Give each blocked writer a chance to write what they indended to write. + // If they are blocked again, they will call |OnWriteBlocked| to add + // themselves back into |write_blocked_list_|. + while (!temp_list.empty()) { + QuicBlockedWriterInterface* blocked_writer = temp_list.begin()->first; + temp_list.erase(temp_list.begin()); + blocked_writer->OnBlockedWriterCanWrite(); + } + const size_t num_blocked_writers_after = write_blocked_list_.size(); + if (num_blocked_writers_after != 0) { + if (num_blocked_writers_before == num_blocked_writers_after) { + QUIC_CODE_COUNT(quic_zero_progress_on_can_write); + } else { + QUIC_CODE_COUNT(quic_blocked_again_on_can_write); + } + } + return; + } + // Give all the blocked writers one chance to write, until we're blocked again // or there's no work left. while (!write_blocked_list_.empty() && !writer_->IsWriteBlocked()) { @@ -635,12 +664,25 @@ void QuicDispatcher::OnWriteBlocked( QuicBlockedWriterInterface* blocked_writer) { - if (!ShouldAddToBlockedList()) { - QUIC_BUG - << "Tried to add writer into blocked list when it shouldn't be added"; - // Return without adding the connection to the blocked list, to avoid - // infinite loops in OnCanWrite. - return; + if (check_blocked_writer_for_blockage_) { + QUIC_RESTART_FLAG_COUNT_N(quic_check_blocked_writer_for_blockage, 1, 4); + if (!blocked_writer->IsWriterBlocked()) { + // It is a programming error if this ever happens. When we are sure it is + // not happening, replace it with a DCHECK. + QUIC_BUG + << "Tried to add writer into blocked list when it shouldn't be added"; + // Return without adding the connection to the blocked list, to avoid + // infinite loops in OnCanWrite. + return; + } + } else { + if (!ShouldAddToBlockedList()) { + QUIC_BUG + << "Tried to add writer into blocked list when it shouldn't be added"; + // Return without adding the connection to the blocked list, to avoid + // infinite loops in OnCanWrite. + return; + } } write_blocked_list_.insert(std::make_pair(blocked_writer, true)); }
diff --git a/net/third_party/quic/core/quic_dispatcher.h b/net/third_party/quic/core/quic_dispatcher.h index 7153dfb..e16f02df 100644 --- a/net/third_party/quic/core/quic_dispatcher.h +++ b/net/third_party/quic/core/quic_dispatcher.h
@@ -320,6 +320,7 @@ void StopAcceptingNewConnections(); // Return true if the blocked writer should be added to blocked list. + // TODO(wub): Remove when deprecating --quic_check_blocked_writer_for_blockage virtual bool ShouldAddToBlockedList(); // Called to terminate a connection statelessly. Depending on |format|, either @@ -468,6 +469,9 @@ // True if this dispatcher is not draining. bool accept_new_connections_; + + // Latched value of --quic_check_blocked_writer_for_blockage. + const bool check_blocked_writer_for_blockage_; }; } // namespace quic
diff --git a/net/third_party/quic/core/quic_dispatcher_test.cc b/net/third_party/quic/core/quic_dispatcher_test.cc index 8bff02d..7b98303 100644 --- a/net/third_party/quic/core/quic_dispatcher_test.cc +++ b/net/third_party/quic/core/quic_dispatcher_test.cc
@@ -21,6 +21,7 @@ #include "net/third_party/quic/core/stateless_rejector.h" #include "net/third_party/quic/core/tls_server_handshaker.h" #include "net/third_party/quic/platform/api/quic_arraysize.h" +#include "net/third_party/quic/platform/api/quic_expect_bug.h" #include "net/third_party/quic/platform/api/quic_flags.h" #include "net/third_party/quic/platform/api/quic_logging.h" #include "net/third_party/quic/platform/api/quic_str_cat.h" @@ -157,6 +158,7 @@ using QuicDispatcher::current_peer_address; using QuicDispatcher::current_self_address; using QuicDispatcher::GetLastPacketFormat; + using QuicDispatcher::writer; }; // A Connection class which unregisters the session from the dispatcher when @@ -304,7 +306,7 @@ } QuicServerSessionBase* CreateSession( - QuicDispatcher* dispatcher, + TestDispatcher* dispatcher, const QuicConfig& config, QuicConnectionId connection_id, const QuicSocketAddress& peer_address, @@ -315,6 +317,8 @@ TestQuicSpdyServerSession** session) { MockServerConnection* connection = new MockServerConnection( connection_id, helper, alarm_factory, dispatcher); + connection->SetQuicPacketWriter(dispatcher->writer(), + /*owns_writer=*/false); *session = new TestQuicSpdyServerSession(config, connection, crypto_config, compressed_certs_cache); connection->set_visitor(*session); @@ -1281,13 +1285,33 @@ dispatcher_->Shutdown(); } - void SetBlocked() { writer_->write_blocked_ = true; } - - void BlockConnection2() { + // Set the dispatcher's writer to be blocked. By default, all connections use + // the same writer as the dispatcher in this test. + void SetBlocked() { + QUIC_LOG(INFO) << "set writer " << writer_ << " to blocked"; writer_->write_blocked_ = true; + } + + // Simulate what happens when connection1 gets blocked when writing. + void BlockConnection1() { + Connection1Writer()->write_blocked_ = true; + dispatcher_->OnWriteBlocked(connection1()); + } + + BlockingWriter* Connection1Writer() { + return static_cast<BlockingWriter*>(connection1()->writer()); + } + + // Simulate what happens when connection2 gets blocked when writing. + void BlockConnection2() { + Connection2Writer()->write_blocked_ = true; dispatcher_->OnWriteBlocked(connection2()); } + BlockingWriter* Connection2Writer() { + return static_cast<BlockingWriter*>(connection2()->writer()); + } + protected: MockQuicConnectionHelper helper_; MockAlarmFactory alarm_factory_; @@ -1373,6 +1397,9 @@ } TEST_F(QuicDispatcherWriteBlockedListTest, OnCanWriteHandleBlock) { + if (GetQuicRestartFlag(quic_check_blocked_writer_for_blockage)) { + return; + } // Finally make sure if we write block on a write call, we stop calling. InSequence s; SetBlocked(); @@ -1382,17 +1409,38 @@ .WillOnce(Invoke(this, &QuicDispatcherWriteBlockedListTest::SetBlocked)); EXPECT_CALL(*connection2(), OnCanWrite()).Times(0); dispatcher_->OnCanWrite(); - EXPECT_TRUE(dispatcher_->HasPendingWrites()); // And we'll resume where we left off when we get another call. EXPECT_CALL(*connection2(), OnCanWrite()); dispatcher_->OnCanWrite(); +} + +TEST_F(QuicDispatcherWriteBlockedListTest, OnCanWriteHandleBlockConnection1) { + // If the 1st blocked writer gets blocked in OnCanWrite, it will be added back + // into the write blocked list. + InSequence s; + SetBlocked(); + dispatcher_->OnWriteBlocked(connection1()); + dispatcher_->OnWriteBlocked(connection2()); + EXPECT_CALL(*connection1(), OnCanWrite()) + .WillOnce( + Invoke(this, &QuicDispatcherWriteBlockedListTest::BlockConnection1)); + EXPECT_CALL(*connection2(), OnCanWrite()); + dispatcher_->OnCanWrite(); + + // connection1 should be still in the write blocked list. + EXPECT_TRUE(dispatcher_->HasPendingWrites()); + + // Now call OnCanWrite again, connection1 should get its second chance. + EXPECT_CALL(*connection1(), OnCanWrite()); + EXPECT_CALL(*connection2(), OnCanWrite()).Times(0); + dispatcher_->OnCanWrite(); EXPECT_FALSE(dispatcher_->HasPendingWrites()); } -TEST_F(QuicDispatcherWriteBlockedListTest, LimitedWrites) { - // Make sure we call both writers. The first will register for more writing - // but should not be immediately called due to limits. +TEST_F(QuicDispatcherWriteBlockedListTest, OnCanWriteHandleBlockConnection2) { + // If the 2nd blocked writer gets blocked in OnCanWrite, it will be added back + // into the write blocked list. InSequence s; SetBlocked(); dispatcher_->OnWriteBlocked(connection1()); @@ -1402,9 +1450,68 @@ .WillOnce( Invoke(this, &QuicDispatcherWriteBlockedListTest::BlockConnection2)); dispatcher_->OnCanWrite(); + + // connection2 should be still in the write blocked list. EXPECT_TRUE(dispatcher_->HasPendingWrites()); - // Now call OnCanWrite again, and connection1 should get its second chance + // Now call OnCanWrite again, connection2 should get its second chance. + EXPECT_CALL(*connection1(), OnCanWrite()).Times(0); + EXPECT_CALL(*connection2(), OnCanWrite()); + dispatcher_->OnCanWrite(); + EXPECT_FALSE(dispatcher_->HasPendingWrites()); +} + +TEST_F(QuicDispatcherWriteBlockedListTest, + OnCanWriteHandleBlockBothConnections) { + if (!GetQuicRestartFlag(quic_check_blocked_writer_for_blockage)) { + return; + } + // Both connections get blocked in OnCanWrite, and added back into the write + // blocked list. + InSequence s; + SetBlocked(); + dispatcher_->OnWriteBlocked(connection1()); + dispatcher_->OnWriteBlocked(connection2()); + EXPECT_CALL(*connection1(), OnCanWrite()) + .WillOnce( + Invoke(this, &QuicDispatcherWriteBlockedListTest::BlockConnection1)); + EXPECT_CALL(*connection2(), OnCanWrite()) + .WillOnce( + Invoke(this, &QuicDispatcherWriteBlockedListTest::BlockConnection2)); + dispatcher_->OnCanWrite(); + + // Both connections should be still in the write blocked list. + EXPECT_TRUE(dispatcher_->HasPendingWrites()); + + // Now call OnCanWrite again, both connections should get its second chance. + EXPECT_CALL(*connection1(), OnCanWrite()); + EXPECT_CALL(*connection2(), OnCanWrite()); + dispatcher_->OnCanWrite(); + EXPECT_FALSE(dispatcher_->HasPendingWrites()); +} + +TEST_F(QuicDispatcherWriteBlockedListTest, PerConnectionWriterBlocked) { + // By default, all connections share the same packet writer with the + // dispatcher. + EXPECT_EQ(dispatcher_->writer(), connection1()->writer()); + EXPECT_EQ(dispatcher_->writer(), connection2()->writer()); + + // Test the case where connection1 shares the same packet writer as the + // dispatcher, whereas connection2 owns it's packet writer. + // Change connection2's writer. + connection2()->SetQuicPacketWriter(new BlockingWriter, /*owns_writer=*/true); + EXPECT_NE(dispatcher_->writer(), connection2()->writer()); + + if (!GetQuicRestartFlag(quic_check_blocked_writer_for_blockage)) { + EXPECT_QUIC_BUG( + BlockConnection2(), + "Tried to add writer into blocked list when it shouldn't be added"); + return; + } + + BlockConnection2(); + EXPECT_TRUE(dispatcher_->HasPendingWrites()); + EXPECT_CALL(*connection2(), OnCanWrite()); dispatcher_->OnCanWrite(); EXPECT_FALSE(dispatcher_->HasPendingWrites());
diff --git a/net/third_party/quic/core/quic_time_wait_list_manager.cc b/net/third_party/quic/core/quic_time_wait_list_manager.cc index 31e6b1fb..42c60ef 100644 --- a/net/third_party/quic/core/quic_time_wait_list_manager.cc +++ b/net/third_party/quic/core/quic_time_wait_list_manager.cc
@@ -16,6 +16,7 @@ #include "net/third_party/quic/core/quic_packets.h" #include "net/third_party/quic/core/quic_utils.h" #include "net/third_party/quic/platform/api/quic_clock.h" +#include "net/third_party/quic/platform/api/quic_flag_utils.h" #include "net/third_party/quic/platform/api/quic_flags.h" #include "net/third_party/quic/platform/api/quic_logging.h" #include "net/third_party/quic/platform/api/quic_map_util.h" @@ -124,6 +125,10 @@ } void QuicTimeWaitListManager::OnBlockedWriterCanWrite() { + if (GetQuicRestartFlag(quic_check_blocked_writer_for_blockage)) { + QUIC_RESTART_FLAG_COUNT_N(quic_check_blocked_writer_for_blockage, 4, 4); + writer_->SetWritable(); + } while (!pending_packets_queue_.empty()) { QueuedPacket* queued_packet = pending_packets_queue_.front().get(); if (!WriteToWire(queued_packet)) {
diff --git a/net/third_party/quic/core/quic_time_wait_list_manager.h b/net/third_party/quic/core/quic_time_wait_list_manager.h index aac5acf5..b13e89a 100644 --- a/net/third_party/quic/core/quic_time_wait_list_manager.h +++ b/net/third_party/quic/core/quic_time_wait_list_manager.h
@@ -102,6 +102,10 @@ // send because the underlying socket was write blocked. void OnBlockedWriterCanWrite() override; + bool IsWriterBlocked() const override { + return writer_ != nullptr && writer_->IsWriteBlocked(); + } + // Used to delete connection_id entries that have outlived their time wait // period. void CleanUpOldConnectionIds();
diff --git a/net/url_request/url_request_http_job.cc b/net/url_request/url_request_http_job.cc index 6cbaaea..5aa54e47a 100644 --- a/net/url_request/url_request_http_job.cc +++ b/net/url_request/url_request_http_job.cc
@@ -405,6 +405,7 @@ request_info_.url = request_->url(); request_info_.method = request_->method(); + request_info_.top_frame_origin = request_->top_frame_origin(); request_info_.load_flags = request_->load_flags(); request_info_.traffic_annotation = net::MutableNetworkTrafficAnnotationTag(request_->traffic_annotation());
diff --git a/net/url_request/url_request_unittest.cc b/net/url_request/url_request_unittest.cc index 817ea50..8373405 100644 --- a/net/url_request/url_request_unittest.cc +++ b/net/url_request/url_request_unittest.cc
@@ -8072,6 +8072,27 @@ EXPECT_FALSE(r->top_frame_origin()); } +TEST_F(URLRequestTestHTTP, RedirectPreserveTopFrameURL) { + ASSERT_TRUE(http_test_server()->Start()); + + GURL url(http_test_server()->GetURL("/redirect302-to-echo")); + url::Origin top_frame_origin = + url::Origin::Create(GURL("http://example.com")); + TestDelegate d; + { + std::unique_ptr<URLRequest> r(default_context().CreateRequest( + url, DEFAULT_PRIORITY, &d, TRAFFIC_ANNOTATION_FOR_TESTS)); + r->set_top_frame_origin(top_frame_origin); + + r->Start(); + d.RunUntilComplete(); + + EXPECT_EQ(2U, r->url_chain().size()); + EXPECT_EQ(OK, d.request_status()); + EXPECT_EQ(top_frame_origin, *r->top_frame_origin()); + } +} + TEST_F(URLRequestTestHTTP, RedirectUpdateFirstPartyURL) { ASSERT_TRUE(http_test_server()->Start());
diff --git a/remoting/host/BUILD.gn b/remoting/host/BUILD.gn index 67e7d837..b6e72dd 100644 --- a/remoting/host/BUILD.gn +++ b/remoting/host/BUILD.gn
@@ -142,13 +142,6 @@ "dns_blackhole_checker.h", "evaluate_capability.cc", "evaluate_capability.h", - "file_proxy_wrapper.cc", - "file_proxy_wrapper.h", - "file_proxy_wrapper_linux.cc", - "file_proxy_wrapper_mac.cc", - "file_proxy_wrapper_win.cc", - "file_transfer_message_handler.cc", - "file_transfer_message_handler.h", "forward_process_stats_agent.cc", "forward_process_stats_agent.h", "gcd_rest_client.cc", @@ -304,6 +297,7 @@ "//media", "//remoting/base", "//remoting/base:authorization", + "//remoting/host/file_transfer", "//remoting/host/input_monitor", "//remoting/host/security_key", "//remoting/protocol", @@ -462,8 +456,6 @@ "daemon_process_unittest.cc", "desktop_process_unittest.cc", "desktop_session_agent_unittest.cc", - "file_proxy_wrapper_linux_unittest.cc", - "file_transfer_message_handler_unittest.cc", "gcd_rest_client_unittest.cc", "gcd_state_updater_unittest.cc", "heartbeat_sender_unittest.cc",
diff --git a/remoting/host/basic_desktop_environment.cc b/remoting/host/basic_desktop_environment.cc index 3c9ee36..2622454c5 100644 --- a/remoting/host/basic_desktop_environment.cc +++ b/remoting/host/basic_desktop_environment.cc
@@ -12,7 +12,7 @@ #include "remoting/host/audio_capturer.h" #include "remoting/host/client_session_control.h" #include "remoting/host/desktop_capturer_proxy.h" -#include "remoting/host/file_proxy_wrapper.h" +#include "remoting/host/file_transfer/local_file_operations.h" #include "remoting/host/input_injector.h" #include "remoting/host/mouse_cursor_monitor_proxy.h" #include "remoting/host/screen_controls.h" @@ -70,9 +70,9 @@ desktop_capture_options()); } -std::unique_ptr<FileProxyWrapper> -BasicDesktopEnvironment::CreateFileProxyWrapper() { - return FileProxyWrapper::Create(); +std::unique_ptr<FileOperations> +BasicDesktopEnvironment::CreateFileOperations() { + return std::make_unique<LocalFileOperations>(); } std::string BasicDesktopEnvironment::GetCapabilities() const {
diff --git a/remoting/host/basic_desktop_environment.h b/remoting/host/basic_desktop_environment.h index f59e0079..21edc6d 100644 --- a/remoting/host/basic_desktop_environment.h +++ b/remoting/host/basic_desktop_environment.h
@@ -44,7 +44,7 @@ std::unique_ptr<webrtc::DesktopCapturer> CreateVideoCapturer() override; std::unique_ptr<webrtc::MouseCursorMonitor> CreateMouseCursorMonitor() override; - std::unique_ptr<FileProxyWrapper> CreateFileProxyWrapper() override; + std::unique_ptr<FileOperations> CreateFileOperations() override; std::string GetCapabilities() const override; void SetCapabilities(const std::string& capabilities) override; uint32_t GetDesktopSessionId() const override;
diff --git a/remoting/host/client_session.cc b/remoting/host/client_session.cc index 90e1e865..8280f36 100644 --- a/remoting/host/client_session.cc +++ b/remoting/host/client_session.cc
@@ -20,7 +20,7 @@ #include "remoting/host/action_message_handler.h" #include "remoting/host/audio_capturer.h" #include "remoting/host/desktop_environment.h" -#include "remoting/host/file_transfer_message_handler.h" +#include "remoting/host/file_transfer/file_transfer_message_handler.h" #include "remoting/host/host_extension_session.h" #include "remoting/host/input_injector.h" #include "remoting/host/mouse_shape_pump.h" @@ -558,9 +558,8 @@ // FileTransferMessageHandler manages its own lifetime and is tied to the // lifetime of |pipe|. Once |pipe| is closed, this instance will be cleaned // up. - new FileTransferMessageHandler( - channel_name, std::move(pipe), - desktop_environment_->CreateFileProxyWrapper()); + new FileTransferMessageHandler(channel_name, std::move(pipe), + desktop_environment_->CreateFileOperations()); } void ClientSession::CreateActionMessageHandler(
diff --git a/remoting/host/desktop_environment.h b/remoting/host/desktop_environment.h index 512e123..2e67319 100644 --- a/remoting/host/desktop_environment.h +++ b/remoting/host/desktop_environment.h
@@ -24,7 +24,7 @@ class ActionExecutor; class AudioCapturer; class ClientSessionControl; -class FileProxyWrapper; +class FileOperations; class InputInjector; class ScreenControls; @@ -43,7 +43,7 @@ virtual std::unique_ptr<webrtc::DesktopCapturer> CreateVideoCapturer() = 0; virtual std::unique_ptr<webrtc::MouseCursorMonitor> CreateMouseCursorMonitor() = 0; - virtual std::unique_ptr<FileProxyWrapper> CreateFileProxyWrapper() = 0; + virtual std::unique_ptr<FileOperations> CreateFileOperations() = 0; // Returns the set of all capabilities supported by |this|. virtual std::string GetCapabilities() const = 0;
diff --git a/remoting/host/fake_desktop_environment.cc b/remoting/host/fake_desktop_environment.cc index 08f4eea..5aca053 100644 --- a/remoting/host/fake_desktop_environment.cc +++ b/remoting/host/fake_desktop_environment.cc
@@ -8,7 +8,7 @@ #include "remoting/host/audio_capturer.h" #include "remoting/host/desktop_capturer_proxy.h" -#include "remoting/host/file_proxy_wrapper.h" +#include "remoting/host/file_transfer/file_operations.h" #include "remoting/host/input_injector.h" #include "remoting/proto/event.pb.h" #include "remoting/protocol/fake_desktop_capturer.h" @@ -100,8 +100,7 @@ return std::make_unique<FakeMouseCursorMonitor>(); } -std::unique_ptr<FileProxyWrapper> -FakeDesktopEnvironment::CreateFileProxyWrapper() { +std::unique_ptr<FileOperations> FakeDesktopEnvironment::CreateFileOperations() { return nullptr; }
diff --git a/remoting/host/fake_desktop_environment.h b/remoting/host/fake_desktop_environment.h index 740f6b5..a490c1d 100644 --- a/remoting/host/fake_desktop_environment.h +++ b/remoting/host/fake_desktop_environment.h
@@ -99,7 +99,7 @@ std::unique_ptr<webrtc::DesktopCapturer> CreateVideoCapturer() override; std::unique_ptr<webrtc::MouseCursorMonitor> CreateMouseCursorMonitor() override; - std::unique_ptr<FileProxyWrapper> CreateFileProxyWrapper() override; + std::unique_ptr<FileOperations> CreateFileOperations() override; std::string GetCapabilities() const override; void SetCapabilities(const std::string& capabilities) override; uint32_t GetDesktopSessionId() const override;
diff --git a/remoting/host/file_proxy_wrapper.cc b/remoting/host/file_proxy_wrapper.cc deleted file mode 100644 index 6e1aabc..0000000 --- a/remoting/host/file_proxy_wrapper.cc +++ /dev/null
@@ -1,13 +0,0 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "remoting/host/file_proxy_wrapper.h" - -namespace remoting { - -FileProxyWrapper::FileProxyWrapper() = default; - -FileProxyWrapper::~FileProxyWrapper() = default; - -} // namespace remoting
diff --git a/remoting/host/file_proxy_wrapper.h b/remoting/host/file_proxy_wrapper.h deleted file mode 100644 index 0c959dd..0000000 --- a/remoting/host/file_proxy_wrapper.h +++ /dev/null
@@ -1,84 +0,0 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef REMOTING_HOST_FILE_PROXY_WRAPPER_H_ -#define REMOTING_HOST_FILE_PROXY_WRAPPER_H_ - -#include "base/callback.h" -#include "base/files/file_proxy.h" -#include "base/optional.h" -#include "remoting/proto/file_transfer.pb.h" - -namespace remoting { - -// FileProxyWrapper is an interface for implementing platform-specific file -// writers for file transfers. Each operation is posted to a separate file IO -// thread, and possibly a different process depending on the platform. -// TODO(jarhar): Create interfaces for reading and writing implemented by this -// interface to constrain the usage of this interface to reading or writing. -class FileProxyWrapper { - public: - enum State { - // Created, but Init() has not been called yet. - kUninitialized = 0, - - // Init() has been called. - kInitialized = 1, - - // The file has been opened. WriteChunk(), ReadChunk(), and Close() can be - // called. - kReady = 2, - - // A file operation is currently being processed. WriteChunk(), ReadChunk(), - // and Close() cannot be called until the state changes back to kReady. - kBusy = 3, - - // Close() has been called and succeeded. - kClosed = 4, - - // Cancel() has been called or an error occured. - kFailed = 5, - }; - - // If writing the file fails, the status callback will be called with the - // causal error. Otherwise, the callback will be called with a nullopt once - // the file has been successfully written. - typedef base::OnceCallback<void(base::Optional<protocol::FileTransfer_Error>)> - ResultCallback; - - typedef base::OnceCallback<void(int64_t filesize)> OpenFileCallback; - - typedef base::OnceCallback<void(std::unique_ptr<std::vector<char>>)> - ReadCallback; - - // Creates a platform-specific FileProxyWrapper. - static std::unique_ptr<FileProxyWrapper> Create(); - - FileProxyWrapper(); - virtual ~FileProxyWrapper(); - - // |result_callback| is called either when FileProxyWrapper encounters an - // error or when Close() has been called and the file has been written - // successfully. |result_callback| must not immediately destroy this - // FileProxyWrapper. - virtual void Init(ResultCallback result_callback) = 0; - // Creates a new file and opens it for writing. - virtual void CreateFile(const base::FilePath& directory, - const std::string& filename) = 0; - // Opens an existing file for reading. - virtual void OpenFile(const base::FilePath& filepath, - OpenFileCallback open_callback) = 0; - virtual void WriteChunk(std::string buffer) = 0; - // |size| must not be greater than the remaining amount of bytes in the file - // from the current read offset. After calling ReadChunk(), ReadChunk() cannot - // be called again until |read_callback| is called and state() returns kReady. - virtual void ReadChunk(uint64_t size, ReadCallback read_callback) = 0; - virtual void Close() = 0; - virtual void Cancel() = 0; - virtual State state() = 0; -}; - -} // namespace remoting - -#endif // REMOTING_HOST_FILE_PROXY_WRAPPER_H_
diff --git a/remoting/host/file_proxy_wrapper_linux.cc b/remoting/host/file_proxy_wrapper_linux.cc deleted file mode 100644 index 917622a..0000000 --- a/remoting/host/file_proxy_wrapper_linux.cc +++ /dev/null
@@ -1,515 +0,0 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "remoting/host/file_proxy_wrapper.h" - -#include <cstring> -#include <memory> -#include <string> -#include <vector> - -#include "base/containers/queue.h" -#include "base/files/file_util.h" -#include "base/memory/ptr_util.h" -#include "base/optional.h" -#include "base/sequenced_task_runner.h" -#include "base/strings/stringprintf.h" -#include "base/task/post_task.h" -#include "base/task_runner_util.h" -#include "base/threading/thread_checker.h" -#include "remoting/base/compound_buffer.h" -#include "remoting/protocol/file_transfer_helpers.h" - -namespace { - -constexpr char kTempFileExtension[] = ".crdownload"; - -remoting::protocol::FileTransfer_Error_Type FileErrorToResponseErrorType( - base::File::Error file_error) { - switch (file_error) { - case base::File::FILE_ERROR_ACCESS_DENIED: - return remoting::protocol::FileTransfer_Error_Type_PERMISSION_DENIED; - case base::File::FILE_ERROR_NO_SPACE: - return remoting::protocol::FileTransfer_Error_Type_OUT_OF_DISK_SPACE; - default: - return remoting::protocol::FileTransfer_Error_Type_IO_ERROR; - } -} - -} // namespace - -namespace remoting { - -class FileProxyWrapperLinux : public FileProxyWrapper { - public: - FileProxyWrapperLinux(); - ~FileProxyWrapperLinux() override; - - // FileProxyWrapper implementation. - void Init(ResultCallback result_callback) override; - void CreateFile(const base::FilePath& directory, - const std::string& filename) override; - void OpenFile(const base::FilePath& filepath, - OpenFileCallback open_callback) override; - void WriteChunk(std::string buffer) override; - void ReadChunk(uint64_t chunk_size, ReadCallback read_callback) override; - void Close() override; - void Cancel() override; - State state() override; - - private: - enum Mode { - // Neither CreateFile() nor OpenFile() has been called yet. - kUnknown = 0, - - // CreateFile() has been called. - kWriting = 1, - - // OpenFile() has been called. - kReading = 2, - } mode_ = kUnknown; - - struct FileChunk { - int64_t write_offset; - std::string data; - }; - - // Callbacks for CreateFile(). - void CreateTempFile(int unique_path_number); - void CreateTempFileCallback(base::File::Error error); - - // Callbacks for OpenFile(). - void OpenCallback(base::File::Error error); - void GetInfoCallback(base::File::Error error, const base::File::Info& info); - - // Callbacks for WriteChunk(). - void WriteFileChunk(FileChunk chunk); - void WriteCallback(base::File::Error error, int bytes_written); - - // Callbacks for ReadChunk(). - void ReadChunkCallback(base::File::Error error, - const char* data, - int bytes_read); - - // Callbacks for Close(). - void CloseFileAndMoveToDestination(); - void CloseCallback(base::File::Error error); - void MoveToDestination(int unique_path_number); - void MoveFileCallback(bool success); - - void CancelWithError(protocol::FileTransfer_Error error, - const std::string& log_message); - void SetState(State state); - - State state_ = kUninitialized; - scoped_refptr<base::SequencedTaskRunner> file_task_runner_; - std::unique_ptr<base::FileProxy> file_proxy_; - - ResultCallback result_callback_; - - // CreateFile() state - for writing only - bool temp_file_created_ = false; - base::FilePath temp_filepath_; - base::FilePath destination_filepath_; - - // OpenFile() state - for reading only - base::FilePath read_filepath_; - OpenFileCallback open_callback_; - - // WriteChunk() state - for writing only - int64_t next_write_file_offset_ = 0; - base::queue<FileChunk> file_chunks_; - // active_file_chunk_ is the chunk currently being written to disk. It is - // empty if nothing is being written to disk right now. - base::Optional<FileChunk> active_file_chunk_; - - // ReadChunk() state - for reading only - ReadCallback read_callback_; - uint64_t expected_bytes_read_ = 0; - int64_t next_read_file_offset_ = 0; - - base::ThreadChecker thread_checker_; - base::WeakPtr<FileProxyWrapperLinux> weak_ptr_; - base::WeakPtrFactory<FileProxyWrapperLinux> weak_factory_; -}; - -FileProxyWrapperLinux::FileProxyWrapperLinux() : weak_factory_(this) { - weak_ptr_ = weak_factory_.GetWeakPtr(); -} - -FileProxyWrapperLinux::~FileProxyWrapperLinux() { - DCHECK(thread_checker_.CalledOnValidThread()); -} - -void FileProxyWrapperLinux::Init(ResultCallback result_callback) { - DCHECK(thread_checker_.CalledOnValidThread()); - - SetState(kInitialized); - result_callback_ = std::move(result_callback); - - file_task_runner_ = base::CreateSequencedTaskRunnerWithTraits( - {base::MayBlock(), base::TaskPriority::BEST_EFFORT}); - DCHECK(file_task_runner_); - - file_proxy_.reset(new base::FileProxy(file_task_runner_.get())); - - if (!file_task_runner_) { - CancelWithError( - protocol::MakeFileTransferError( - FROM_HERE, protocol::FileTransfer_Error_Type_UNEXPECTED_ERROR), - "Failed to create file task runner."); - } -} - -void FileProxyWrapperLinux::CreateFile(const base::FilePath& directory, - const std::string& filename) { - DCHECK(thread_checker_.CalledOnValidThread()); - DCHECK_EQ(mode_, kUnknown); - mode_ = kWriting; - SetState(kReady); - - destination_filepath_ = directory.Append(filename); - temp_filepath_ = destination_filepath_.AddExtension(kTempFileExtension); - - PostTaskAndReplyWithResult( - file_task_runner_.get(), FROM_HERE, - base::BindOnce(&base::GetUniquePathNumber, temp_filepath_, - base::FilePath::StringType()), - base::BindOnce(&FileProxyWrapperLinux::CreateTempFile, weak_ptr_)); -} - -void FileProxyWrapperLinux::CreateTempFile(int unique_path_number) { - if (unique_path_number > 0) { - temp_filepath_ = temp_filepath_.InsertBeforeExtensionASCII( - base::StringPrintf(" (%d)", unique_path_number)); - } - if (!file_proxy_->CreateOrOpen( - temp_filepath_, base::File::FLAG_CREATE | base::File::FLAG_WRITE, - base::Bind(&FileProxyWrapperLinux::CreateTempFileCallback, - weak_ptr_))) { - CancelWithError( - protocol::MakeFileTransferError( - FROM_HERE, protocol::FileTransfer_Error_Type_UNEXPECTED_ERROR), - "File proxy failed to post task to file task runner."); - } -} - -void FileProxyWrapperLinux::CreateTempFileCallback(base::File::Error error) { - if (error) { - CancelWithError( - protocol::MakeFileTransferError( - FROM_HERE, FileErrorToResponseErrorType(error), error), - base::StringPrintf("Creating temp file failed with error: %d", error)); - } else { - // Now that the temp file has been created successfully, we could lock it - // using base::File::Lock(), but this would not prevent the file from being - // deleted. When the file is deleted, WriteChunk() will continue to write to - // the file as if the file was still there, and an error will occur when - // calling base::Move() to move the temp file. Chrome exhibits the same - // behavior with its downloads. - temp_file_created_ = true; - // Chunks to write may have been queued while we were creating the file, - // start writing them now if there were any. - if (!file_chunks_.empty()) { - FileChunk chunk_to_write = std::move(file_chunks_.front()); - file_chunks_.pop(); - WriteFileChunk(std::move(chunk_to_write)); - } - } -} - -void FileProxyWrapperLinux::OpenFile(const base::FilePath& filepath, - OpenFileCallback open_callback) { - DCHECK(thread_checker_.CalledOnValidThread()); - DCHECK_EQ(mode_, kUnknown); - mode_ = kReading; - - read_filepath_ = filepath; - open_callback_ = std::move(open_callback); - - if (!file_proxy_->CreateOrOpen( - read_filepath_, base::File::FLAG_OPEN | base::File::FLAG_READ, - base::Bind(&FileProxyWrapperLinux::OpenCallback, weak_ptr_))) { - CancelWithError( - protocol::MakeFileTransferError( - FROM_HERE, protocol::FileTransfer_Error_Type_UNEXPECTED_ERROR), - "File proxy failed to post task to file task runner."); - } -} - -void FileProxyWrapperLinux::OpenCallback(base::File::Error error) { - if (error) { - CancelWithError( - protocol::MakeFileTransferError( - FROM_HERE, FileErrorToResponseErrorType(error), error), - base::StringPrintf("Opening file failed with error: %d", error)); - return; - } - - if (!file_proxy_->GetInfo( - base::Bind(&FileProxyWrapperLinux::GetInfoCallback, weak_ptr_))) { - CancelWithError( - protocol::MakeFileTransferError( - FROM_HERE, protocol::FileTransfer_Error_Type_UNEXPECTED_ERROR), - "File proxy failed to post task to file task runner."); - } -} - -void FileProxyWrapperLinux::GetInfoCallback(base::File::Error error, - const base::File::Info& info) { - if (error) { - CancelWithError( - protocol::MakeFileTransferError( - FROM_HERE, FileErrorToResponseErrorType(error), error), - base::StringPrintf("Getting file info failed with error: %d", error)); - return; - } - - if (info.is_directory) { - CancelWithError( - protocol::MakeFileTransferError( - FROM_HERE, protocol::FileTransfer_Error_Type_UNEXPECTED_ERROR), - "Tried to open directory for reading chunks."); - return; - } - - SetState(kReady); - std::move(open_callback_).Run(info.size); -} - -void FileProxyWrapperLinux::WriteChunk(std::string buffer) { - DCHECK(thread_checker_.CalledOnValidThread()); - DCHECK_EQ(mode_, kWriting); - DCHECK_EQ(state_, kReady); - - FileChunk new_file_chunk; - new_file_chunk.data = std::move(buffer); - new_file_chunk.write_offset = next_write_file_offset_; - next_write_file_offset_ += new_file_chunk.data.size(); - - // If the file hasn't been created yet or there is another chunk currently - // being written, we have to queue this chunk to be written later. - if (!temp_file_created_ || active_file_chunk_) { - // TODO(jarhar): When flow control enabled QUIC-based WebRTC data channels - // are implemented, block the flow of incoming chunks here if - // file_chunks_ has reached a maximum size. This implementation will - // allow file_chunks_ to grow without limits. - file_chunks_.push(std::move(new_file_chunk)); - } else { - WriteFileChunk(std::move(new_file_chunk)); - } -} - -void FileProxyWrapperLinux::WriteFileChunk(FileChunk chunk) { - active_file_chunk_ = std::move(chunk); - if (!file_proxy_->Write( - active_file_chunk_->write_offset, active_file_chunk_->data.data(), - active_file_chunk_->data.size(), - base::Bind(&FileProxyWrapperLinux::WriteCallback, weak_ptr_))) { - CancelWithError( - protocol::MakeFileTransferError( - FROM_HERE, protocol::FileTransfer_Error_Type_UNEXPECTED_ERROR), - "File proxy failed to post task to file task runner."); - } -} - -void FileProxyWrapperLinux::WriteCallback(base::File::Error error, - int bytes_written) { - if (active_file_chunk_->data.size() != static_cast<unsigned>(bytes_written) || - error) { - if (!error) { - error = base::File::FILE_ERROR_FAILED; - } - CancelWithError(protocol::MakeFileTransferError( - FROM_HERE, FileErrorToResponseErrorType(error), error), - base::StringPrintf("Write failed with error: %d", error)); - return; - } - - active_file_chunk_.reset(); - if (!file_chunks_.empty()) { - FileChunk chunk_to_write = std::move(file_chunks_.front()); - file_chunks_.pop(); - WriteFileChunk(std::move(chunk_to_write)); - } else if (state_ == kBusy) { - // All writes are complete and we have gotten the signal to move the file. - CloseFileAndMoveToDestination(); - } -} - -void FileProxyWrapperLinux::ReadChunk(uint64_t size, - ReadCallback read_callback) { - DCHECK(thread_checker_.CalledOnValidThread()); - DCHECK_EQ(mode_, kReading); - SetState(kBusy); - - expected_bytes_read_ = size; - read_callback_ = std::move(read_callback); - - if (!file_proxy_->Read( - next_read_file_offset_, expected_bytes_read_, - base::Bind(&FileProxyWrapperLinux::ReadChunkCallback, weak_ptr_))) { - CancelWithError( - protocol::MakeFileTransferError( - FROM_HERE, protocol::FileTransfer_Error_Type_UNEXPECTED_ERROR), - "File proxy failed to post task to file task runner."); - } -} - -void FileProxyWrapperLinux::ReadChunkCallback(base::File::Error error, - const char* data, - int bytes_read) { - if (static_cast<unsigned>(bytes_read) != expected_bytes_read_ || error) { - if (!error) { - error = base::File::FILE_ERROR_FAILED; - } - CancelWithError(protocol::MakeFileTransferError( - FROM_HERE, FileErrorToResponseErrorType(error), error), - base::StringPrintf("Read failed with error: %d", error)); - return; - } - - next_read_file_offset_ += bytes_read; - - std::unique_ptr<std::vector<char>> read_buffer = - std::make_unique<std::vector<char>>(); - read_buffer->resize(bytes_read); - memcpy(read_buffer->data(), data, read_buffer->size()); - - SetState(kReady); - std::move(read_callback_).Run(std::move(read_buffer)); -} - -void FileProxyWrapperLinux::Close() { - DCHECK(thread_checker_.CalledOnValidThread()); - DCHECK_EQ(state_, kReady); - - if (mode_ == kWriting) { - SetState(kBusy); - if (!active_file_chunk_ && file_chunks_.empty()) { - // All writes are complete, so we can finish up now. - CloseFileAndMoveToDestination(); - } - return; - } - - file_proxy_->Close(base::DoNothing()); - SetState(kClosed); -} - -void FileProxyWrapperLinux::CloseFileAndMoveToDestination() { - DCHECK_EQ(state_, kBusy); - file_proxy_->Close( - base::Bind(&FileProxyWrapperLinux::CloseCallback, weak_ptr_)); -} - -void FileProxyWrapperLinux::CloseCallback(base::File::Error error) { - if (error) { - CancelWithError(protocol::MakeFileTransferError( - FROM_HERE, FileErrorToResponseErrorType(error), error), - base::StringPrintf("Close failed with error: %d", error)); - return; - } - - PostTaskAndReplyWithResult( - file_task_runner_.get(), FROM_HERE, - base::BindOnce(&base::GetUniquePathNumber, destination_filepath_, - base::FilePath::StringType()), - base::BindOnce(&FileProxyWrapperLinux::MoveToDestination, weak_ptr_)); -} - -void FileProxyWrapperLinux::MoveToDestination(int unique_path_number) { - if (unique_path_number > 0) { - destination_filepath_ = destination_filepath_.InsertBeforeExtensionASCII( - base::StringPrintf(" (%d)", unique_path_number)); - } - PostTaskAndReplyWithResult( - file_task_runner_.get(), FROM_HERE, - base::BindOnce(&base::Move, temp_filepath_, destination_filepath_), - base::BindOnce(&FileProxyWrapperLinux::MoveFileCallback, weak_ptr_)); -} - -void FileProxyWrapperLinux::MoveFileCallback(bool success) { - DCHECK(thread_checker_.CalledOnValidThread()); - - if (success) { - SetState(kClosed); - std::move(result_callback_).Run(base::nullopt); - } else { - CancelWithError(protocol::MakeFileTransferError( - FROM_HERE, protocol::FileTransfer_Error_Type_IO_ERROR), - "Failed to move file to final destination."); - } -} - -void FileProxyWrapperLinux::Cancel() { - if (file_proxy_->IsValid()) { - file_proxy_->Close(base::DoNothing()); - } - - // Invalidate any outstanding weak pointers to ensure we don't get unexpected - // callbacks. - weak_factory_.InvalidateWeakPtrs(); - - if (mode_ == kWriting) { - if (state_ == kReady || state_ == kBusy) { - file_task_runner_->PostTask( - FROM_HERE, base::BindOnce(base::IgnoreResult(&base::DeleteFile), - temp_filepath_, false /* recursive */)); - } - - if (state_ == kBusy || state_ == kClosed) { - file_task_runner_->PostTask( - FROM_HERE, - base::BindOnce(base::IgnoreResult(&base::DeleteFile), - destination_filepath_, false /* recursive */)); - } - } - - SetState(kFailed); -} - -void FileProxyWrapperLinux::CancelWithError(protocol::FileTransfer_Error error, - const std::string& log_message) { - LOG(ERROR) << log_message; - Cancel(); - std::move(result_callback_).Run(error); -} - -void FileProxyWrapperLinux::SetState(State state) { - switch (state) { - case kUninitialized: - // No state can change to kUninitialized. - NOTREACHED(); - break; - case kInitialized: - DCHECK_EQ(state_, kUninitialized); - break; - case kReady: - DCHECK(state_ == kInitialized || state_ == kBusy); - break; - case kBusy: - DCHECK_EQ(state_, kReady); - break; - case kClosed: - DCHECK(state_ == kReady || state_ == kBusy); - break; - case kFailed: - // Any state can change to kFailed. - break; - } - - state_ = state; -} - -FileProxyWrapper::State FileProxyWrapperLinux::state() { - return state_; -} - -// static -std::unique_ptr<FileProxyWrapper> FileProxyWrapper::Create() { - return base::WrapUnique(new FileProxyWrapperLinux()); -} - -} // namespace remoting
diff --git a/remoting/host/file_proxy_wrapper_linux_unittest.cc b/remoting/host/file_proxy_wrapper_linux_unittest.cc deleted file mode 100644 index 440fa27..0000000 --- a/remoting/host/file_proxy_wrapper_linux_unittest.cc +++ /dev/null
@@ -1,214 +0,0 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "remoting/host/file_proxy_wrapper.h" - -#include <memory> -#include <queue> - -#include "base/bind.h" -#include "base/bind_helpers.h" -#include "base/containers/queue.h" -#include "base/files/file_util.h" -#include "base/files/scoped_temp_dir.h" -#include "base/run_loop.h" -#include "base/test/scoped_task_environment.h" -#include "net/base/io_buffer.h" -#include "remoting/base/compound_buffer.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace { - -constexpr char kTestFilename[] = "test-file.txt"; -constexpr char kTestFilenameSecondary[] = "test-file (1).txt"; -const std::string& kTestDataOne = "this is the first test string"; -const std::string& kTestDataTwo = "this is the second test string"; -const std::string& kTestDataThree = "this is the third test string"; - -} // namespace - -namespace remoting { - -class FileProxyWrapperLinuxTest : public testing::Test { - public: - FileProxyWrapperLinuxTest(); - ~FileProxyWrapperLinuxTest() override; - - // testing::Test implementation. - void SetUp() override; - void TearDown() override; - - const base::FilePath& TestDir() const { return dir_.GetPath(); } - const base::FilePath TestFilePath() const { - return dir_.GetPath().Append(kTestFilename); - } - - void ResultCallback(base::Optional<protocol::FileTransfer_Error> error); - void OpenFileCallback(int64_t filesize); - void ReadChunkCallback(std::unique_ptr<std::vector<char>> chunk); - - protected: - base::test::ScopedTaskEnvironment scoped_task_environment_; - base::ScopedTempDir dir_; - - std::unique_ptr<FileProxyWrapper> file_proxy_wrapper_; - base::Optional<protocol::FileTransfer_Error> error_; - bool done_callback_succeeded_; - - base::queue<std::vector<char>> read_chunks_; - int64_t read_filesize_; -}; - -FileProxyWrapperLinuxTest::FileProxyWrapperLinuxTest() - : scoped_task_environment_( - base::test::ScopedTaskEnvironment::MainThreadType::DEFAULT, - base::test::ScopedTaskEnvironment::ExecutionMode::QUEUED) {} -FileProxyWrapperLinuxTest::~FileProxyWrapperLinuxTest() = default; - -void FileProxyWrapperLinuxTest::SetUp() { - ASSERT_TRUE(dir_.CreateUniqueTempDir()); - - file_proxy_wrapper_ = FileProxyWrapper::Create(); - file_proxy_wrapper_->Init(base::BindOnce( - &FileProxyWrapperLinuxTest::ResultCallback, base::Unretained(this))); - - error_ = base::nullopt; - done_callback_succeeded_ = false; - - read_chunks_ = base::queue<std::vector<char>>(); - read_filesize_ = 0; -} - -void FileProxyWrapperLinuxTest::TearDown() { - file_proxy_wrapper_.reset(); -} - -void FileProxyWrapperLinuxTest::ResultCallback( - base::Optional<protocol::FileTransfer_Error> error) { - error_ = error; - done_callback_succeeded_ = !error_; -} - -void FileProxyWrapperLinuxTest::OpenFileCallback(int64_t filesize) { - read_filesize_ = filesize; -} - -void FileProxyWrapperLinuxTest::ReadChunkCallback( - std::unique_ptr<std::vector<char>> chunk) { - read_chunks_.push(*chunk); -} - -// Verifies that FileProxyWrapper can write three chunks to a file without -// throwing any errors. -TEST_F(FileProxyWrapperLinuxTest, WriteThreeChunks) { - file_proxy_wrapper_->CreateFile(TestDir(), kTestFilename); - file_proxy_wrapper_->WriteChunk(kTestDataOne); - file_proxy_wrapper_->WriteChunk(kTestDataTwo); - file_proxy_wrapper_->WriteChunk(kTestDataThree); - file_proxy_wrapper_->Close(); - scoped_task_environment_.RunUntilIdle(); - - ASSERT_FALSE(error_); - ASSERT_TRUE(done_callback_succeeded_); - - std::string actual_file_data; - ASSERT_TRUE(base::ReadFileToString(TestFilePath(), &actual_file_data)); - ASSERT_TRUE(kTestDataOne + kTestDataTwo + kTestDataThree == actual_file_data); -} - -// Verifies that calling Cancel() deletes any temporary or destination files. -TEST_F(FileProxyWrapperLinuxTest, CancelDeletesFiles) { - file_proxy_wrapper_->CreateFile(TestDir(), kTestFilename); - file_proxy_wrapper_->WriteChunk(kTestDataOne); - scoped_task_environment_.RunUntilIdle(); - - file_proxy_wrapper_->Cancel(); - file_proxy_wrapper_.reset(); - scoped_task_environment_.RunUntilIdle(); - - ASSERT_TRUE(base::IsDirectoryEmpty(TestDir())); -} - -// Verifies that FileProxyWrapper will write to a file named "file (1).txt" when -// "file.txt" already exists. -TEST_F(FileProxyWrapperLinuxTest, FileAlreadyExists) { - WriteFile(TestFilePath(), kTestDataOne.data(), kTestDataOne.size()); - - file_proxy_wrapper_->CreateFile(TestDir(), kTestFilename); - file_proxy_wrapper_->WriteChunk(kTestDataTwo); - file_proxy_wrapper_->Close(); - scoped_task_environment_.RunUntilIdle(); - - std::string actual_file_data; - base::FilePath secondary_filepath = TestDir().Append(kTestFilenameSecondary); - ASSERT_TRUE(base::ReadFileToString(secondary_filepath, &actual_file_data)); - ASSERT_STREQ(kTestDataTwo.data(), actual_file_data.data()); - - ASSERT_FALSE(error_); -} - -// Verifies that FileProxyWrapper can read chunks from a file. -TEST_F(FileProxyWrapperLinuxTest, ReadThreeChunks) { - std::string test_data = kTestDataOne + kTestDataTwo + kTestDataThree; - WriteFile(TestFilePath(), test_data.data(), test_data.size()); - - file_proxy_wrapper_->OpenFile( - TestFilePath(), base::Bind(&FileProxyWrapperLinuxTest::OpenFileCallback, - base::Unretained(this))); - scoped_task_environment_.RunUntilIdle(); - ASSERT_FALSE(error_); - ASSERT_EQ(static_cast<uint64_t>(read_filesize_), test_data.size()); - - file_proxy_wrapper_->ReadChunk( - kTestDataOne.size(), - base::BindOnce(&FileProxyWrapperLinuxTest::ReadChunkCallback, - base::Unretained(this))); - scoped_task_environment_.RunUntilIdle(); - - file_proxy_wrapper_->ReadChunk( - kTestDataTwo.size(), - base::BindOnce(&FileProxyWrapperLinuxTest::ReadChunkCallback, - base::Unretained(this))); - scoped_task_environment_.RunUntilIdle(); - - file_proxy_wrapper_->ReadChunk( - kTestDataThree.size(), - base::BindOnce(&FileProxyWrapperLinuxTest::ReadChunkCallback, - base::Unretained(this))); - scoped_task_environment_.RunUntilIdle(); - - file_proxy_wrapper_->Close(); - scoped_task_environment_.RunUntilIdle(); - - base::queue<std::vector<char>> expected_read_chunks; - expected_read_chunks.push( - std::vector<char>(kTestDataOne.begin(), kTestDataOne.end())); - expected_read_chunks.push( - std::vector<char>(kTestDataTwo.begin(), kTestDataTwo.end())); - expected_read_chunks.push( - std::vector<char>(kTestDataThree.begin(), kTestDataThree.end())); - ASSERT_FALSE(error_); - - ASSERT_EQ(expected_read_chunks.size(), read_chunks_.size()); - while (!expected_read_chunks.empty()) { - ASSERT_EQ(expected_read_chunks.front(), read_chunks_.front()); - expected_read_chunks.pop(); - read_chunks_.pop(); - } -} - -// Verifies that FileProxyWrapper fails to open a file for reading if the file -// doesn't exist. -TEST_F(FileProxyWrapperLinuxTest, FileDoesntExist) { - file_proxy_wrapper_->OpenFile( - TestFilePath(), base::Bind(&FileProxyWrapperLinuxTest::OpenFileCallback, - base::Unretained(this))); - scoped_task_environment_.RunUntilIdle(); - - ASSERT_TRUE(error_); - ASSERT_TRUE(error_->has_type()); - ASSERT_EQ(error_->type(), protocol::FileTransfer_Error_Type_IO_ERROR); -} - -} // namespace remoting
diff --git a/remoting/host/file_proxy_wrapper_mac.cc b/remoting/host/file_proxy_wrapper_mac.cc deleted file mode 100644 index e336e08e..0000000 --- a/remoting/host/file_proxy_wrapper_mac.cc +++ /dev/null
@@ -1,17 +0,0 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "remoting/host/file_proxy_wrapper.h" - -namespace remoting { - -// static -std::unique_ptr<FileProxyWrapper> FileProxyWrapper::Create() { - // TODO(jarhar): Implement FileProxyWrapper for mac. - // The Linux implementation may work, but has not been tested on mac. - NOTIMPLEMENTED(); - return nullptr; -} - -} // namespace remoting
diff --git a/remoting/host/file_proxy_wrapper_win.cc b/remoting/host/file_proxy_wrapper_win.cc deleted file mode 100644 index 5a6f3fef..0000000 --- a/remoting/host/file_proxy_wrapper_win.cc +++ /dev/null
@@ -1,16 +0,0 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "remoting/host/file_proxy_wrapper.h" - -namespace remoting { - -// static -std::unique_ptr<FileProxyWrapper> FileProxyWrapper::Create() { - // TODO(jarhar): Implement FileProxyWrapper for windows. - NOTIMPLEMENTED(); - return nullptr; -} - -} // namespace remoting
diff --git a/remoting/host/file_transfer/BUILD.gn b/remoting/host/file_transfer/BUILD.gn index 1ce9896..16b053a 100644 --- a/remoting/host/file_transfer/BUILD.gn +++ b/remoting/host/file_transfer/BUILD.gn
@@ -7,12 +7,14 @@ source_set("file_transfer") { public = [ "file_operations.h", + "file_transfer_message_handler.h", "local_file_operations.h", ] sources = [ "buffered_file_writer.cc", "buffered_file_writer.h", + "file_transfer_message_handler.cc", "local_file_operations.cc", ] @@ -29,6 +31,7 @@ "buffered_file_writer_unittest.cc", "fake_file_operations.cc", "fake_file_operations.h", + "file_transfer_message_handler_unittest.cc", "local_file_operations_unittest.cc", ]
diff --git a/remoting/host/file_transfer/buffered_file_writer.h b/remoting/host/file_transfer/buffered_file_writer.h index 88ecd219..62a9949 100644 --- a/remoting/host/file_transfer/buffered_file_writer.h +++ b/remoting/host/file_transfer/buffered_file_writer.h
@@ -24,7 +24,8 @@ // Constructor. // |on_error| may be called an any time if any operation fails. If no error // occurs, |on_complete| will be called after Close() has been called and all - // chunks have been successfully written. + // chunks have been successfully written. Callbacks will never be called after + // Cancel is called or BufferedFileWriter is destroyed. BufferedFileWriter( base::OnceClosure on_complete, base::OnceCallback<void(protocol::FileTransfer_Error)> on_error);
diff --git a/remoting/host/file_transfer/file_transfer_message_handler.cc b/remoting/host/file_transfer/file_transfer_message_handler.cc new file mode 100644 index 0000000..a4fd02f --- /dev/null +++ b/remoting/host/file_transfer/file_transfer_message_handler.cc
@@ -0,0 +1,188 @@ +// 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 "remoting/host/file_transfer/file_transfer_message_handler.h" + +#include "base/bind.h" +#include "base/path_service.h" +#include "base/stl_util.h" +#include "base/strings/stringprintf.h" +#include "net/base/filename_util.h" +#include "remoting/base/compound_buffer.h" +#include "remoting/protocol/file_transfer_helpers.h" +#include "url/gurl.h" + +namespace remoting { + +namespace { + +// Used if the provided filename can't be used. (E.g., if it is empty, or if +// it consists entirely of disallowed characters.) +constexpr char kDefaultFileName[] = "crd_transfer"; + +} // namespace + +FileTransferMessageHandler::FileTransferMessageHandler( + const std::string& name, + std::unique_ptr<protocol::MessagePipe> pipe, + std::unique_ptr<FileOperations> file_operations) + : protocol::NamedMessagePipeHandler(name, std::move(pipe)), + file_operations_(std::move(file_operations)) { + DCHECK(file_operations_); +} + +FileTransferMessageHandler::~FileTransferMessageHandler() = default; + +void FileTransferMessageHandler::OnConnected() {} + +void FileTransferMessageHandler::OnIncomingMessage( + std::unique_ptr<CompoundBuffer> buffer) { + protocol::FileTransfer message; + CompoundBufferInputStream buffer_stream(buffer.get()); + if (!message.ParseFromZeroCopyStream(&buffer_stream)) { + LOG(ERROR) << "Failed to parse message."; + CancelAndSendError(protocol::MakeFileTransferError( + FROM_HERE, protocol::FileTransfer_Error_Type_PROTOCOL_ERROR)); + return; + } + + if (message.has_metadata()) { + StartFile(std::move(*message.mutable_metadata())); + return; + } + + switch (state_) { + case kWriting: + // This is the expected state. + break; + case kFailed: + // Ignore any messages that come in after cancel or error. + return; + case kConnected: + // Don't send an error in response to an error. + if (!message.has_error()) { + LOG(ERROR) << "First message must contain file metadata"; + CancelAndSendError(protocol::MakeFileTransferError( + FROM_HERE, protocol::FileTransfer_Error_Type_PROTOCOL_ERROR)); + } + return; + case kClosed: + LOG(ERROR) << "Message received after End"; + CancelAndSendError(protocol::MakeFileTransferError( + FROM_HERE, protocol::FileTransfer_Error_Type_PROTOCOL_ERROR)); + return; + } + + switch (message.message_case()) { + case protocol::FileTransfer::kData: + Write(std::move(*message.mutable_data()->mutable_data())); + break; + case protocol::FileTransfer::kEnd: + Close(); + break; + case protocol::FileTransfer::kError: + LOG(ERROR) << "File transfer error from client: " << message.error(); + FALLTHROUGH; + case protocol::FileTransfer::kCancel: + Cancel(); + break; + default: + LOG(ERROR) << "Received invalid file-transfer message."; + CancelAndSendError(protocol::MakeFileTransferError( + FROM_HERE, protocol::FileTransfer_Error_Type_PROTOCOL_ERROR)); + break; + } +} + +void FileTransferMessageHandler::OnDisconnecting() {} + +void FileTransferMessageHandler::StartFile( + protocol::FileTransfer::Metadata metadata) { + if (state_ != kConnected) { + LOG(ERROR) << "Only one file per connection is supported."; + CancelAndSendError(protocol::MakeFileTransferError( + FROM_HERE, protocol::FileTransfer_Error_Type_PROTOCOL_ERROR)); + return; + } + + SetState(kWriting); + // Unretained is sound because the callbacks won't be called after + // BufferedFileWriter is destroyed, which is in turn owned by this + // FileTransferMessageHandler. + buffered_file_writer_.emplace( + base::BindOnce(&FileTransferMessageHandler::OnComplete, + base::Unretained(this)), + base::BindOnce(&FileTransferMessageHandler::OnError, + base::Unretained(this))); + buffered_file_writer_->Start( + file_operations_.get(), + // Ensure filename is safe, and convert from UTF-8 to a FilePath. + net::GenerateFileName(GURL(), std::string(), std::string(), + metadata.filename(), std::string(), + kDefaultFileName)); +} + +void FileTransferMessageHandler::Write(std::string data) { + DCHECK(state_ == kWriting); + buffered_file_writer_->Write(std::move(data)); +} + +void FileTransferMessageHandler::Close() { + DCHECK(state_ == kWriting); + SetState(kClosed); + buffered_file_writer_->Close(); +} + +void FileTransferMessageHandler::Cancel() { + SetState(kFailed); + // Will implicitly cancel if still in progress. + buffered_file_writer_.reset(); +} + +void FileTransferMessageHandler::OnComplete() { + SendResult(base::nullopt); // Success +} + +void FileTransferMessageHandler::OnError(protocol::FileTransfer_Error error) { + CancelAndSendError(std::move(error)); +} + +void FileTransferMessageHandler::SendResult( + base::Optional<protocol::FileTransfer_Error> error) { + protocol::FileTransfer result_message; + if (error) { + *result_message.mutable_error() = std::move(*error); + } else { + result_message.mutable_success(); + } + Send(result_message, base::Closure()); +} + +void FileTransferMessageHandler::CancelAndSendError( + protocol::FileTransfer_Error error) { + Cancel(); + SendResult(error); +} + +void FileTransferMessageHandler::SetState(State state) { + switch (state) { + case kConnected: + // This is the initial state, but should never be reached again. + NOTREACHED(); + break; + case kWriting: + DCHECK_EQ(kConnected, state_); + break; + case kClosed: + DCHECK_EQ(kWriting, state_); + break; + case kFailed: + // Any state can change to kFailed. + break; + } + + state_ = state; +} + +} // namespace remoting
diff --git a/remoting/host/file_transfer/file_transfer_message_handler.h b/remoting/host/file_transfer/file_transfer_message_handler.h new file mode 100644 index 0000000..9a8139be --- /dev/null +++ b/remoting/host/file_transfer/file_transfer_message_handler.h
@@ -0,0 +1,65 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef REMOTING_HOST_FILE_TRANSFER_FILE_TRANSFER_MESSAGE_HANDLER_H_ +#define REMOTING_HOST_FILE_TRANSFER_FILE_TRANSFER_MESSAGE_HANDLER_H_ + +#include <cstdint> +#include <memory> +#include <string> + +#include "base/containers/queue.h" +#include "base/memory/weak_ptr.h" +#include "base/optional.h" +#include "remoting/host/file_transfer/buffered_file_writer.h" +#include "remoting/host/file_transfer/file_operations.h" +#include "remoting/proto/file_transfer.pb.h" +#include "remoting/protocol/named_message_pipe_handler.h" + +namespace remoting { + +constexpr char kFileTransferDataChannelPrefix[] = "filetransfer-"; + +class FileTransferMessageHandler : public protocol::NamedMessagePipeHandler { + public: + FileTransferMessageHandler(const std::string& name, + std::unique_ptr<protocol::MessagePipe> pipe, + std::unique_ptr<FileOperations> file_operations); + ~FileTransferMessageHandler() override; + + // protocol::NamedMessagePipeHandler implementation. + void OnConnected() override; + void OnIncomingMessage(std::unique_ptr<CompoundBuffer> message) override; + void OnDisconnecting() override; + + private: + enum State { + // Initial state. + kConnected, + // We are writing a file. + kWriting, + // End states + // File successfully written. + kClosed, + // An error occured or the transfer was canceled. + kFailed, + }; + void StartFile(protocol::FileTransfer_Metadata metadata); + void Write(std::string data); + void Close(); + void Cancel(); + void OnComplete(); + void OnError(protocol::FileTransfer_Error error); + void SendResult(base::Optional<protocol::FileTransfer_Error> error); + void CancelAndSendError(protocol::FileTransfer_Error error); + void SetState(State state); + + State state_ = kConnected; + std::unique_ptr<FileOperations> file_operations_; + base::Optional<BufferedFileWriter> buffered_file_writer_; +}; + +} // namespace remoting + +#endif // REMOTING_HOST_FILE_TRANSFER_FILE_TRANSFER_MESSAGE_HANDLER_H_
diff --git a/remoting/host/file_transfer/file_transfer_message_handler_unittest.cc b/remoting/host/file_transfer/file_transfer_message_handler_unittest.cc new file mode 100644 index 0000000..f32204e --- /dev/null +++ b/remoting/host/file_transfer/file_transfer_message_handler_unittest.cc
@@ -0,0 +1,334 @@ +// 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 "remoting/host/file_transfer/file_transfer_message_handler.h" + +#include <memory> +#include <string> +#include <utility> +#include <vector> + +#include "base/bind.h" +#include "base/containers/queue.h" +#include "base/memory/ptr_util.h" +#include "base/test/scoped_task_environment.h" +#include "base/threading/sequenced_task_runner_handle.h" +#include "net/base/io_buffer.h" +#include "remoting/base/compound_buffer.h" +#include "remoting/host/file_transfer/fake_file_operations.h" +#include "remoting/protocol/fake_message_pipe.h" +#include "remoting/protocol/fake_message_pipe_wrapper.h" +#include "remoting/protocol/file_transfer_helpers.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace { + +constexpr char kTestDatachannelName[] = "filetransfer-test"; +constexpr char kTestFilename[] = "test-file.txt"; + +std::unique_ptr<remoting::CompoundBuffer> StringToBuffer( + const std::string& data) { + std::unique_ptr<remoting::CompoundBuffer> buffer = + std::make_unique<remoting::CompoundBuffer>(); + buffer->Append(base::MakeRefCounted<net::StringIOBuffer>(data.data()), + data.size()); + return buffer; +} + +std::unique_ptr<remoting::CompoundBuffer> MessageToBuffer( + const remoting::protocol::FileTransfer& message) { + return StringToBuffer(message.SerializeAsString()); +} + +std::unique_ptr<remoting::CompoundBuffer> DataToBuffer( + const std::string& data) { + remoting::protocol::FileTransfer message; + message.mutable_data()->set_data(data); + return MessageToBuffer(message); +} + +// base::queue doesn't provide operator==. +template <typename T> +bool QueuesEqual(const base::queue<T>& a, const base::queue<T>& b) { + if (a.size() != b.size()) + return false; + + auto a_copy = a; + auto b_copy = b; + while (!a_copy.empty()) { + if (a_copy.front() != b_copy.front()) + return false; + a_copy.pop(); + b_copy.pop(); + } + return true; +} + +} // namespace + +namespace remoting { + +class FileTransferMessageHandlerTest : public testing::Test { + public: + FileTransferMessageHandlerTest(); + ~FileTransferMessageHandlerTest() override; + + // testing::Test implementation. + void SetUp() override; + void TearDown() override; + + protected: + const std::string kTestDataOne = "this is the first test string"; + const std::string kTestDataTwo = "this is the second test string"; + const std::string kTestDataThree = "this is the third test string"; + + base::test::ScopedTaskEnvironment scoped_task_environment_; + std::unique_ptr<protocol::FakeMessagePipe> fake_pipe_; + protocol::FileTransfer fake_metadata_; + protocol::FileTransfer fake_end_; +}; + +FileTransferMessageHandlerTest::FileTransferMessageHandlerTest() + : scoped_task_environment_( + base::test::ScopedTaskEnvironment::MainThreadType::DEFAULT, + base::test::ScopedTaskEnvironment::ExecutionMode::QUEUED) {} +FileTransferMessageHandlerTest::~FileTransferMessageHandlerTest() = default; + +void FileTransferMessageHandlerTest::SetUp() { + fake_pipe_ = + base::WrapUnique(new protocol::FakeMessagePipe(false /* asynchronous */)); + + fake_metadata_.Clear(); + fake_metadata_.mutable_metadata()->set_filename(kTestFilename); + fake_metadata_.mutable_metadata()->set_size( + kTestDataOne.size() + kTestDataTwo.size() + kTestDataThree.size()); + fake_end_.Clear(); + fake_end_.mutable_end(); +} + +void FileTransferMessageHandlerTest::TearDown() {} + +// Verify that the message handler creates, writes to, and closes a +// FileProxyWrapper without errors when given valid input. +TEST_F(FileTransferMessageHandlerTest, WritesThreeChunks) { + FakeFileOperations::TestIo test_io; + auto file_operations = std::make_unique<FakeFileOperations>(&test_io); + + // This will delete itself when fake_pipe_->ClosePipe() is called. + new FileTransferMessageHandler(kTestDatachannelName, fake_pipe_->Wrap(), + std::move(file_operations)); + + fake_pipe_->OpenPipe(); + fake_pipe_->Receive(MessageToBuffer(fake_metadata_)); + fake_pipe_->Receive(DataToBuffer(kTestDataOne)); + fake_pipe_->Receive(DataToBuffer(kTestDataTwo)); + fake_pipe_->Receive(DataToBuffer(kTestDataThree)); + fake_pipe_->Receive(MessageToBuffer(fake_end_)); + scoped_task_environment_.RunUntilIdle(); + + fake_pipe_->ClosePipe(); + + ASSERT_EQ(1ul, test_io.files_written.size()); + ASSERT_EQ(false, test_io.files_written[0].failed); + std::vector<std::string> expected_chunks = {kTestDataOne, kTestDataTwo, + kTestDataThree}; + ASSERT_EQ(expected_chunks, test_io.files_written[0].chunks); + + const base::queue<std::string>& actual_sent_messages = + fake_pipe_->sent_messages(); + protocol::FileTransfer expected_response; + expected_response.mutable_success(); + base::queue<std::string> expected_sent_messages; + expected_sent_messages.push(expected_response.SerializeAsString()); + ASSERT_TRUE(QueuesEqual(expected_sent_messages, actual_sent_messages)); +} + +// Verifies that the message handler sends an error protobuf when +// FileProxyWrapper returns an error. +TEST_F(FileTransferMessageHandlerTest, HandlesWriteError) { + FakeFileOperations::TestIo test_io; + auto file_operations = std::make_unique<FakeFileOperations>(&test_io); + + protocol::FileTransfer_Error fake_error = protocol::MakeFileTransferError( + FROM_HERE, protocol::FileTransfer_Error_Type_IO_ERROR); + + // This will delete itself when fake_pipe_->ClosePipe() is called. + new FileTransferMessageHandler(kTestDatachannelName, fake_pipe_->Wrap(), + std::move(file_operations)); + + fake_pipe_->OpenPipe(); + fake_pipe_->Receive(MessageToBuffer(fake_metadata_)); + fake_pipe_->Receive(DataToBuffer(kTestDataOne)); + fake_pipe_->Receive(DataToBuffer(kTestDataTwo)); + scoped_task_environment_.RunUntilIdle(); + test_io.io_error = fake_error; + fake_pipe_->Receive(DataToBuffer(kTestDataTwo)); + fake_pipe_->Receive(MessageToBuffer(fake_end_)); + scoped_task_environment_.RunUntilIdle(); + + fake_pipe_->ClosePipe(); + + const base::queue<std::string>& actual_sent_messages = + fake_pipe_->sent_messages(); + protocol::FileTransfer expected_response; + *expected_response.mutable_error() = fake_error; + base::queue<std::string> expected_sent_messages; + expected_sent_messages.push(expected_response.SerializeAsString()); + ASSERT_TRUE(QueuesEqual(expected_sent_messages, actual_sent_messages)); +} + +// Verifies that the message handler cancels the write if an error is received +// from the sender. +TEST_F(FileTransferMessageHandlerTest, HandlesErrorMessage) { + FakeFileOperations::TestIo test_io; + auto file_operations = std::make_unique<FakeFileOperations>(&test_io); + + // This will delete itself when fake_pipe_->ClosePipe() is called. + new FileTransferMessageHandler(kTestDatachannelName, fake_pipe_->Wrap(), + std::move(file_operations)); + + protocol::FileTransfer fake_error_message; + *fake_error_message.mutable_error() = protocol::MakeFileTransferError( + FROM_HERE, protocol::FileTransfer_Error_Type_IO_ERROR); + + fake_pipe_->OpenPipe(); + fake_pipe_->Receive(MessageToBuffer(fake_metadata_)); + fake_pipe_->Receive(DataToBuffer(kTestDataOne)); + fake_pipe_->Receive(DataToBuffer(kTestDataTwo)); + scoped_task_environment_.RunUntilIdle(); + fake_pipe_->Receive(MessageToBuffer(fake_error_message)); + scoped_task_environment_.RunUntilIdle(); + + fake_pipe_->ClosePipe(); + + ASSERT_EQ(1ul, test_io.files_written.size()); + ASSERT_EQ(true, test_io.files_written[0].failed); + std::vector<std::string> expected_chunks = {kTestDataOne, kTestDataTwo}; + ASSERT_EQ(expected_chunks, test_io.files_written[0].chunks); + + const base::queue<std::string>& actual_sent_messages = + fake_pipe_->sent_messages(); + // No messages + base::queue<std::string> expected_sent_messages; + ASSERT_TRUE(QueuesEqual(expected_sent_messages, actual_sent_messages)); +} + +// Verifies that the message handler cancels the write if the connection is +// closed prematurely. +TEST_F(FileTransferMessageHandlerTest, HandlesPrematureClose) { + FakeFileOperations::TestIo test_io; + auto file_operations = std::make_unique<FakeFileOperations>(&test_io); + + // This will delete itself when fake_pipe_->ClosePipe() is called. + new FileTransferMessageHandler(kTestDatachannelName, fake_pipe_->Wrap(), + std::move(file_operations)); + + fake_pipe_->OpenPipe(); + fake_pipe_->Receive(MessageToBuffer(fake_metadata_)); + fake_pipe_->Receive(DataToBuffer(kTestDataOne)); + fake_pipe_->Receive(DataToBuffer(kTestDataTwo)); + scoped_task_environment_.RunUntilIdle(); + + fake_pipe_->ClosePipe(); + + ASSERT_EQ(1ul, test_io.files_written.size()); + ASSERT_EQ(true, test_io.files_written[0].failed); + std::vector<std::string> expected_chunks = {kTestDataOne, kTestDataTwo}; + ASSERT_EQ(expected_chunks, test_io.files_written[0].chunks); +} + +// Verifies that an error is sent if data is sent before/without metadata. +TEST_F(FileTransferMessageHandlerTest, ErrorsOnMissingMetadata) { + FakeFileOperations::TestIo test_io; + auto file_operations = std::make_unique<FakeFileOperations>(&test_io); + + // This will delete itself when fake_pipe_->ClosePipe() is called. + new FileTransferMessageHandler(kTestDatachannelName, fake_pipe_->Wrap(), + std::move(file_operations)); + + fake_pipe_->OpenPipe(); + fake_pipe_->Receive(DataToBuffer(kTestDataOne)); + fake_pipe_->Receive(DataToBuffer(kTestDataTwo)); + fake_pipe_->Receive(DataToBuffer(kTestDataThree)); + fake_pipe_->Receive(MessageToBuffer(fake_end_)); + scoped_task_environment_.RunUntilIdle(); + + fake_pipe_->ClosePipe(); + + ASSERT_EQ(0ul, test_io.files_written.size()); + + const base::queue<std::string>& sent_messages = fake_pipe_->sent_messages(); + ASSERT_EQ(1ul, sent_messages.size()); + protocol::FileTransfer response; + response.ParseFromString(sent_messages.front()); + ASSERT_EQ(protocol::FileTransfer::kError, response.message_case()); + ASSERT_EQ(protocol::FileTransfer_Error_Type_PROTOCOL_ERROR, + response.error().type()); +} + +// Verifies that an error is sent if another metadata message is sent. +TEST_F(FileTransferMessageHandlerTest, ErrorsOnNewMetadata) { + FakeFileOperations::TestIo test_io; + auto file_operations = std::make_unique<FakeFileOperations>(&test_io); + + // This will delete itself when fake_pipe_->ClosePipe() is called. + new FileTransferMessageHandler(kTestDatachannelName, fake_pipe_->Wrap(), + std::move(file_operations)); + + fake_pipe_->OpenPipe(); + fake_pipe_->Receive(MessageToBuffer(fake_metadata_)); + fake_pipe_->Receive(DataToBuffer(kTestDataOne)); + fake_pipe_->Receive(DataToBuffer(kTestDataTwo)); + fake_pipe_->Receive(DataToBuffer(kTestDataThree)); + fake_pipe_->Receive(MessageToBuffer(fake_end_)); + scoped_task_environment_.RunUntilIdle(); + fake_pipe_->Receive(MessageToBuffer(fake_metadata_)); + + fake_pipe_->ClosePipe(); + + const base::queue<std::string>& sent_messages = fake_pipe_->sent_messages(); + // First is the sucess message, second should be a protocol error. + ASSERT_EQ(2ul, sent_messages.size()); + protocol::FileTransfer response; + response.ParseFromString(sent_messages.back()); + ASSERT_EQ(protocol::FileTransfer::kError, response.message_case()); + ASSERT_EQ(protocol::FileTransfer_Error_Type_PROTOCOL_ERROR, + response.error().type()); +} + +// Verifies that an error is sent if more data is sent after Close. +TEST_F(FileTransferMessageHandlerTest, ErrorsOnDataAfterClose) { + FakeFileOperations::TestIo test_io; + auto file_operations = std::make_unique<FakeFileOperations>(&test_io); + + // This will delete itself when fake_pipe_->ClosePipe() is called. + new FileTransferMessageHandler(kTestDatachannelName, fake_pipe_->Wrap(), + std::move(file_operations)); + + fake_pipe_->OpenPipe(); + fake_pipe_->Receive(MessageToBuffer(fake_metadata_)); + fake_pipe_->Receive(DataToBuffer(kTestDataOne)); + fake_pipe_->Receive(DataToBuffer(kTestDataTwo)); + fake_pipe_->Receive(DataToBuffer(kTestDataThree)); + fake_pipe_->Receive(MessageToBuffer(fake_end_)); + fake_pipe_->Receive(DataToBuffer(kTestDataOne)); + scoped_task_environment_.RunUntilIdle(); + + fake_pipe_->ClosePipe(); + + ASSERT_EQ(1ul, test_io.files_written.size()); + ASSERT_EQ(true, test_io.files_written[0].failed); + + const base::queue<std::string>& sent_messages = fake_pipe_->sent_messages(); + // Because the error is triggered before RunUntilIdle is called, there should + // be no complete message this time. + ASSERT_EQ(1ul, sent_messages.size()); + protocol::FileTransfer response; + response.ParseFromString(sent_messages.front()); + ASSERT_EQ(protocol::FileTransfer::kError, response.message_case()); + ASSERT_EQ(protocol::FileTransfer_Error_Type_PROTOCOL_ERROR, + response.error().type()); +} + +} // namespace remoting
diff --git a/remoting/host/file_transfer/local_file_operations.cc b/remoting/host/file_transfer/local_file_operations.cc index 4f85428..77639032 100644 --- a/remoting/host/file_transfer/local_file_operations.cc +++ b/remoting/host/file_transfer/local_file_operations.cc
@@ -24,7 +24,7 @@ namespace { -constexpr char kTempFileExtension[] = ".crdownload"; +constexpr char kTempFileExtension[] = ".part"; remoting::protocol::FileTransfer_Error_Type FileErrorToResponseErrorType( base::File::Error file_error) {
diff --git a/remoting/host/file_transfer_message_handler.cc b/remoting/host/file_transfer_message_handler.cc deleted file mode 100644 index b8f2365..0000000 --- a/remoting/host/file_transfer_message_handler.cc +++ /dev/null
@@ -1,153 +0,0 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "remoting/host/file_transfer_message_handler.h" - -#include "base/bind.h" -#include "base/path_service.h" -#include "base/stl_util.h" -#include "base/strings/stringprintf.h" -#include "remoting/base/compound_buffer.h" -#include "remoting/protocol/file_transfer_helpers.h" - -namespace remoting { - -FileTransferMessageHandler::FileTransferMessageHandler( - const std::string& name, - std::unique_ptr<protocol::MessagePipe> pipe, - std::unique_ptr<FileProxyWrapper> file_proxy_wrapper) - : protocol::NamedMessagePipeHandler(name, std::move(pipe)), - file_proxy_wrapper_(std::move(file_proxy_wrapper)) { - DCHECK(file_proxy_wrapper_); -} - -FileTransferMessageHandler::~FileTransferMessageHandler() = default; - -void FileTransferMessageHandler::OnConnected() { - // base::Unretained is safe here because |file_proxy_wrapper_| is owned by - // this class, so the callback cannot be run after this class is destroyed. - file_proxy_wrapper_->Init(base::BindOnce( - &FileTransferMessageHandler::SaveResultCallback, base::Unretained(this))); -} - -void FileTransferMessageHandler::OnIncomingMessage( - std::unique_ptr<CompoundBuffer> buffer) { - protocol::FileTransfer message; - CompoundBufferInputStream buffer_stream(buffer.get()); - if (!message.ParseFromZeroCopyStream(&buffer_stream)) { - CancelAndSendError( - protocol::MakeFileTransferError( - FROM_HERE, protocol::FileTransfer_Error_Type_PROTOCOL_ERROR), - "Failed to parse message."); - return; - } - - if (message.has_metadata()) { - StartFile(std::move(*message.mutable_metadata())); - return; - } - - switch (file_proxy_wrapper_->state()) { - case FileProxyWrapper::kReady: - // This is the expected state. - break; - case FileProxyWrapper::kFailed: - // Ignore any messages that come in after we've returned an error. - return; - case FileProxyWrapper::kInitialized: - // Don't send an error in response to an error. - if (!message.has_error()) { - CancelAndSendError( - protocol::MakeFileTransferError( - FROM_HERE, protocol::FileTransfer_Error_Type_PROTOCOL_ERROR), - "First message must contain file metadata"); - } - return; - case FileProxyWrapper::kBusy: - case FileProxyWrapper::kClosed: - CancelAndSendError( - protocol::MakeFileTransferError( - FROM_HERE, protocol::FileTransfer_Error_Type_PROTOCOL_ERROR), - "Message received after End"); - return; - default: - CancelAndSendError( - protocol::MakeFileTransferError( - FROM_HERE, protocol::FileTransfer_Error_Type_UNEXPECTED_ERROR), - base::StringPrintf("Unexpected FileProxyWrapper state: %d", - file_proxy_wrapper_->state())); - return; - } - - switch (message.message_case()) { - case protocol::FileTransfer::kData: - file_proxy_wrapper_->WriteChunk( - std::move(*message.mutable_data()->mutable_data())); - break; - case protocol::FileTransfer::kEnd: - file_proxy_wrapper_->Close(); - break; - case protocol::FileTransfer::kCancel: - case protocol::FileTransfer::kError: - file_proxy_wrapper_->Cancel(); - break; - default: - CancelAndSendError( - protocol::MakeFileTransferError( - FROM_HERE, protocol::FileTransfer_Error_Type_PROTOCOL_ERROR), - "Received invalid file-transfer message."); - break; - } -} - -void FileTransferMessageHandler::OnDisconnecting() { - FileProxyWrapper::State proxy_state = file_proxy_wrapper_->state(); - if (proxy_state != FileProxyWrapper::kClosed && - proxy_state != FileProxyWrapper::kFailed) { - // Channel was closed earlier than expected, cancel the transfer. - file_proxy_wrapper_->Cancel(); - } -} - -void FileTransferMessageHandler::SaveResultCallback( - base::Optional<protocol::FileTransfer_Error> error) { - protocol::FileTransfer result_message; - if (error) { - *result_message.mutable_error() = std::move(*error); - } else { - result_message.mutable_success(); - } - Send(result_message, base::Closure()); -} - -void FileTransferMessageHandler::StartFile( - protocol::FileTransfer::Metadata metadata) { - if (file_proxy_wrapper_->state() != FileProxyWrapper::kInitialized) { - CancelAndSendError( - protocol::MakeFileTransferError( - FROM_HERE, protocol::FileTransfer_Error_Type_PROTOCOL_ERROR), - "Only one file per connection is supported."); - return; - } - - base::FilePath target_directory; - if (!base::PathService::Get(base::DIR_USER_DESKTOP, &target_directory)) { - CancelAndSendError( - protocol::MakeFileTransferError( - FROM_HERE, protocol::FileTransfer_Error_Type_UNEXPECTED_ERROR), - "Failed to get DIR_USER_DESKTOP from base::PathService::Get"); - return; - } - file_proxy_wrapper_->CreateFile(target_directory, metadata.filename()); -} - -void FileTransferMessageHandler::CancelAndSendError( - protocol::FileTransfer_Error error, - const std::string& log_message) { - LOG(ERROR) << log_message; - file_proxy_wrapper_->Cancel(); - SaveResultCallback(error); -} - -} // namespace remoting
diff --git a/remoting/host/file_transfer_message_handler.h b/remoting/host/file_transfer_message_handler.h deleted file mode 100644 index 84b20ff3..0000000 --- a/remoting/host/file_transfer_message_handler.h +++ /dev/null
@@ -1,44 +0,0 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef REMOTING_HOST_FILE_TRANSFER_MESSAGE_HANDLER_H_ -#define REMOTING_HOST_FILE_TRANSFER_MESSAGE_HANDLER_H_ - -#include <cstdint> -#include <memory> -#include <string> - -#include "base/optional.h" -#include "remoting/host/file_proxy_wrapper.h" -#include "remoting/proto/file_transfer.pb.h" -#include "remoting/protocol/named_message_pipe_handler.h" - -namespace remoting { - -constexpr char kFileTransferDataChannelPrefix[] = "filetransfer-"; - -class FileTransferMessageHandler : public protocol::NamedMessagePipeHandler { - public: - FileTransferMessageHandler(const std::string& name, - std::unique_ptr<protocol::MessagePipe> pipe, - std::unique_ptr<FileProxyWrapper> file_proxy); - ~FileTransferMessageHandler() override; - - // protocol::NamedMessagePipeHandler implementation. - void OnConnected() override; - void OnIncomingMessage(std::unique_ptr<CompoundBuffer> message) override; - void OnDisconnecting() override; - - private: - void SaveResultCallback(base::Optional<protocol::FileTransfer_Error> error); - void StartFile(protocol::FileTransfer_Metadata metadata); - void CancelAndSendError(protocol::FileTransfer_Error error, - const std::string& log_message); - - std::unique_ptr<FileProxyWrapper> file_proxy_wrapper_; -}; - -} // namespace remoting - -#endif // REMOTING_HOST_FILE_TRANSFER_MESSAGE_HANDLER_H_
diff --git a/remoting/host/file_transfer_message_handler_unittest.cc b/remoting/host/file_transfer_message_handler_unittest.cc deleted file mode 100644 index 0d22e7f..0000000 --- a/remoting/host/file_transfer_message_handler_unittest.cc +++ /dev/null
@@ -1,271 +0,0 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "remoting/host/file_transfer_message_handler.h" - -#include <memory> -#include <string> -#include <utility> -#include <vector> - -#include "base/bind.h" -#include "base/containers/queue.h" -#include "base/memory/ptr_util.h" -#include "net/base/io_buffer.h" -#include "remoting/base/compound_buffer.h" -#include "remoting/host/file_proxy_wrapper.h" -#include "remoting/protocol/fake_message_pipe.h" -#include "remoting/protocol/fake_message_pipe_wrapper.h" -#include "remoting/protocol/file_transfer_helpers.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace { - -constexpr char kTestDatachannelName[] = "filetransfer-test"; -constexpr char kTestFilename[] = "test-file.txt"; - -std::unique_ptr<remoting::CompoundBuffer> StringToBuffer( - const std::string& data) { - std::unique_ptr<remoting::CompoundBuffer> buffer = - std::make_unique<remoting::CompoundBuffer>(); - buffer->Append(base::MakeRefCounted<net::StringIOBuffer>(data.data()), - data.size()); - return buffer; -} - -std::unique_ptr<remoting::CompoundBuffer> MessageToBuffer( - const remoting::protocol::FileTransfer& message) { - return StringToBuffer(message.SerializeAsString()); -} - -std::unique_ptr<remoting::CompoundBuffer> DataToBuffer( - const std::string& data) { - remoting::protocol::FileTransfer message; - message.mutable_data()->set_data(data); - return MessageToBuffer(message); -} - -// base::queue doesn't provide operator==. -template <typename T> -bool QueuesEqual(const base::queue<T>& a, const base::queue<T>& b) { - if (a.size() != b.size()) - return false; - - auto a_copy = a; - auto b_copy = b; - while (!a_copy.empty()) { - if (a_copy.front() != b_copy.front()) - return false; - a_copy.pop(); - b_copy.pop(); - } - return true; -} - -} // namespace - -namespace remoting { - -class FakeFileProxyWrapper : public FileProxyWrapper { - public: - FakeFileProxyWrapper(); - ~FakeFileProxyWrapper() override; - - // FileProxyWrapper implementation. - void Init(ResultCallback result_callback) override; - void CreateFile(const base::FilePath& directory, - const std::string& filename) override; - void OpenFile(const base::FilePath& filepath, - OpenFileCallback open_callback) override; - void WriteChunk(std::string buffer) override; - void ReadChunk(uint64_t chunk_size, ReadCallback read_callback) override; - void Close() override; - void Cancel() override; - State state() override; - - void RunResultCallback(base::Optional<protocol::FileTransfer_Error> error); - const std::string& filename(); - base::queue<std::string> chunks(); - - private: - State state_ = kUninitialized; - ResultCallback result_callback_; - std::string filename_; - base::queue<std::string> chunks_; -}; - -class FileTransferMessageHandlerTest : public testing::Test { - public: - FileTransferMessageHandlerTest(); - ~FileTransferMessageHandlerTest() override; - - // testing::Test implementation. - void SetUp() override; - void TearDown() override; - - protected: - const std::string kTestDataOne = "this is the first test string"; - const std::string kTestDataTwo = "this is the second test string"; - - std::unique_ptr<protocol::FakeMessagePipe> fake_pipe_; - protocol::FileTransfer fake_metadata_; - protocol::FileTransfer fake_end_; -}; - -FakeFileProxyWrapper::FakeFileProxyWrapper() = default; -FakeFileProxyWrapper::~FakeFileProxyWrapper() = default; - -void FakeFileProxyWrapper::Init(ResultCallback result_callback) { - ASSERT_EQ(state_, kUninitialized); - state_ = kInitialized; - - result_callback_ = std::move(result_callback); -} - -void FakeFileProxyWrapper::CreateFile(const base::FilePath& directory, - const std::string& filename) { - ASSERT_EQ(state_, kInitialized); - state_ = kReady; - - filename_ = filename; -} - -void FakeFileProxyWrapper::OpenFile(const base::FilePath& filepath, - OpenFileCallback open_callback) { - ASSERT_EQ(state_, kInitialized); - state_ = kReady; - - // TODO(jarhar): Implement fake file reading. -} - -void FakeFileProxyWrapper::WriteChunk(std::string buffer) { - ASSERT_EQ(state_, kReady); - - chunks_.push(std::move(buffer)); -} - -void FakeFileProxyWrapper::ReadChunk(uint64_t chunk_size, - ReadCallback read_callback) { - ASSERT_EQ(state_, kReady); - - // TODO(jarhar): Implement fake file reading. -} - -void FakeFileProxyWrapper::Close() { - ASSERT_EQ(state_, kReady); - state_ = kClosed; -} - -void FakeFileProxyWrapper::Cancel() { - state_ = kFailed; -} - -FileProxyWrapper::State FakeFileProxyWrapper::state() { - return state_; -} - -void FakeFileProxyWrapper::RunResultCallback( - base::Optional<protocol::FileTransfer_Error> error) { - std::move(result_callback_).Run(std::move(error)); -} - -const std::string& FakeFileProxyWrapper::filename() { - return filename_; -} - -base::queue<std::string> FakeFileProxyWrapper::chunks() { - return chunks_; -} - -FileTransferMessageHandlerTest::FileTransferMessageHandlerTest() = default; -FileTransferMessageHandlerTest::~FileTransferMessageHandlerTest() = default; - -void FileTransferMessageHandlerTest::SetUp() { - fake_pipe_ = - base::WrapUnique(new protocol::FakeMessagePipe(false /* asynchronous */)); - - fake_metadata_.Clear(); - fake_metadata_.mutable_metadata()->set_filename(kTestFilename); - fake_metadata_.mutable_metadata()->set_size(kTestDataOne.size() + - kTestDataTwo.size()); - fake_end_.Clear(); - fake_end_.mutable_end(); -} - -void FileTransferMessageHandlerTest::TearDown() {} - -// Verify that the message handler creates, writes to, and closes a -// FileProxyWrapper without errors when given valid input. -TEST_F(FileTransferMessageHandlerTest, WriteTwoChunks) { - std::unique_ptr<FakeFileProxyWrapper> file_proxy_wrapper = - std::make_unique<FakeFileProxyWrapper>(); - // |file_proxy_wrapper_ptr| is valid until fake_pipe_->ClosePipe() is called. - FakeFileProxyWrapper* file_proxy_wrapper_ptr = file_proxy_wrapper.get(); - - // This will delete itself when fake_pipe_->ClosePipe() is called. - new FileTransferMessageHandler(kTestDatachannelName, fake_pipe_->Wrap(), - std::move(file_proxy_wrapper)); - - fake_pipe_->OpenPipe(); - fake_pipe_->Receive(MessageToBuffer(fake_metadata_)); - fake_pipe_->Receive(DataToBuffer(kTestDataOne)); - fake_pipe_->Receive(DataToBuffer(kTestDataTwo)); - fake_pipe_->Receive(MessageToBuffer(fake_end_)); - - file_proxy_wrapper_ptr->RunResultCallback(base::nullopt); - - base::queue<std::string> actual_chunks = file_proxy_wrapper_ptr->chunks(); - - fake_pipe_->ClosePipe(); - file_proxy_wrapper_ptr = nullptr; - - base::queue<std::string> expected_chunks; - expected_chunks.push(kTestDataOne); - expected_chunks.push(kTestDataTwo); - ASSERT_TRUE(QueuesEqual(expected_chunks, actual_chunks)); - - const base::queue<std::string>& actual_sent_messages = - fake_pipe_->sent_messages(); - protocol::FileTransfer expected_response; - expected_response.mutable_success(); - base::queue<std::string> expected_sent_messages; - expected_sent_messages.push(expected_response.SerializeAsString()); - ASSERT_TRUE(QueuesEqual(expected_sent_messages, actual_sent_messages)); -} - -// Verifies that the message handler sends an error protobuf when -// FileProxyWrapper returns an error. -TEST_F(FileTransferMessageHandlerTest, FileProxyError) { - std::unique_ptr<FakeFileProxyWrapper> file_proxy_wrapper = - std::make_unique<FakeFileProxyWrapper>(); - // |file_proxy_wrapper_ptr| is valid until fake_pipe_->ClosePipe() is called. - FakeFileProxyWrapper* file_proxy_wrapper_ptr = file_proxy_wrapper.get(); - - protocol::FileTransfer_Error fake_error = protocol::MakeFileTransferError( - FROM_HERE, protocol::FileTransfer_Error_Type_IO_ERROR); - - // This will delete itself when fake_pipe_->ClosePipe() is called. - new FileTransferMessageHandler(kTestDatachannelName, fake_pipe_->Wrap(), - std::move(file_proxy_wrapper)); - - fake_pipe_->OpenPipe(); - fake_pipe_->Receive(MessageToBuffer(fake_metadata_)); - fake_pipe_->Receive(DataToBuffer(kTestDataOne)); - - file_proxy_wrapper_ptr->Cancel(); - file_proxy_wrapper_ptr->RunResultCallback(fake_error); - - fake_pipe_->ClosePipe(); - file_proxy_wrapper_ptr = nullptr; - - const base::queue<std::string>& actual_sent_messages = - fake_pipe_->sent_messages(); - protocol::FileTransfer expected_response; - *expected_response.mutable_error() = fake_error; - base::queue<std::string> expected_sent_messages; - expected_sent_messages.push(expected_response.SerializeAsString()); - ASSERT_TRUE(QueuesEqual(expected_sent_messages, actual_sent_messages)); -} - -} // namespace remoting
diff --git a/remoting/host/host_mock_objects.cc b/remoting/host/host_mock_objects.cc index 8cda071..f6eb2cee4 100644 --- a/remoting/host/host_mock_objects.cc +++ b/remoting/host/host_mock_objects.cc
@@ -11,7 +11,7 @@ #include "remoting/codec/audio_encoder.h" #include "remoting/codec/video_encoder.h" #include "remoting/host/audio_capturer.h" -#include "remoting/host/file_proxy_wrapper.h" +#include "remoting/host/file_transfer/file_operations.h" #include "remoting/host/input_injector.h" #include "remoting/proto/event.pb.h" #include "remoting/proto/video.pb.h" @@ -51,9 +51,8 @@ return base::WrapUnique(CreateMouseCursorMonitorPtr()); } -std::unique_ptr<FileProxyWrapper> -MockDesktopEnvironment::CreateFileProxyWrapper() { - return base::WrapUnique(CreateFileProxyWrapperPtr()); +std::unique_ptr<FileOperations> MockDesktopEnvironment::CreateFileOperations() { + return base::WrapUnique(CreateFileOperationsPtr()); } MockDesktopEnvironmentFactory::MockDesktopEnvironmentFactory() = default;
diff --git a/remoting/host/host_mock_objects.h b/remoting/host/host_mock_objects.h index d43dcc4..851a5be 100644 --- a/remoting/host/host_mock_objects.h +++ b/remoting/host/host_mock_objects.h
@@ -45,7 +45,7 @@ MOCK_METHOD0(CreateScreenControlsPtr, ScreenControls*()); MOCK_METHOD0(CreateVideoCapturerPtr, webrtc::DesktopCapturer*()); MOCK_METHOD0(CreateMouseCursorMonitorPtr, webrtc::MouseCursorMonitor*()); - MOCK_METHOD0(CreateFileProxyWrapperPtr, FileProxyWrapper*()); + MOCK_METHOD0(CreateFileOperationsPtr, FileOperations*()); MOCK_CONST_METHOD0(GetCapabilities, std::string()); MOCK_METHOD1(SetCapabilities, void(const std::string&)); MOCK_CONST_METHOD0(GetDesktopSessionId, uint32_t()); @@ -58,7 +58,7 @@ std::unique_ptr<webrtc::DesktopCapturer> CreateVideoCapturer() override; std::unique_ptr<webrtc::MouseCursorMonitor> CreateMouseCursorMonitor() override; - std::unique_ptr<FileProxyWrapper> CreateFileProxyWrapper() override; + std::unique_ptr<FileOperations> CreateFileOperations() override; }; class MockClientSessionControl : public ClientSessionControl {
diff --git a/remoting/host/ipc_desktop_environment.cc b/remoting/host/ipc_desktop_environment.cc index 874cd02..ba6d0b5 100644 --- a/remoting/host/ipc_desktop_environment.cc +++ b/remoting/host/ipc_desktop_environment.cc
@@ -19,7 +19,7 @@ #include "remoting/host/client_session_control.h" #include "remoting/host/desktop_session.h" #include "remoting/host/desktop_session_proxy.h" -#include "remoting/host/file_proxy_wrapper.h" +#include "remoting/host/file_transfer/file_operations.h" #include "remoting/host/input_injector.h" #include "remoting/host/screen_controls.h" #include "third_party/webrtc/modules/desktop_capture/desktop_capturer.h" @@ -69,9 +69,9 @@ return desktop_session_proxy_->CreateVideoCapturer(); } -std::unique_ptr<FileProxyWrapper> -IpcDesktopEnvironment::CreateFileProxyWrapper() { - return FileProxyWrapper::Create(); +std::unique_ptr<FileOperations> IpcDesktopEnvironment::CreateFileOperations() { + NOTIMPLEMENTED(); + return nullptr; } std::string IpcDesktopEnvironment::GetCapabilities() const {
diff --git a/remoting/host/ipc_desktop_environment.h b/remoting/host/ipc_desktop_environment.h index 9d87469d..b76fe4b8 100644 --- a/remoting/host/ipc_desktop_environment.h +++ b/remoting/host/ipc_desktop_environment.h
@@ -56,7 +56,7 @@ std::unique_ptr<webrtc::DesktopCapturer> CreateVideoCapturer() override; std::unique_ptr<webrtc::MouseCursorMonitor> CreateMouseCursorMonitor() override; - std::unique_ptr<FileProxyWrapper> CreateFileProxyWrapper() override; + std::unique_ptr<FileOperations> CreateFileOperations() override; std::string GetCapabilities() const override; void SetCapabilities(const std::string& capabilities) override; uint32_t GetDesktopSessionId() const override;
diff --git a/remoting/protocol/file_transfer_helpers.cc b/remoting/protocol/file_transfer_helpers.cc index 4486c35..469b5c9 100644 --- a/remoting/protocol/file_transfer_helpers.cc +++ b/remoting/protocol/file_transfer_helpers.cc
@@ -22,5 +22,16 @@ return error; } +std::ostream& operator<<(std::ostream& stream, + const FileTransfer_Error& error) { + stream << "[" << error.source_file() << ":" << error.line_number() << " (" + << error.function() << ")"; + if (error.has_api_error_code()) { + stream << ": " << error.api_error_code(); + } + stream << "]"; + return stream; +} + } // namespace protocol } // namespace remoting
diff --git a/remoting/protocol/file_transfer_helpers.h b/remoting/protocol/file_transfer_helpers.h index 7fc25fe..81edc9d 100644 --- a/remoting/protocol/file_transfer_helpers.h +++ b/remoting/protocol/file_transfer_helpers.h
@@ -6,6 +6,7 @@ #define REMOTING_PROTOCOL_FILE_TRANSFER_HELPERS_H_ #include <cstdint> +#include <ostream> #include "base/location.h" #include "base/optional.h" @@ -19,6 +20,8 @@ FileTransfer_Error_Type type, base::Optional<std::int32_t> api_error_code = base::nullopt); +std::ostream& operator<<(std::ostream& stream, const FileTransfer_Error& error); + } // namespace protocol } // namespace remoting
diff --git a/services/network/OWNERS b/services/network/OWNERS index 98a9813..8263d9d 100644 --- a/services/network/OWNERS +++ b/services/network/OWNERS
@@ -1,3 +1,4 @@ +ericorth@chromium.org jam@chromium.org kinuko@chromium.org mmenke@chromium.org
diff --git a/services/service_manager/embedder/BUILD.gn b/services/service_manager/embedder/BUILD.gn index 15c7b9a0..2a41a0e4 100644 --- a/services/service_manager/embedder/BUILD.gn +++ b/services/service_manager/embedder/BUILD.gn
@@ -81,11 +81,13 @@ component("embedder_switches") { sources = [ - "service_manager_embedder_switches_export.h", "switches.cc", "switches.h", ] - defines = [ "SERVICE_MANAGER_EMBEDDER_SWITCHES_IMPL" ] + deps = [ + "//base", + ] + defines = [ "IS_SERVICE_MANAGER_EMBEDDER_SWITCHES_IMPL" ] } source_set("embedder_result_codes") {
diff --git a/services/service_manager/embedder/service_manager_embedder_switches_export.h b/services/service_manager/embedder/service_manager_embedder_switches_export.h deleted file mode 100644 index 94151b8d..0000000 --- a/services/service_manager/embedder/service_manager_embedder_switches_export.h +++ /dev/null
@@ -1,30 +0,0 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef SERVICES_SERVICE_MANAGER_EMBEDDER_SERVICE_MANAGER_EMBEDDER_SWITCHES_EXPORT_H_ -#define SERVICES_SERVICE_MANAGER_EMBEDDER_SERVICE_MANAGER_EMBEDDER_SWITCHES_EXPORT_H_ - -#if defined(COMPONENT_BUILD) -#if defined(WIN32) - -#if defined(SERVICE_MANAGER_EMBEDDER_SWITCHES_IMPL) -#define SERVICE_MANAGER_EMBEDDER_SWITCHES_EXPORT __declspec(dllexport) -#else -#define SERVICE_MANAGER_EMBEDDER_SWITCHES_EXPORT __declspec(dllimport) -#endif // defined(SERVICE_MANAGER_EMBEDDER_SWITCHES_IMPL) - -#else // defined(WIN32) -#if defined(SERVICE_MANAGER_EMBEDDER_SWITCHES_IMPL) -#define SERVICE_MANAGER_EMBEDDER_SWITCHES_EXPORT \ - __attribute__((visibility("default"))) -#else -#define SERVICE_MANAGER_EMBEDDER_SWITCHES_EXPORT -#endif // defined(SERVICE_MANAGER_EMBEDDER_SWITCHES_IMPL) -#endif - -#else // defined(COMPONENT_BUILD) -#define SERVICE_MANAGER_EMBEDDER_SWITCHES_EXPORT -#endif - -#endif // SERVICES_SERVICE_MANAGER_EMBEDDER_SERVICE_MANAGER_EMBEDDER_SWITCHES_EXPORT_H_
diff --git a/services/service_manager/embedder/switches.h b/services/service_manager/embedder/switches.h index 25d4ca9..548165e 100644 --- a/services/service_manager/embedder/switches.h +++ b/services/service_manager/embedder/switches.h
@@ -5,30 +5,43 @@ #ifndef SERVICES_SERVICE_MANAGER_EMBEDDER_SWITCHES_H_ #define SERVICES_SERVICE_MANAGER_EMBEDDER_SWITCHES_H_ +#include "base/component_export.h" #include "build/build_config.h" -#include "services/service_manager/embedder/service_manager_embedder_switches_export.h" namespace service_manager { namespace switches { #if defined(OS_WIN) -SERVICE_MANAGER_EMBEDDER_SWITCHES_EXPORT +COMPONENT_EXPORT(SERVICE_MANAGER_EMBEDDER_SWITCHES) extern const char kDefaultServicePrefetchArgument[]; #endif // defined(OS_WIN) -SERVICE_MANAGER_EMBEDDER_SWITCHES_EXPORT extern const char - kDisableInProcessStackTraces[]; -SERVICE_MANAGER_EMBEDDER_SWITCHES_EXPORT extern const char kEnableLogging[]; -SERVICE_MANAGER_EMBEDDER_SWITCHES_EXPORT extern const char kProcessType[]; -SERVICE_MANAGER_EMBEDDER_SWITCHES_EXPORT extern const char - kProcessTypeServiceManager[]; -SERVICE_MANAGER_EMBEDDER_SWITCHES_EXPORT extern const char - kProcessTypeService[]; -SERVICE_MANAGER_EMBEDDER_SWITCHES_EXPORT extern const char - kServiceRequestChannelToken[]; -SERVICE_MANAGER_EMBEDDER_SWITCHES_EXPORT extern const char kSharedFiles[]; -SERVICE_MANAGER_EMBEDDER_SWITCHES_EXPORT extern const char kZygoteCmdPrefix[]; -SERVICE_MANAGER_EMBEDDER_SWITCHES_EXPORT extern const char kZygoteProcess[]; +COMPONENT_EXPORT(SERVICE_MANAGER_EMBEDDER_SWITCHES) +extern const char kDisableInProcessStackTraces[]; + +COMPONENT_EXPORT(SERVICE_MANAGER_EMBEDDER_SWITCHES) +extern const char kEnableLogging[]; + +COMPONENT_EXPORT(SERVICE_MANAGER_EMBEDDER_SWITCHES) +extern const char kProcessType[]; + +COMPONENT_EXPORT(SERVICE_MANAGER_EMBEDDER_SWITCHES) +extern const char kProcessTypeServiceManager[]; + +COMPONENT_EXPORT(SERVICE_MANAGER_EMBEDDER_SWITCHES) +extern const char kProcessTypeService[]; + +COMPONENT_EXPORT(SERVICE_MANAGER_EMBEDDER_SWITCHES) +extern const char kServiceRequestChannelToken[]; + +COMPONENT_EXPORT(SERVICE_MANAGER_EMBEDDER_SWITCHES) +extern const char kSharedFiles[]; + +COMPONENT_EXPORT(SERVICE_MANAGER_EMBEDDER_SWITCHES) +extern const char kZygoteCmdPrefix[]; + +COMPONENT_EXPORT(SERVICE_MANAGER_EMBEDDER_SWITCHES) +extern const char kZygoteProcess[]; } // namespace switches } // namespace service_manager
diff --git a/services/service_manager/sandbox/fuchsia/sandbox_policy_fuchsia.cc b/services/service_manager/sandbox/fuchsia/sandbox_policy_fuchsia.cc index 31ecd0b..c82d44d 100644 --- a/services/service_manager/sandbox/fuchsia/sandbox_policy_fuchsia.cc +++ b/services/service_manager/sandbox/fuchsia/sandbox_policy_fuchsia.cc
@@ -70,7 +70,8 @@ { SANDBOX_TYPE_GPU, base::make_span( - (const char* const[]){fuchsia::ui::scenic::Scenic::Name_}), + (const char* const[]){fuchsia::ui::scenic::Scenic::Name_, + "fuchsia.vulkan.loader.Loader"}), kProvideVulkanResources, }, }; @@ -176,7 +177,7 @@ options->paths_to_clone.push_back(base::FilePath("/config/ssl")); if (config.features & kProvideVulkanResources) { - // /system/lib is used to load Vilkan libraries. /dev/class/gpu and + // /system/lib is used to load Vulkan libraries. /dev/class/gpu and // /config/vulkan/icd.d are to used configure and access the GPU. options->paths_to_clone.push_back(base::FilePath("/system/lib")); options->paths_to_clone.push_back(base::FilePath("/dev/class/gpu"));
diff --git a/skia/ext/skia_utils_base.cc b/skia/ext/skia_utils_base.cc index 90e7ab2..516ad7e 100644 --- a/skia/ext/skia_utils_base.cc +++ b/skia/ext/skia_utils_base.cc
@@ -7,6 +7,7 @@ #include <stdint.h> #include "base/pickle.h" +#include "third_party/skia/include/core/SkBitmap.h" #include "third_party/skia/include/core/SkData.h" #include "third_party/skia/include/core/SkEncodedImageFormat.h" #include "third_party/skia/include/core/SkImage.h" @@ -81,4 +82,29 @@ pickle->WriteUInt16(style.slant()); } +bool SkBitmapToN32OpaqueOrPremul(const SkBitmap& in, SkBitmap* out) { + DCHECK(out); + const SkImageInfo& info = in.info(); + if (info.colorType() == kN32_SkColorType && + (info.alphaType() == kPremul_SkAlphaType || + info.alphaType() == kOpaque_SkAlphaType)) { + // Shallow copy if the data is already in the right format. + *out = in; + return true; + } + + SkImageInfo new_info = + info.makeColorType(kN32_SkColorType) + .makeAlphaType(info.alphaType() == kOpaque_SkAlphaType + ? kOpaque_SkAlphaType + : kPremul_SkAlphaType); + if (!out->tryAllocPixels(new_info, 0)) { + return false; + } + if (!in.readPixels(out->pixmap())) { + return false; + } + return true; +} + } // namespace skia
diff --git a/skia/ext/skia_utils_base.h b/skia/ext/skia_utils_base.h index d1f844cb..2a1eca124 100644 --- a/skia/ext/skia_utils_base.h +++ b/skia/ext/skia_utils_base.h
@@ -13,6 +13,7 @@ class PickleIterator; } +class SkBitmap; class SkFlattenable; namespace skia { @@ -41,6 +42,13 @@ // Writes style into the request pickle. SK_API void WriteSkFontStyle(base::Pickle* pickle, SkFontStyle style); +// Converts an SkBitmap to an Opaque or Premul N32 SkBitmap. If the input is in +// the right format (N32 Opaque or Premul) already, points |out| directly at +// |in|. |out| may or may not be GPU-backed. +// +// If unsuccessful, returns false, but |out| may be modified. +SK_API bool SkBitmapToN32OpaqueOrPremul(const SkBitmap& in, SkBitmap* out); + } // namespace skia #endif // SKIA_EXT_SKIA_UTILS_BASE_H_
diff --git a/skia/ext/skia_utils_mac.mm b/skia/ext/skia_utils_mac.mm index 9e21649..7eb0671 100644 --- a/skia/ext/skia_utils_mac.mm +++ b/skia/ext/skia_utils_mac.mm
@@ -219,6 +219,8 @@ // First convert SkBitmap to CGImageRef. base::ScopedCFTypeRef<CGImageRef> cgimage( SkCreateCGImageRefWithColorspace(skiaBitmap, colorSpace)); + if (!cgimage) + return nil; // Now convert to NSBitmapImageRep. base::scoped_nsobject<NSBitmapImageRep> bitmap( @@ -232,8 +234,11 @@ return nil; base::scoped_nsobject<NSImage> image([[NSImage alloc] init]); - [image addRepresentation: - SkBitmapToNSBitmapImageRepWithColorSpace(skiaBitmap, colorSpace)]; + NSBitmapImageRep* imageRep = + SkBitmapToNSBitmapImageRepWithColorSpace(skiaBitmap, colorSpace); + if (!imageRep) + return nil; + [image addRepresentation:imageRep]; [image setSize:NSMakeSize(skiaBitmap.width(), skiaBitmap.height())]; return [image.release() autorelease]; }
diff --git a/styleguide/objective-c/objective-c.md b/styleguide/objective-c/objective-c.md index fc6ddebe..cd74cdc7 100644 --- a/styleguide/objective-c/objective-c.md +++ b/styleguide/objective-c/objective-c.md
@@ -45,3 +45,8 @@ mostly testing Objective-C objects and methods, the test should be written using C++ style. +## #import and #include in the `ios/` directory + +#import directive can be used to import C++ and Objective-C headers for all +source code in the `ios/` directory. This differs from Google Objective-C Style +Guide, which requires using #include directive for C++ headers.
diff --git a/testing/buildbot/chromium.linux.json b/testing/buildbot/chromium.linux.json index 67f7926..f1f2c1e 100644 --- a/testing/buildbot/chromium.linux.json +++ b/testing/buildbot/chromium.linux.json
@@ -485,6 +485,12 @@ "swarming": { "can_use_on_swarming_builders": true }, + "test": "exo_unittests" + }, + { + "swarming": { + "can_use_on_swarming_builders": true + }, "test": "gcm_unit_tests" }, {
diff --git a/testing/buildbot/test_suites.pyl b/testing/buildbot/test_suites.pyl index ba38fa9..6cc6d4c 100644 --- a/testing/buildbot/test_suites.pyl +++ b/testing/buildbot/test_suites.pyl
@@ -361,6 +361,7 @@ 'cast_video_specific_chromium_gtests': { 'cast_graphics_unittests': {}, + 'exo_unittests': {}, }, 'check_gn_headers_script': {
diff --git a/testing/run_with_dummy_home.py b/testing/run_with_dummy_home.py new file mode 100755 index 0000000..3d28e06 --- /dev/null +++ b/testing/run_with_dummy_home.py
@@ -0,0 +1,59 @@ +#!/usr/bin/env python +# Copyright 2018 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +"""Usage: run_with_dummy_home.py <command> + +Helper for running a test with a dummy $HOME, populated with just enough for +tests to run and pass. Useful for isolating tests from the real $HOME, which +can contain config files that negatively affect test performance. +""" + +import os +import shutil +import subprocess +import sys +import tempfile + + +def _set_up_dummy_home(original_home, dummy_home): + """Sets up a dummy $HOME that Chromium tests can run in. + + Files are copied, while directories are symlinked. + """ + for filename in ['.Xauthority']: + original_path = os.path.join(original_home, filename) + if not os.path.exists(original_path): + continue + shutil.copyfile(original_path, os.path.join(dummy_home, filename)) + + # Prevent fontconfig etc. from reconstructing the cache and symlink rr + # trace directory. + for dirpath in [['.cache'], ['.local', 'share', 'rr'], ['.vpython'], + ['.vpython_cipd_cache'], ['.vpython-root']]: + original_path = os.path.join(original_home, *dirpath) + if not os.path.exists(original_path): + continue + dummy_parent_path = os.path.join(dummy_home, *dirpath[:-1]) + if not os.path.isdir(dummy_parent_path): + os.makedirs(dummy_parent_path) + os.symlink(original_path, os.path.join(dummy_home, *dirpath)) + + +def main(): + try: + dummy_home = tempfile.mkdtemp() + print 'Creating dummy home in %s' % dummy_home + + original_home = os.environ['HOME'] + os.environ['HOME'] = dummy_home + _set_up_dummy_home(original_home, dummy_home) + + return subprocess.call(sys.argv[1:]) + finally: + shutil.rmtree(dummy_home) + + +if __name__ == '__main__': + sys.exit(main())
diff --git a/testing/test.gni b/testing/test.gni index 4436bab7..a67452b 100644 --- a/testing/test.gni +++ b/testing/test.gni
@@ -257,7 +257,11 @@ fuchsia_package_runner(target_name) { testonly = true - forward_variables_from(invoker, [ "use_test_server" ]) + forward_variables_from(invoker, + [ + "use_test_server", + "package_deps", + ]) runner_script = "//build/fuchsia/test_runner.py" package = ":$_pkg_target" package_name_override = _output_name
diff --git a/third_party/android_deps/BUILD.gn b/third_party/android_deps/BUILD.gn index 8aec5e9c..6fb2c730 100644 --- a/third_party/android_deps/BUILD.gn +++ b/third_party/android_deps/BUILD.gn
@@ -535,6 +535,12 @@ ] } +android_aar_prebuilt("com_google_ar_core_java") { + aar_path = "libs/com_google_ar_core/core-1.5.0.aar" + info_path = "libs/com_google_ar_core/com_google_ar_core.info" + extract_native_libraries = true +} + java_prebuilt("com_google_dagger_dagger_java") { jar_path = "libs/com_google_dagger_dagger/dagger-2.17.jar" output_name = "com_google_dagger_dagger"
diff --git a/third_party/android_deps/additional_readme_paths.json b/third_party/android_deps/additional_readme_paths.json index 9dc6610f..3e52c7b 100644 --- a/third_party/android_deps/additional_readme_paths.json +++ b/third_party/android_deps/additional_readme_paths.json
@@ -45,6 +45,7 @@ "libs/com_google_android_gms_play_services_tasks", "libs/com_google_android_gms_play_services_vision", "libs/com_google_android_gms_play_services_vision_common", + "libs/com_google_ar_core", "libs/com_google_code_findbugs_jsr305", "libs/com_google_dagger_dagger", "libs/com_google_dagger_dagger_compiler",
diff --git a/third_party/android_deps/libs/com_google_ar_core/LICENSE b/third_party/android_deps/libs/com_google_ar_core/LICENSE new file mode 100644 index 0000000..f731190 --- /dev/null +++ b/third_party/android_deps/libs/com_google_ar_core/LICENSE
@@ -0,0 +1,179 @@ +Except as indicated at the end of this LICENSE file, +files in this SDK are licensed as follows: + +Copyright (c) 2017, Google Inc. +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION +1. Definitions. + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. +END OF TERMS AND CONDITIONS + +=============================================================================== + +The following files: +tools/arcoreimg/linux/arcoreimg +tools/arcoreimg/macos/arcoreimg +tools/arcoreimg/windows/arcoreimg.exe + +are licensed as follows: +Covered by the **Google APIs Terms of Service** at +[https://developers.google.com/terms/](https://developers.google.com/terms/) + +=============================================================================== + +The *.apk files attached to [GitHub releases](https://github.com/google-ar/arcore-android-sdk/releases) +are licensed as follows: +Covered by the **Google APIs Terms of Service** at +[https://developers.google.com/terms/](https://developers.google.com/terms/)
diff --git a/third_party/android_deps/libs/com_google_ar_core/OWNERS b/third_party/android_deps/libs/com_google_ar_core/OWNERS new file mode 100644 index 0000000..7b571d97 --- /dev/null +++ b/third_party/android_deps/libs/com_google_ar_core/OWNERS
@@ -0,0 +1 @@ +file://third_party/android_deps/OWNERS \ No newline at end of file
diff --git a/third_party/android_deps/libs/com_google_ar_core/README.chromium b/third_party/android_deps/libs/com_google_ar_core/README.chromium new file mode 100644 index 0000000..c71710d --- /dev/null +++ b/third_party/android_deps/libs/com_google_ar_core/README.chromium
@@ -0,0 +1,13 @@ +Name: +Short Name: core +URL: https://github.com/google-ar/arcore-android-sdk +Version: 1.5.0 +License: Apache 2.0 +License File: LICENSE +Security Critical: yes + +Description: + + +Local Modifications: +No modifications.
diff --git a/third_party/android_deps/libs/com_google_ar_core/cipd.yaml b/third_party/android_deps/libs/com_google_ar_core/cipd.yaml new file mode 100644 index 0000000..754918bc --- /dev/null +++ b/third_party/android_deps/libs/com_google_ar_core/cipd.yaml
@@ -0,0 +1,10 @@ +# Copyright 2018 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +# To create CIPD package run the following command. +# cipd create --pkg-def cipd.yaml -tag version:1.5.0-cr0 +package: chromium/third_party/android_deps/libs/com_google_ar_core +description: "" +data: +- file: core-1.5.0.aar
diff --git a/third_party/android_deps/libs/com_google_ar_core/com_google_ar_core.info b/third_party/android_deps/libs/com_google_ar_core/com_google_ar_core.info new file mode 100644 index 0000000..3f5e833 --- /dev/null +++ b/third_party/android_deps/libs/com_google_ar_core/com_google_ar_core.info
@@ -0,0 +1,14 @@ +# Generated by //build/android/gyp/aar.py +# To regenerate, use "update_android_aar_prebuilts = true" and run "gn gen". + +aidl = [ ] +assets = [ ] +has_classes_jar = true +has_native_libraries = true +has_proguard_flags = true +has_r_text_file = true +is_manifest_empty = false +native_libraries = [ "jni/arm64-v8a/libarcore_sdk_c.so", "jni/arm64-v8a/libarcore_sdk_jni.so", "jni/armeabi-v7a/libarcore_sdk_c.so", "jni/armeabi-v7a/libarcore_sdk_jni.so", "jni/x86/libarcore_sdk_c.so", "jni/x86/libarcore_sdk_jni.so" ] +resources = [ "res/layout/__arcore_education.xml", "res/values-af/values.xml", "res/values-am/values.xml", "res/values-ar-rEG/values.xml", "res/values-ar-rSA/values.xml", "res/values-ar-rXB/values.xml", "res/values-az/values.xml", "res/values-b+es+419/values.xml", "res/values-b+sr+Latn/values.xml", "res/values-be/values.xml", "res/values-bg/values.xml", "res/values-bn/values.xml", "res/values-bs/values.xml", "res/values-ca/values.xml", "res/values-cs/values.xml", "res/values-da/values.xml", "res/values-de-rAT/values.xml", "res/values-de-rCH/values.xml", "res/values-de/values.xml", "res/values-el/values.xml", "res/values-en-rAU/values.xml", "res/values-en-rCA/values.xml", "res/values-en-rGB/values.xml", "res/values-en-rIE/values.xml", "res/values-en-rSG/values.xml", "res/values-en-rXA/values.xml", "res/values-en-rXC/values.xml", "res/values-en-rZA/values.xml", "res/values-es-rAR/values.xml", "res/values-es-rBO/values.xml", "res/values-es-rCL/values.xml", "res/values-es-rCO/values.xml", "res/values-es-rCR/values.xml", "res/values-es-rDO/values.xml", "res/values-es-rEC/values.xml", "res/values-es-rGT/values.xml", "res/values-es-rHN/values.xml", "res/values-es-rMX/values.xml", "res/values-es-rNI/values.xml", "res/values-es-rPA/values.xml", "res/values-es-rPE/values.xml", "res/values-es-rPR/values.xml", "res/values-es-rPY/values.xml", "res/values-es-rSV/values.xml", "res/values-es-rUS/values.xml", "res/values-es-rUY/values.xml", "res/values-es-rVE/values.xml", "res/values-es/values.xml", "res/values-et/values.xml", "res/values-eu/values.xml", "res/values-fa/values.xml", "res/values-fi/values.xml", "res/values-fil/values.xml", "res/values-fr-rCA/values.xml", "res/values-fr-rCH/values.xml", "res/values-fr/values.xml", "res/values-gl/values.xml", "res/values-gsw/values.xml", "res/values-gu/values.xml", "res/values-he/values.xml", "res/values-hi/values.xml", "res/values-hr/values.xml", "res/values-hu/values.xml", "res/values-hy/values.xml", "res/values-id/values.xml", "res/values-in/values.xml", "res/values-is/values.xml", "res/values-it/values.xml", "res/values-iw/values.xml", "res/values-ja/values.xml", "res/values-ka/values.xml", "res/values-kk/values.xml", "res/values-km/values.xml", "res/values-kn/values.xml", "res/values-ko/values.xml", "res/values-ky/values.xml", "res/values-lo/values.xml", "res/values-lt/values.xml", "res/values-lv/values.xml", "res/values-mk/values.xml", "res/values-ml/values.xml", "res/values-mn/values.xml", "res/values-mo/values.xml", "res/values-ms/values.xml", "res/values-my/values.xml", "res/values-nb/values.xml", "res/values-ne/values.xml", "res/values-nl/values.xml", "res/values-no/values.xml", "res/values-pa/values.xml", "res/values-pl/values.xml", "res/values-pt-rBR/values.xml", "res/values-pt-rPT/values.xml", "res/values-pt/values.xml", "res/values-ro/values.xml", "res/values-ru/values.xml", "res/values-si/values.xml", "res/values-sk/values.xml", "res/values-sl/values.xml", "res/values-sq/values.xml", "res/values-sr/values.xml", "res/values-sv/values.xml", "res/values-sw/values.xml", "res/values-ta/values.xml", "res/values-te/values.xml", "res/values-th/values.xml", "res/values-tl/values.xml", "res/values-tr/values.xml", "res/values-uk/values.xml", "res/values-ur/values.xml", "res/values-uz/values.xml", "res/values-vi/values.xml", "res/values-zh-rCN/values.xml", "res/values-zh-rHK/values.xml", "res/values-zh-rTW/values.xml", "res/values-zh/values.xml", "res/values-zu/values.xml", "res/values/values.xml" ] +subjar_tuples = [ ] +subjars = [ ]
diff --git a/third_party/blink/renderer/DEPS b/third_party/blink/renderer/DEPS index 2515e2d..9fc2759d 100644 --- a/third_party/blink/renderer/DEPS +++ b/third_party/blink/renderer/DEPS
@@ -24,6 +24,7 @@ "+base/sequenced_task_runner.h", "+base/single_thread_task_runner.h", "+base/stl_util.h", + "+base/synchronization", "+base/sys_byteorder.h", "+base/system/sys_info.h", "+base/task/post_task.h",
diff --git a/third_party/blink/renderer/core/clipboard/system_clipboard.cc b/third_party/blink/renderer/core/clipboard/system_clipboard.cc index 038e828..46cf67c8 100644 --- a/third_party/blink/renderer/core/clipboard/system_clipboard.cc +++ b/third_party/blink/renderer/core/clipboard/system_clipboard.cc
@@ -172,11 +172,8 @@ if (bitmap.isNull()) return; - // Only 32-bit bitmaps are supported. - DCHECK_EQ(bitmap.colorType(), kN32_SkColorType); - void* pixels = bitmap.getPixels(); // TODO(piman): this should not be NULL, but it is. crbug.com/369621 - if (!pixels) + if (!bitmap.getPixels()) return; clipboard_->WriteImage(mojom::ClipboardBuffer::kStandard, bitmap);
diff --git a/third_party/blink/renderer/core/css/font_face_set.cc b/third_party/blink/renderer/core/css/font_face_set.cc index d67753b..08c68f2 100644 --- a/third_party/blink/renderer/core/css/font_face_set.cc +++ b/third_party/blink/renderer/core/css/font_face_set.cc
@@ -7,30 +7,29 @@ #include "third_party/blink/renderer/core/css/font_face_cache.h" #include "third_party/blink/renderer/core/css/font_face_set_load_event.h" #include "third_party/blink/renderer/platform/fonts/font.h" +#include "third_party/blink/renderer/platform/wtf/functional.h" namespace blink { const int FontFaceSet::kDefaultFontSize = 10; const char FontFaceSet::kDefaultFontFamily[] = "sans-serif"; -void FontFaceSet::Pause() { - async_runner_->Pause(); -} - -void FontFaceSet::Unpause() { - async_runner_->Unpause(); -} - -void FontFaceSet::ContextDestroyed(ExecutionContext*) { - async_runner_->Stop(); -} - void FontFaceSet::HandlePendingEventsAndPromisesSoon() { - // async_runner_ will be automatically stopped on destruction. - async_runner_->RunAsync(); + if (!pending_task_queued_) { + if (auto* context = GetExecutionContext()) { + pending_task_queued_ = true; + context->GetTaskRunner(TaskType::kInternalDefault) + ->PostTask(FROM_HERE, + WTF::Bind(&FontFaceSet::HandlePendingEventsAndPromises, + WrapPersistent(this))); + } + } } void FontFaceSet::HandlePendingEventsAndPromises() { + pending_task_queued_ = false; + if (!GetExecutionContext()) + return; FireLoadingEvent(); FireDoneEventIfPossible(); } @@ -112,8 +111,7 @@ visitor->Trace(loaded_fonts_); visitor->Trace(failed_fonts_); visitor->Trace(ready_); - visitor->Trace(async_runner_); - PausableObject::Trace(visitor); + ContextClient::Trace(visitor); EventTargetWithInlineData::Trace(visitor); FontFace::LoadFontCallback::Trace(visitor); }
diff --git a/third_party/blink/renderer/core/css/font_face_set.h b/third_party/blink/renderer/core/css/font_face_set.h index 94a3d46c..935a006 100644 --- a/third_party/blink/renderer/core/css/font_face_set.h +++ b/third_party/blink/renderer/core/css/font_face_set.h
@@ -12,10 +12,9 @@ #include "third_party/blink/renderer/bindings/core/v8/script_promise.h" #include "third_party/blink/renderer/bindings/core/v8/script_promise_resolver.h" #include "third_party/blink/renderer/core/css/font_face.h" +#include "third_party/blink/renderer/core/dom/context_lifecycle_observer.h" #include "third_party/blink/renderer/core/dom/events/event_listener.h" #include "third_party/blink/renderer/core/dom/events/event_target.h" -#include "third_party/blink/renderer/core/dom/pausable_object.h" -#include "third_party/blink/renderer/platform/async_method_runner.h" #include "third_party/blink/renderer/platform/bindings/script_wrappable.h" #include "third_party/blink/renderer/platform/fonts/font_selector.h" @@ -32,23 +31,17 @@ using FontFaceSetIterable = SetlikeIterable<Member<FontFace>>; class CORE_EXPORT FontFaceSet : public EventTargetWithInlineData, - public PausableObject, + public ContextClient, public FontFaceSetIterable, public FontFace::LoadFontCallback { DEFINE_WRAPPERTYPEINFO(); public: FontFaceSet(ExecutionContext& context) - : PausableObject(&context), - is_loading_(false), - should_fire_loading_event_(false), + : ContextClient(&context), ready_(MakeGarbageCollected<ReadyProperty>(GetExecutionContext(), this, - ReadyProperty::kReady)), - async_runner_(AsyncMethodRunner<FontFaceSet>::Create( - this, - &FontFaceSet::HandlePendingEventsAndPromises, - context.GetTaskRunner(TaskType::kInternalDefault))) {} + ReadyProperty::kReady)) {} ~FontFaceSet() override = default; DEFINE_ATTRIBUTE_EVENT_LISTENER(loading, kLoading); @@ -60,7 +53,7 @@ virtual ScriptPromise ready(ScriptState*) = 0; ExecutionContext* GetExecutionContext() const override { - return PausableObject::GetExecutionContext(); + return ContextClient::GetExecutionContext(); } const AtomicString& InterfaceName() const override { @@ -74,11 +67,6 @@ void AddFontFacesToFontFaceCache(FontFaceCache*); - // PausableObject - void Pause() override; - void Unpause() override; - void ContextDestroyed(ExecutionContext*) override; - wtf_size_t size() const; virtual AtomicString status() const = 0; @@ -109,16 +97,15 @@ Member<FontFaceSet>, Member<DOMException>>; - bool is_loading_; - bool should_fire_loading_event_; + bool is_loading_ = false; + bool should_fire_loading_event_ = false; + bool pending_task_queued_ = false; HeapLinkedHashSet<Member<FontFace>> non_css_connected_faces_; HeapHashSet<Member<FontFace>> loading_fonts_; FontFaceArray loaded_fonts_; FontFaceArray failed_fonts_; Member<ReadyProperty> ready_; - Member<AsyncMethodRunner<FontFaceSet>> async_runner_; - class IterationSource final : public FontFaceSetIterable::IterationSource { public: explicit IterationSource(const HeapVector<Member<FontFace>>& font_faces)
diff --git a/third_party/blink/renderer/core/css/font_face_set_document.cc b/third_party/blink/renderer/core/css/font_face_set_document.cc index 36b128a..038815f 100644 --- a/third_party/blink/renderer/core/css/font_face_set_document.cc +++ b/third_party/blink/renderer/core/css/font_face_set_document.cc
@@ -48,7 +48,6 @@ FontFaceSetDocument::FontFaceSetDocument(Document& document) : FontFaceSet(document), Supplement<Document>(document) { - PauseIfNeeded(); } FontFaceSetDocument::~FontFaceSetDocument() = default;
diff --git a/third_party/blink/renderer/core/css/font_face_set_worker.cc b/third_party/blink/renderer/core/css/font_face_set_worker.cc index 5e7ee27f..270f40a 100644 --- a/third_party/blink/renderer/core/css/font_face_set_worker.cc +++ b/third_party/blink/renderer/core/css/font_face_set_worker.cc
@@ -26,7 +26,6 @@ FontFaceSetWorker::FontFaceSetWorker(WorkerGlobalScope& worker) : FontFaceSet(worker), Supplement<WorkerGlobalScope>(worker) { - PauseIfNeeded(); } FontFaceSetWorker::~FontFaceSetWorker() = default;
diff --git a/third_party/blink/renderer/core/css/properties/computed_style_utils.cc b/third_party/blink/renderer/core/css/properties/computed_style_utils.cc index 73b8a08f..2234a3f 100644 --- a/third_party/blink/renderer/core/css/properties/computed_style_utils.cc +++ b/third_party/blink/renderer/core/css/properties/computed_style_utils.cc
@@ -502,7 +502,7 @@ LayoutObject* layout_object = styled_node ? styled_node->GetLayoutObject() : nullptr; if (layout_object && layout_object->IsBox() && - (ToLayoutBox(layout_object)->IsFlexItem() || + (ToLayoutBox(layout_object)->IsFlexItemIncludingNG() || ToLayoutBox(layout_object)->IsGridItem())) { return CSSIdentifierValue::Create(CSSValueAuto); }
diff --git a/third_party/blink/renderer/core/dom/first_letter_pseudo_element.cc b/third_party/blink/renderer/core/dom/first_letter_pseudo_element.cc index a689ec3..4176191f 100644 --- a/third_party/blink/renderer/core/dom/first_letter_pseudo_element.cc +++ b/third_party/blink/renderer/core/dom/first_letter_pseudo_element.cc
@@ -164,7 +164,7 @@ first_letter_text_layout_object->IsMenuList()) { return nullptr; } else if (first_letter_text_layout_object - ->IsFlexibleBoxIncludingDeprecated() || + ->IsFlexibleBoxIncludingDeprecatedAndNG() || first_letter_text_layout_object->IsLayoutGrid()) { first_letter_text_layout_object = first_letter_text_layout_object->NextSibling();
diff --git a/third_party/blink/renderer/core/dom/text.cc b/third_party/blink/renderer/core/dom/text.cc index 6a91669..a7fc2c7 100644 --- a/third_party/blink/renderer/core/dom/text.cc +++ b/third_party/blink/renderer/core/dom/text.cc
@@ -258,8 +258,9 @@ if (parent.IsTable() || parent.IsTableRow() || parent.IsTableSection() || parent.IsLayoutTableCol() || parent.IsFrameSet() || - parent.IsFlexibleBox() || parent.IsLayoutGrid() || parent.IsSVGRoot() || - parent.IsSVGContainer() || parent.IsSVGImage() || parent.IsSVGShape()) { + parent.IsFlexibleBoxIncludingNG() || parent.IsLayoutGrid() || + parent.IsSVGRoot() || parent.IsSVGContainer() || parent.IsSVGImage() || + parent.IsSVGShape()) { if (!context.use_previous_in_flow || !context.previous_in_flow || !context.previous_in_flow->IsText()) return false;
diff --git a/third_party/blink/renderer/core/editing/visible_units.cc b/third_party/blink/renderer/core/editing/visible_units.cc index debe9cad..daf23d4 100644 --- a/third_party/blink/renderer/core/editing/visible_units.cc +++ b/third_party/blink/renderer/core/editing/visible_units.cc
@@ -936,7 +936,8 @@ if (!layout_object->IsSelectable()) return false; - if (layout_object->IsLayoutBlockFlow() || layout_object->IsFlexibleBox() || + if (layout_object->IsLayoutBlockFlow() || + layout_object->IsFlexibleBoxIncludingNG() || layout_object->IsLayoutGrid()) { if (ToLayoutBlock(layout_object)->LogicalHeight() || anchor_node->GetDocument().body() == anchor_node) {
diff --git a/third_party/blink/renderer/core/inspector/inspector_overlay_agent.cc b/third_party/blink/renderer/core/inspector/inspector_overlay_agent.cc index a0d3582..5bd542b 100644 --- a/third_party/blink/renderer/core/inspector/inspector_overlay_agent.cc +++ b/third_party/blink/renderer/core/inspector/inspector_overlay_agent.cc
@@ -1039,7 +1039,7 @@ return false; if ((event.GetModifiers() & kCtrlOrMeta) && - (event.GetModifiers() & WebInputEvent::kLeftButtonDown)) { + event.button == WebPointerProperties::Button::kLeft) { InnerHideHighlight(); hovered_node_for_inspect_mode_.Clear(); screenshot_mode_ = true; @@ -1073,6 +1073,8 @@ int max_x = std::max(p1.X(), p2.X()); int min_y = std::min(p1.Y(), p2.Y()); int max_y = std::max(p1.Y(), p2.Y()); + if (max_x - min_x < 5 || max_y - min_y < 5) + return true; GetFrontend()->screenshotRequested(protocol::Page::Viewport::create() .setX(min_x) .setY(min_y)
diff --git a/third_party/blink/renderer/core/layout/flexible_box_algorithm.cc b/third_party/blink/renderer/core/layout/flexible_box_algorithm.cc index 711ac14..a1efd69 100644 --- a/third_party/blink/renderer/core/layout/flexible_box_algorithm.cc +++ b/third_party/blink/renderer/core/layout/flexible_box_algorithm.cc
@@ -146,7 +146,6 @@ // constructor. Then use cross_axis_min_max.ClampSizeToMinAndMax instead of // relying on legacy in this method. DCHECK_EQ(Alignment(), ItemPosition::kStretch); - LayoutFlexibleBox* flexbox = ToLayoutFlexibleBox(box->Parent()); if (MainAxisIsInlineAxis() && box->StyleRef().LogicalHeight().IsAuto()) { LayoutUnit stretched_logical_height = std::max(box->BorderAndPaddingLogicalHeight(), @@ -155,11 +154,14 @@ stretched_logical_height, box->IntrinsicContentLogicalHeight()); } else if (!MainAxisIsInlineAxis() && box->StyleRef().LogicalWidth().IsAuto()) { + // This doesn't work in NG because CrossAxisContentExtent() isn't yet + // implemented there. + if (box->Parent()->IsLayoutNGFlexibleBox()) + return; LayoutUnit child_width = (Line()->cross_axis_extent - CrossAxisMarginExtent()) .ClampNegativeToZero(); - // This probably doesn't work in NG because flexbox might not yet know its - // CrossAxisContentExtent() + LayoutFlexibleBox* flexbox = ToLayoutFlexibleBox(box->Parent()); cross_axis_size = box->ConstrainLogicalWidthByMinMax( child_width, flexbox->CrossAxisContentExtent(), flexbox); }
diff --git a/third_party/blink/renderer/core/layout/layout_block.cc b/third_party/blink/renderer/core/layout/layout_block.cc index 63757a6..b041d4c 100644 --- a/third_party/blink/renderer/core/layout/layout_block.cc +++ b/third_party/blink/renderer/core/layout/layout_block.cc
@@ -325,8 +325,8 @@ if (before_descendant_container->IsAnonymousBlock()) { // Insert the child into the anonymous block box instead of here. if (new_child->IsInline() || - (new_child->IsFloatingOrOutOfFlowPositioned() && !IsFlexibleBox() && - !IsLayoutGrid()) || + (new_child->IsFloatingOrOutOfFlowPositioned() && + !IsFlexibleBoxIncludingNG() && !IsLayoutGrid()) || before_descendant->Parent()->SlowFirstChild() != before_descendant) { before_descendant_container->AddChild(new_child, before_descendant); } else { @@ -366,8 +366,9 @@ // here. DCHECK(!ChildrenInline()); - if (new_child->IsInline() || (new_child->IsFloatingOrOutOfFlowPositioned() && - !IsFlexibleBox() && !IsLayoutGrid())) { + if (new_child->IsInline() || + (new_child->IsFloatingOrOutOfFlowPositioned() && + !IsFlexibleBoxIncludingNG() && !IsLayoutGrid())) { // If we're inserting an inline child but all of our children are blocks, // then we have to make sure it is put into an anomyous block box. We try to // use an existing anonymous box if possible, otherwise a new one is created @@ -928,6 +929,9 @@ LayoutObject* parent = positioned_object->Parent(); bool layout_changed = false; + // TODO(dgrogan): The NG flexbox implementation doesn't have an analogous + // method yet, so abspos children of NG flexboxes that have a legacy + // containing block will not be positioned correctly. if (parent->IsFlexibleBox() && ToLayoutFlexibleBox(parent)->SetStaticPositionForPositionedLayout( *positioned_object)) { @@ -2191,7 +2195,7 @@ ComputeLogicalHeight(old_height, LogicalTop(), computed_values); if (old_height != computed_values.extent_ && - (HasPercentHeightDescendants() || IsFlexibleBox())) { + (HasPercentHeightDescendants() || IsFlexibleBoxIncludingNG())) { SetIntrinsicContentLogicalHeight(old_intrinsic_content_logical_height); return false; }
diff --git a/third_party/blink/renderer/core/layout/layout_block_flow.cc b/third_party/blink/renderer/core/layout/layout_block_flow.cc index a504698..49d412f5 100644 --- a/third_party/blink/renderer/core/layout/layout_block_flow.cc +++ b/third_party/blink/renderer/core/layout/layout_block_flow.cc
@@ -4493,7 +4493,7 @@ DISABLE_CFI_PERF bool LayoutBlockFlow::CreatesNewFormattingContext() const { if (IsInline() || IsFloatingOrOutOfFlowPositioned() || HasOverflowClip() || - IsFlexItemIncludingDeprecated() || IsCustomItem() || + IsFlexItemIncludingDeprecatedAndNG() || IsCustomItem() || IsDocumentElement() || IsGridItem() || IsWritingModeRoot() || StyleRef().Display() == EDisplay::kFlowRoot || ShouldApplyPaintContainment() || ShouldApplyLayoutContainment() ||
diff --git a/third_party/blink/renderer/core/layout/layout_box.cc b/third_party/blink/renderer/core/layout/layout_box.cc index b539787..c01f3b9 100644 --- a/third_party/blink/renderer/core/layout/layout_box.cc +++ b/third_party/blink/renderer/core/layout/layout_box.cc
@@ -2791,8 +2791,8 @@ container_logical_width != (computed_values.extent_ + computed_values.margins_.start_ + computed_values.margins_.end_) && - !IsFloating() && !IsInline() && !cb->IsFlexibleBoxIncludingDeprecated() && - !cb->IsLayoutGrid()) { + !IsFloating() && !IsInline() && + !cb->IsFlexibleBoxIncludingDeprecatedAndNG() && !cb->IsLayoutGrid()) { LayoutUnit new_margin_total = container_logical_width - computed_values.extent_; bool has_inverted_direction = cb->StyleRef().IsLeftToRightDirection() != @@ -2958,7 +2958,7 @@ // We don't stretch multiline flexboxes because they need to apply line // spacing (align-content) first. - if (parent->IsFlexibleBox() && + if (parent->IsFlexibleBoxIncludingNG() && parent->StyleRef().FlexWrap() == EFlexWrap::kNowrap && parent->StyleRef().IsColumnFlexDirection() && ColumnFlexItemHasStretchAlignment()) @@ -3005,7 +3005,7 @@ // intrinsic widths. In the case of columns that have a stretch alignment, we // go ahead and layout at the stretched size to avoid an extra layout when // applying alignment. - if (Parent()->IsFlexibleBox()) { + if (Parent()->IsFlexibleBoxIncludingNG()) { // For multiline columns, we need to apply align-content first, so we can't // stretch now. if (!Parent()->StyleRef().IsColumnFlexDirection() || @@ -3072,7 +3072,7 @@ return; } - if (containing_block->IsFlexibleBox()) { + if (containing_block->IsFlexibleBoxIncludingNG()) { // We need to let flexbox handle the margin adjustment - otherwise, flexbox // will think we're wider than we actually are and calculate line sizes // wrong. See also https://drafts.csswg.org/css-flexbox/#auto-margins
diff --git a/third_party/blink/renderer/core/layout/layout_box.h b/third_party/blink/renderer/core/layout/layout_box.h index f72f027..3b5063e 100644 --- a/third_party/blink/renderer/core/layout/layout_box.h +++ b/third_party/blink/renderer/core/layout/layout_box.h
@@ -1204,16 +1204,24 @@ bool IsCustomItemShrinkToFit() const; bool IsDeprecatedFlexItem() const { - return !IsInline() && !IsFloatingOrOutOfFlowPositioned() && Parent() && - Parent()->IsDeprecatedFlexibleBox(); + return IsFlexItemCommon() && Parent()->IsDeprecatedFlexibleBox(); } - bool IsFlexItemIncludingDeprecated() const { - return !IsInline() && !IsFloatingOrOutOfFlowPositioned() && Parent() && - Parent()->IsFlexibleBoxIncludingDeprecated(); + bool IsFlexItemIncludingDeprecatedAndNG() const { + return IsFlexItemCommon() && + Parent()->IsFlexibleBoxIncludingDeprecatedAndNG(); } + + // TODO(dgrogan): Replace the rest of the calls to IsFlexItem with + // IsFlexItemIncludingNG when all the callsites can handle an item with an NG + // parent. bool IsFlexItem() const { - return !IsInline() && !IsFloatingOrOutOfFlowPositioned() && Parent() && - Parent()->IsFlexibleBox(); + return IsFlexItemCommon() && Parent()->IsFlexibleBox(); + } + bool IsFlexItemIncludingNG() const { + return IsFlexItemCommon() && Parent()->IsFlexibleBoxIncludingNG(); + } + bool IsFlexItemCommon() const { + return !IsInline() && !IsFloatingOrOutOfFlowPositioned() && Parent(); } bool IsGridItem() const { return Parent() && Parent()->IsLayoutGrid(); }
diff --git a/third_party/blink/renderer/core/layout/layout_deprecated_flexible_box.h b/third_party/blink/renderer/core/layout/layout_deprecated_flexible_box.h index f7000047..c311e35 100644 --- a/third_party/blink/renderer/core/layout/layout_deprecated_flexible_box.h +++ b/third_party/blink/renderer/core/layout/layout_deprecated_flexible_box.h
@@ -44,6 +44,7 @@ void LayoutVerticalBox(bool relayout_children); bool IsDeprecatedFlexibleBox() const override { return true; } + bool IsFlexibleBoxIncludingDeprecatedAndNG() const override { return true; } bool IsStretchingChildren() const { return stretching_children_; } void PlaceChild(LayoutBox* child, const LayoutPoint& location);
diff --git a/third_party/blink/renderer/core/layout/layout_flexible_box.h b/third_party/blink/renderer/core/layout/layout_flexible_box.h index ab18de0f..ec49c583 100644 --- a/third_party/blink/renderer/core/layout/layout_flexible_box.h +++ b/third_party/blink/renderer/core/layout/layout_flexible_box.h
@@ -51,6 +51,8 @@ const char* GetName() const override { return "LayoutFlexibleBox"; } bool IsFlexibleBox() const final { return true; } + bool IsFlexibleBoxIncludingNG() const final { return true; } + bool IsFlexibleBoxIncludingDeprecatedAndNG() const final { return true; } void UpdateBlockLayout(bool relayout_children) final; LayoutUnit BaselinePosition(
diff --git a/third_party/blink/renderer/core/layout/layout_media.cc b/third_party/blink/renderer/core/layout/layout_media.cc index 5157116..33b61df 100644 --- a/third_party/blink/renderer/core/layout/layout_media.cc +++ b/third_party/blink/renderer/core/layout/layout_media.cc
@@ -118,7 +118,7 @@ // check can be removed if ::-webkit-media-controls is made // internal. if (child->GetNode()->IsMediaControls()) - return child->IsFlexibleBox(); + return child->IsFlexibleBoxIncludingNG(); if (child->GetNode()->IsTextTrackContainer() || child->GetNode()->IsMediaRemotingInterstitial() ||
diff --git a/third_party/blink/renderer/core/layout/layout_object.cc b/third_party/blink/renderer/core/layout/layout_object.cc index ba311b7..fa403be 100644 --- a/third_party/blink/renderer/core/layout/layout_object.cc +++ b/third_party/blink/renderer/core/layout/layout_object.cc
@@ -847,7 +847,7 @@ // In general we can't relayout a flex item independently of its container; // not only is the result incorrect due to the override size that's set, it // also messes with the cached main size on the flexbox. - if (object->IsBox() && ToLayoutBox(object)->IsFlexItem()) + if (object->IsBox() && ToLayoutBox(object)->IsFlexItemIncludingNG()) return false; // Inside multicol it's generally problematic to allow relayout roots. The
diff --git a/third_party/blink/renderer/core/layout/layout_object.h b/third_party/blink/renderer/core/layout/layout_object.h index 81c899f..300a96c 100644 --- a/third_party/blink/renderer/core/layout/layout_object.h +++ b/third_party/blink/renderer/core/layout/layout_object.h
@@ -1707,9 +1707,9 @@ // -webkit-flex). virtual bool IsFlexibleBox() const { return false; } - bool IsFlexibleBoxIncludingDeprecated() const { - return IsFlexibleBox() || IsDeprecatedFlexibleBox(); - } + virtual bool IsFlexibleBoxIncludingDeprecatedAndNG() const { return false; } + + virtual bool IsFlexibleBoxIncludingNG() const { return false; } bool IsListItemIncludingNG() const { return IsListItem() || IsLayoutNGListItem();
diff --git a/third_party/blink/renderer/core/layout/layout_table.cc b/third_party/blink/renderer/core/layout/layout_table.cc index ffc3ea9..050eb82b 100644 --- a/third_party/blink/renderer/core/layout/layout_table.cc +++ b/third_party/blink/renderer/core/layout/layout_table.cc
@@ -286,7 +286,7 @@ if (PreferredLogicalWidthsDirty()) ComputePreferredLogicalWidths(); - if (IsFlexItemIncludingDeprecated() || IsGridItem()) { + if (IsFlexItemIncludingDeprecatedAndNG() || IsGridItem()) { // TODO(jfernandez): Investigate whether the grid layout algorithm provides // all the logic needed and that we're not skipping anything essential due // to the early return here.
diff --git a/third_party/blink/renderer/core/layout/ng/inline/ng_inline_items_builder.cc b/third_party/blink/renderer/core/layout/ng/inline/ng_inline_items_builder.cc index 5888f14b..03f03ee 100644 --- a/third_party/blink/renderer/core/layout/ng/inline/ng_inline_items_builder.cc +++ b/third_party/blink/renderer/core/layout/ng/inline/ng_inline_items_builder.cc
@@ -269,6 +269,18 @@ // collapsed. if (original_string[old_item0.StartOffset()] == kSpaceCharacter) return false; + // If the last item ended with a collapsible space run with segment + // breaks, we need to run the full algorithm to apply segment break + // rules. This may result in removal of the space in the last item. + if (last_item->IsEndCollapsibleNewline()) { + const StringView old_item0_view( + original_string, old_item0.StartOffset(), old_item0.Length()); + if (ShouldRemoveNewline(text_, last_item->EndOffset() - 1, + last_item->Style(), old_item0_view, + &new_style)) { + return false; + } + } break; case NGInlineItem::kNotCollapsible: { // If the start of the original string was collapsed, it may be
diff --git a/third_party/blink/renderer/core/layout/ng/inline/ng_inline_node_test.cc b/third_party/blink/renderer/core/layout/ng/inline/ng_inline_node_test.cc index 22b84a0..a57a961 100644 --- a/third_party/blink/renderer/core/layout/ng/inline/ng_inline_node_test.cc +++ b/third_party/blink/renderer/core/layout/ng/inline/ng_inline_node_test.cc
@@ -921,6 +921,40 @@ EXPECT_EQ(String(u"foo\u2066\u2069\n\u2066\u2069bar\nbaz"), GetText()); } +// https://crbug.com/879088 +TEST_F(NGInlineNodeTest, RemoveSegmentBreakFromJapaneseInRelayout) { + SetupHtml("container", + u"<div id=container>" + u"<span>\u30ED\u30B0\u30A4\u30F3</span>" + u"\n" + u"<span>\u767B\u9332</span>" + u"<br></div>"); + EXPECT_EQ(String(u"\u30ED\u30B0\u30A4\u30F3\u767B\u9332\n"), GetText()); + + Node* new_text = Text::Create(GetDocument(), "foo"); + GetElementById("container")->appendChild(new_text); + UpdateAllLifecyclePhasesForTest(); + + EXPECT_EQ(String(u"\u30ED\u30B0\u30A4\u30F3\u767B\u9332\nfoo"), GetText()); +} + +// https://crbug.com/879088 +TEST_F(NGInlineNodeTest, RemoveSegmentBreakFromJapaneseInRelayout2) { + SetupHtml("container", + u"<div id=container>" + u"<span>\u30ED\u30B0\u30A4\u30F3</span>" + u"\n" + u"<span> \u767B\u9332</span>" + u"<br></div>"); + EXPECT_EQ(String(u"\u30ED\u30B0\u30A4\u30F3\u767B\u9332\n"), GetText()); + + Node* new_text = Text::Create(GetDocument(), "foo"); + GetElementById("container")->appendChild(new_text); + UpdateAllLifecyclePhasesForTest(); + + EXPECT_EQ(String(u"\u30ED\u30B0\u30A4\u30F3\u767B\u9332\nfoo"), GetText()); +} + TEST_F(NGInlineNodeTest, SegmentRanges) { SetupHtml("container", "<div id=container>"
diff --git a/third_party/blink/renderer/core/layout/ng/layout_ng_flexible_box.h b/third_party/blink/renderer/core/layout/ng/layout_ng_flexible_box.h index 45f1acd8..3f258fe 100644 --- a/third_party/blink/renderer/core/layout/ng/layout_ng_flexible_box.h +++ b/third_party/blink/renderer/core/layout/ng/layout_ng_flexible_box.h
@@ -17,7 +17,8 @@ void UpdateBlockLayout(bool relayout_children) override; - bool IsFlexibleBox() const final { return true; } + bool IsFlexibleBoxIncludingDeprecatedAndNG() const final { return true; } + bool IsFlexibleBoxIncludingNG() const final { return true; } bool IsLayoutNGObject() const override { return true; } const char* GetName() const override { return "LayoutNGFlexibleBox"; }
diff --git a/third_party/blink/renderer/core/layout/ng/ng_layout_input_node.h b/third_party/blink/renderer/core/layout/ng/ng_layout_input_node.h index b7cbcd6..531fdc6 100644 --- a/third_party/blink/renderer/core/layout/ng/ng_layout_input_node.h +++ b/third_party/blink/renderer/core/layout/ng/ng_layout_input_node.h
@@ -73,7 +73,7 @@ } bool IsBody() const { return IsBlock() && box_->IsBody(); } bool IsDocumentElement() const { return box_->IsDocumentElement(); } - bool IsFlexItem() const { return IsBlock() && box_->IsFlexItem(); } + bool IsFlexItem() const { return IsBlock() && box_->IsFlexItemIncludingNG(); } bool ShouldBeConsideredAsReplaced() const { return box_->ShouldBeConsideredAsReplaced(); }
diff --git a/third_party/blink/renderer/core/layout/ng/ng_length_utils.cc b/third_party/blink/renderer/core/layout/ng/ng_length_utils.cc index 50f068e..b66b82f 100644 --- a/third_party/blink/renderer/core/layout/ng/ng_length_utils.cc +++ b/third_party/blink/renderer/core/layout/ng/ng_length_utils.cc
@@ -1015,7 +1015,7 @@ if (node.Style().LogicalHeight().IsPercentOrCalc() || node.Style().LogicalMinHeight().IsPercentOrCalc() || node.Style().LogicalMaxHeight().IsPercentOrCalc() || - (node.GetLayoutBox()->IsFlexItem() && + (node.GetLayoutBox()->IsFlexItemIncludingNG() && node.Style().FlexBasis().IsPercentOrCalc())) { // This call has the side-effect of setting HasPercentHeightDescendants // correctly.
diff --git a/third_party/blink/renderer/core/layout/table_layout_algorithm_auto.cc b/third_party/blink/renderer/core/layout/table_layout_algorithm_auto.cc index f79f71c..12a378c 100644 --- a/third_party/blink/renderer/core/layout/table_layout_algorithm_auto.cc +++ b/third_party/blink/renderer/core/layout/table_layout_algorithm_auto.cc
@@ -225,7 +225,7 @@ // use ~infinity to make sure we use all available size in the containing // block. However, this just doesn't work if this is a flex or grid item, so // disallow scaling in that case. - if (cb->IsFlexibleBox() || cb->IsLayoutGrid()) + if (cb->IsFlexibleBoxIncludingNG() || cb->IsLayoutGrid()) return false; cb = cb->ContainingBlock(); }
diff --git a/third_party/blink/renderer/core/layout/text_autosizer.cc b/third_party/blink/renderer/core/layout/text_autosizer.cc index 9ad78dab..e2660a72 100644 --- a/third_party/blink/renderer/core/layout/text_autosizer.cc +++ b/third_party/blink/renderer/core/layout/text_autosizer.cc
@@ -117,7 +117,7 @@ return layout_object->IsLayoutView() || layout_object->IsFloating() || layout_object->IsOutOfFlowPositioned() || layout_object->IsTableCell() || layout_object->IsTableCaption() || - layout_object->IsFlexibleBoxIncludingDeprecated() || + layout_object->IsFlexibleBoxIncludingDeprecatedAndNG() || (containing_block && containing_block->IsHorizontalWritingMode() != layout_object->IsHorizontalWritingMode()) || layout_object->StyleRef().IsDisplayReplacedType() ||
diff --git a/third_party/blink/renderer/core/loader/threadable_loader_test.cc b/third_party/blink/renderer/core/loader/threadable_loader_test.cc index fd995353..3a17014b 100644 --- a/third_party/blink/renderer/core/loader/threadable_loader_test.cc +++ b/third_party/blink/renderer/core/loader/threadable_loader_test.cc
@@ -424,7 +424,6 @@ CallCheckpoint(1); EXPECT_CALL(GetCheckpoint(), Call(2)); - EXPECT_CALL(*Client(), DidReceiveResponseMock(_, _, _)); EXPECT_CALL(*Client(), DidFail(Truly(IsNotCancellation))); StartLoader(ErrorURL()); @@ -439,7 +438,6 @@ CallCheckpoint(1); EXPECT_CALL(GetCheckpoint(), Call(2)); - EXPECT_CALL(*Client(), DidReceiveResponseMock(_, _, _)); EXPECT_CALL(*Client(), DidFail(_)) .WillOnce(InvokeWithoutArgs(this, &ThreadableLoaderTest::CancelLoader)); @@ -455,7 +453,6 @@ CallCheckpoint(1); EXPECT_CALL(GetCheckpoint(), Call(2)); - EXPECT_CALL(*Client(), DidReceiveResponseMock(_, _, _)); EXPECT_CALL(*Client(), DidFail(_)) .WillOnce(InvokeWithoutArgs(this, &ThreadableLoaderTest::ClearLoader));
diff --git a/third_party/blink/renderer/modules/crypto/crypto_result_impl.cc b/third_party/blink/renderer/modules/crypto/crypto_result_impl.cc index 42055a9..421067b 100644 --- a/third_party/blink/renderer/modules/crypto/crypto_result_impl.cc +++ b/third_party/blink/renderer/modules/crypto/crypto_result_impl.cc
@@ -89,16 +89,6 @@ Member<CryptoResultImpl> result_; }; -CryptoResultImpl::ResultCancel::ResultCancel() : cancelled_(0) {} - -bool CryptoResultImpl::ResultCancel::Cancelled() const { - return AcquireLoad(&cancelled_); -} - -void CryptoResultImpl::ResultCancel::Cancel() { - ReleaseStore(&cancelled_, 1); -} - ExceptionCode WebCryptoErrorToExceptionCode(WebCryptoErrorType error_type) { switch (error_type) { case kWebCryptoErrorTypeNotSupported: @@ -121,7 +111,7 @@ CryptoResultImpl::CryptoResultImpl(ScriptState* script_state) : resolver_(Resolver::Create(script_state, this)), - cancel_(ResultCancel::Create()) { + cancel_(base::MakeRefCounted<CryptoResultCancel>()) { // Sync cancellation state. if (ExecutionContext::From(script_state)->IsContextDestroyed()) cancel_->Cancel();
diff --git a/third_party/blink/renderer/modules/crypto/crypto_result_impl.h b/third_party/blink/renderer/modules/crypto/crypto_result_impl.h index 4c08467..f1e97954 100644 --- a/third_party/blink/renderer/modules/crypto/crypto_result_impl.h +++ b/third_party/blink/renderer/modules/crypto/crypto_result_impl.h
@@ -78,21 +78,6 @@ private: class Resolver; - class ResultCancel : public CryptoResultCancel { - public: - static scoped_refptr<ResultCancel> Create() { - return base::AdoptRef(new ResultCancel); - } - - bool Cancelled() const override; - - void Cancel(); - - private: - ResultCancel(); - - int cancelled_; - }; void Cancel(); void ClearResolver(); @@ -108,7 +93,7 @@ // check cancellation status via this result object. So, keep a separate // cancellation status object for the purpose, which will outlive the // result object and can be safely accessed by multiple threads. - scoped_refptr<ResultCancel> cancel_; + scoped_refptr<CryptoResultCancel> cancel_; }; } // namespace blink
diff --git a/third_party/blink/renderer/modules/gamepad/gamepad_button.idl b/third_party/blink/renderer/modules/gamepad/gamepad_button.idl index a36a3b8..99fae2f2 100644 --- a/third_party/blink/renderer/modules/gamepad/gamepad_button.idl +++ b/third_party/blink/renderer/modules/gamepad/gamepad_button.idl
@@ -4,7 +4,6 @@ interface GamepadButton { readonly attribute boolean pressed; - // TODO(bajones): Enable this by default as it is part of the core spec. - [OriginTrialEnabled=WebXRGamepadSupport, MeasureAs=GamepadButtonTouched] readonly attribute boolean touched; + [MeasureAs=GamepadButtonTouched] readonly attribute boolean touched; readonly attribute double value; };
diff --git a/third_party/blink/renderer/platform/crypto_result.h b/third_party/blink/renderer/platform/crypto_result.h index b206f7bc..bd38608 100644 --- a/third_party/blink/renderer/platform/crypto_result.h +++ b/third_party/blink/renderer/platform/crypto_result.h
@@ -31,19 +31,21 @@ #ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_CRYPTO_RESULT_H_ #define THIRD_PARTY_BLINK_RENDERER_PLATFORM_CRYPTO_RESULT_H_ +#include "base/synchronization/atomic_flag.h" #include "third_party/blink/public/platform/web_crypto.h" #include "third_party/blink/renderer/platform/platform_export.h" #include "third_party/blink/renderer/platform/wtf/thread_safe_ref_counted.h" namespace blink { -// Result cancellation status interface to allow non-Blink webcrypto threads -// to query for status. +// Allows non-Blink webcrypto threads to query for cancellation status. class CryptoResultCancel : public ThreadSafeRefCounted<CryptoResultCancel> { public: - virtual ~CryptoResultCancel() = default; + bool Cancelled() const { return cancelled_.IsSet(); } + void Cancel() { cancelled_.Set(); } - virtual bool Cancelled() const = 0; + private: + base::AtomicFlag cancelled_; }; // Receives notification of completion of the crypto operation.
diff --git a/third_party/blink/renderer/platform/testing/weburl_loader_mock.cc b/third_party/blink/renderer/platform/testing/weburl_loader_mock.cc index 3a42fa3..b61d4c9 100644 --- a/third_party/blink/renderer/platform/testing/weburl_loader_mock.cc +++ b/third_party/blink/renderer/platform/testing/weburl_loader_mock.cc
@@ -56,6 +56,11 @@ delegate = default_delegate.get(); } + if (error) { + delegate->DidFail(client_, *error, data.size(), 0, 0); + return; + } + // didReceiveResponse() and didReceiveData() might end up getting ::cancel() // to be called which will make the ResourceLoader to delete |this|. base::WeakPtr<WebURLLoaderMock> self = weak_factory_.GetWeakPtr(); @@ -64,11 +69,6 @@ if (!self) return; - if (error) { - delegate->DidFail(client_, *error, data.size(), 0, 0); - return; - } - data.ForEachSegment([this, &delegate, &self](const char* segment, size_t segment_size, size_t segment_offset) {
diff --git a/third_party/blink/tools/blinkpy/common/net/buildbot.py b/third_party/blink/tools/blinkpy/common/net/buildbot.py index b218456..3f8b6ac 100644 --- a/third_party/blink/tools/blinkpy/common/net/buildbot.py +++ b/third_party/blink/tools/blinkpy/common/net/buildbot.py
@@ -34,7 +34,7 @@ import urllib2 from blinkpy.common.memoized import memoized -from blinkpy.common.net.layout_test_results import LayoutTestResults +from blinkpy.common.net.web_test_results import WebTestResults from blinkpy.common.net.network_transaction import NetworkTransaction from blinkpy.web_tests.layout_package import json_results_generator @@ -57,13 +57,13 @@ class BuildBot(object): """This class represents an interface to BuildBot-related functionality. - This includes fetching layout test results from Google Storage; - for more information about the layout test result format, see: + This includes fetching web test results from Google Storage; + for more information about the web test result format, see: https://www.chromium.org/developers/the-json-test-results-format """ def results_url(self, builder_name, build_number=None, step_name=None): - """Returns a URL for one set of archived layout test results. + """Returns a URL for one set of archived web test results. If a build number is given, this will be results for a particular run; otherwise it will be the accumulated results URL, which should have @@ -93,7 +93,7 @@ def fetch_retry_summary_json(self, build): """Fetches and returns the text of the archived retry_summary file. - This file is expected to contain the results of retrying layout tests + This file is expected to contain the results of retrying web tests with and without a patch in a try job. It includes lists of tests that failed only with the patch ("failures"), and tests that failed both with and without ("ignored"). @@ -107,10 +107,10 @@ @memoized def fetch_results(self, build, full=False): - """Returns a LayoutTestResults object for results from a given Build. + """Returns a WebTestResults object for results from a given Build. Uses full_results.json if full is True, otherwise failing_results.json. """ - return self.fetch_layout_test_results( + return self.fetch_web_test_results( self.results_url(build.builder_name, build.build_number, step_name=self.get_layout_test_step_name(build)), full) @@ -146,15 +146,15 @@ suites = list(set(suites)) if len(suites) != 1: raise Exception( - 'build %s on builder %s expected to only have one layout test ' + 'build %s on builder %s expected to only have one web test ' 'step, instead has %s' % ( build.build_number, build.builder_name, suites)) return suites[0] @memoized - def fetch_layout_test_results(self, results_url, full=False): - """Returns a LayoutTestResults object for results fetched from a given URL. + def fetch_web_test_results(self, results_url, full=False): + """Returns a WebTestResults object for results fetched from a given URL. Uses full_results.json if full is True, otherwise failing_results.json. """ base_filename = 'full_results.json' if full else 'failing_results.json' @@ -167,7 +167,7 @@ lambda: self.fetch_file('%s/LAST_CHANGE' % results_url)) if revision is None: _log.debug('Got 404 response from:\n%s/LAST_CHANGE', results_url) - return LayoutTestResults.results_from_string(results_file, revision) + return WebTestResults.results_from_string(results_file, revision) def fetch_file(self, url): # It seems this can return None if the url redirects and then returns 404.
diff --git a/third_party/blink/tools/blinkpy/common/net/buildbot_unittest.py b/third_party/blink/tools/blinkpy/common/net/buildbot_unittest.py index 231b923..32bef0b 100644 --- a/third_party/blink/tools/blinkpy/common/net/buildbot_unittest.py +++ b/third_party/blink/tools/blinkpy/common/net/buildbot_unittest.py
@@ -70,21 +70,21 @@ BuildBot().accumulated_results_url_base('WebKit Mac10.8 (dbg)'), 'https://test-results.appspot.com/data/layout_results/WebKit_Mac10_8__dbg_/results/layout-test-results') - def test_fetch_layout_test_results_with_no_results_fetched(self): + def test_fetch_web_test_results_with_no_results_fetched(self): buildbot = BuildBot() def fetch_file(url): return None if url.endswith('failing_results.json') else 'contents' buildbot.fetch_file = fetch_file - results = buildbot.fetch_layout_test_results(buildbot.results_url('B')) + results = buildbot.fetch_web_test_results(buildbot.results_url('B')) self.assertIsNone(results) self.assertLog([ 'DEBUG: Got 404 response from:\n' 'https://test-results.appspot.com/data/layout_results/B/results/layout-test-results/failing_results.json\n' ]) - def test_fetch_layout_test_results_weird_step_name(self): + def test_fetch_web_test_results_weird_step_name(self): buildbot = BuildBot() def fetch_file(url):
diff --git a/third_party/blink/tools/blinkpy/common/net/layout_test_results.py b/third_party/blink/tools/blinkpy/common/net/web_test_results.py similarity index 88% rename from third_party/blink/tools/blinkpy/common/net/layout_test_results.py rename to third_party/blink/tools/blinkpy/common/net/web_test_results.py index 02d7d59..65b8259 100644 --- a/third_party/blink/tools/blinkpy/common/net/layout_test_results.py +++ b/third_party/blink/tools/blinkpy/common/net/web_test_results.py
@@ -32,7 +32,7 @@ from blinkpy.web_tests.layout_package import json_results_generator -class LayoutTestResult(object): +class WebTestResult(object): def __init__(self, test_name, result_dict): self._test_name = test_name @@ -78,17 +78,17 @@ return self.last_retry_result() == 'MISSING' -# FIXME: This should be unified with ResultsSummary or other NRWT layout tests code -# in the layout_tests package. +# FIXME: This should be unified with ResultsSummary or other NRWT web tests code +# in the web_tests package. # This doesn't belong in common.net, but we don't have a better place for it yet. -class LayoutTestResults(object): +class WebTestResults(object): @classmethod def results_from_string(cls, string, chromium_revision=None): - """Creates a LayoutTestResults object from a test result JSON string. + """Creates a WebTestResults object from a test result JSON string. Args: - string: JSON string containing layout test result. + string: JSON string containing web test result. chromium_revision: If given, it will override the chromium_revision field in json, to indicate the last revision that has completed uploading onto the storage server. chromium_revision can be a @@ -131,32 +131,32 @@ if part not in tree: return None tree = tree[part] - return LayoutTestResult(test, tree) + return WebTestResult(test, tree) def for_each_test(self, handler): - LayoutTestResults._for_each_test(self._test_result_tree(), handler, '') + WebTestResults._for_each_test(self._test_result_tree(), handler, '') @staticmethod def _for_each_test(tree, handler, prefix=''): for key in tree: new_prefix = (prefix + '/' + key) if prefix else key if 'actual' not in tree[key]: - LayoutTestResults._for_each_test(tree[key], handler, new_prefix) + WebTestResults._for_each_test(tree[key], handler, new_prefix) else: - handler(LayoutTestResult(new_prefix, tree[key])) + handler(WebTestResult(new_prefix, tree[key])) def _test_result_tree(self): return self._results['tests'] def _filter_tests(self, result_filter): - """Returns LayoutTestResult objects for tests which pass the given filter.""" + """Returns WebTestResult objects for tests which pass the given filter.""" results = [] def add_if_passes(result): if result_filter(result): results.append(result) - LayoutTestResults._for_each_test(self._test_result_tree(), add_if_passes) + WebTestResults._for_each_test(self._test_result_tree(), add_if_passes) return sorted(results, key=lambda r: r.test_name()) def didnt_run_as_expected_results(self):
diff --git a/third_party/blink/tools/blinkpy/common/net/layout_test_results_unittest.py b/third_party/blink/tools/blinkpy/common/net/web_test_results_unittest.py similarity index 88% rename from third_party/blink/tools/blinkpy/common/net/layout_test_results_unittest.py rename to third_party/blink/tools/blinkpy/common/net/web_test_results_unittest.py index 32ca9140..2f0b6af 100644 --- a/third_party/blink/tools/blinkpy/common/net/layout_test_results_unittest.py +++ b/third_party/blink/tools/blinkpy/common/net/web_test_results_unittest.py
@@ -28,10 +28,10 @@ import unittest -from blinkpy.common.net.layout_test_results import LayoutTestResults +from blinkpy.common.net.web_test_results import WebTestResults -class LayoutTestResultsTest(unittest.TestCase): +class WebTestResultsTest(unittest.TestCase): # The real files have no whitespace, but newlines make this much more readable. example_full_results_json = """ADD_RESULTS({ "tests": { @@ -97,26 +97,26 @@ });""" def test_results_from_string(self): - self.assertIsNone(LayoutTestResults.results_from_string(None)) - self.assertIsNone(LayoutTestResults.results_from_string('')) + self.assertIsNone(WebTestResults.results_from_string(None)) + self.assertIsNone(WebTestResults.results_from_string('')) def test_was_interrupted(self): - self.assertTrue(LayoutTestResults.results_from_string( + self.assertTrue(WebTestResults.results_from_string( 'ADD_RESULTS({"tests":{},"interrupted":true});').run_was_interrupted()) - self.assertFalse(LayoutTestResults.results_from_string( + self.assertFalse(WebTestResults.results_from_string( 'ADD_RESULTS({"tests":{},"interrupted":false});').run_was_interrupted()) def test_chromium_revision(self): - self.assertEqual(LayoutTestResults.results_from_string(self.example_full_results_json).chromium_revision(), 1234) + self.assertEqual(WebTestResults.results_from_string(self.example_full_results_json).chromium_revision(), 1234) def test_actual_results(self): - results = LayoutTestResults.results_from_string(self.example_full_results_json) + results = WebTestResults.results_from_string(self.example_full_results_json) self.assertEqual(results.result_for_test('fast/dom/prototype-banana.html').actual_results(), 'PASS') self.assertEqual(results.result_for_test('fast/dom/prototype-taco.html').actual_results(), 'PASS TEXT') self.assertFalse(results.result_for_test('nonexistant.html')) def test_didnt_run_as_expected_results(self): - results = LayoutTestResults.results_from_string(self.example_full_results_json) + results = WebTestResults.results_from_string(self.example_full_results_json) self.assertEqual( [r.test_name() for r in results.didnt_run_as_expected_results()], [ @@ -130,7 +130,7 @@ ]) def test_didnt_run_as_expected_slow_test(self): - results = LayoutTestResults({ + results = WebTestResults({ 'tests': { 'fast': { 'dom': {
diff --git a/third_party/blink/tools/blinkpy/presubmit/audit_non_blink_usage.py b/third_party/blink/tools/blinkpy/presubmit/audit_non_blink_usage.py index 5e20b995c..1e88f1b9 100755 --- a/third_party/blink/tools/blinkpy/presubmit/audit_non_blink_usage.py +++ b/third_party/blink/tools/blinkpy/presubmit/audit_non_blink_usage.py
@@ -134,6 +134,7 @@ 'base::debug::.+', # Base atomic utilities + 'base::AtomicFlag', 'base::AtomicSequenceNumber', # Task traits
diff --git a/third_party/blink/tools/blinkpy/tool/commands/rebaseline_cl.py b/third_party/blink/tools/blinkpy/tool/commands/rebaseline_cl.py index 0f03959..06bc32ae 100644 --- a/third_party/blink/tools/blinkpy/tool/commands/rebaseline_cl.py +++ b/third_party/blink/tools/blinkpy/tool/commands/rebaseline_cl.py
@@ -222,7 +222,7 @@ jobs: A dict mapping Build objects to TryJobStatus objects. Returns: - A dict mapping Build to LayoutTestResults for all completed jobs. + A dict mapping Build to WebTestResults for all completed jobs. """ buildbot = self._tool.buildbot results = {} @@ -237,12 +237,12 @@ # layout tests to download baselines for. continue results_url = buildbot.results_url(build.builder_name, build.build_number) - layout_test_results = buildbot.fetch_results(build) - if layout_test_results is None: + web_test_results = buildbot.fetch_results(build) + if web_test_results is None: _log.info('Failed to fetch results for "%s".', build.builder_name) _log.info('Results URL: %s/results.html', results_url) continue - results[build] = layout_test_results + results[build] = web_test_results return results def _make_test_baseline_set_from_file(self, filename, builds_to_results): @@ -266,7 +266,7 @@ Args: tests: A list of tests. - builds_to_results: A dict mapping Builds to LayoutTestResults. + builds_to_results: A dict mapping Builds to WebTestResults. Returns: A TestBaselineSet object. @@ -284,7 +284,7 @@ modified tests will be rebaselined (depending on only_changed_tests). Args: - builds_to_results: A dict mapping Builds to LayoutTestResults. + builds_to_results: A dict mapping Builds to WebTestResults. only_changed_tests: Whether to only include baselines for tests that are changed in this CL. If False, all new baselines for failing tests will be downloaded, even for tests that were not modified. @@ -322,7 +322,7 @@ Args: build: A Build instance. - layout_test_results: A LayoutTestResults instance or None. + layout_test_results: A WebTestResults instance or None. Returns: A sorted list of tests to rebaseline for this build.
diff --git a/third_party/blink/tools/blinkpy/tool/commands/rebaseline_cl_unittest.py b/third_party/blink/tools/blinkpy/tool/commands/rebaseline_cl_unittest.py index ba88c33..6976ba2 100644 --- a/third_party/blink/tools/blinkpy/tool/commands/rebaseline_cl_unittest.py +++ b/third_party/blink/tools/blinkpy/tool/commands/rebaseline_cl_unittest.py
@@ -10,7 +10,7 @@ from blinkpy.common.net.buildbot import Build from blinkpy.common.net.git_cl import TryJobStatus from blinkpy.common.net.git_cl_mock import MockGitCL -from blinkpy.common.net.layout_test_results import LayoutTestResults +from blinkpy.common.net.web_test_results import WebTestResults from blinkpy.common.path_finder import RELATIVE_WEB_TESTS from blinkpy.common.system.log_testing import LoggingTestCase from blinkpy.tool.commands.rebaseline import TestBaselineSet @@ -59,7 +59,7 @@ 'is_try_builder': True, }, }) - layout_test_results = LayoutTestResults({ + layout_test_results = WebTestResults({ 'tests': { 'one': { 'crash.html': {'expected': 'PASS', 'actual': 'CRASH', 'is_unexpected': True},
diff --git a/third_party/blink/tools/blinkpy/tool/commands/rebaseline_server.py b/third_party/blink/tools/blinkpy/tool/commands/rebaseline_server.py index 621e833f..27ff77d 100644 --- a/third_party/blink/tools/blinkpy/tool/commands/rebaseline_server.py +++ b/third_party/blink/tools/blinkpy/tool/commands/rebaseline_server.py
@@ -32,7 +32,7 @@ """ from blinkpy.common.host import Host -from blinkpy.common.net.layout_test_results import LayoutTestResults +from blinkpy.common.net.web_test_results import WebTestResults from blinkpy.web_tests.layout_package import json_results_generator from blinkpy.tool.commands.abstract_local_server_command import AbstractLocalServerCommand from blinkpy.tool.servers.rebaseline_server import get_test_baselines, RebaselineHTTPServer, STATE_NEEDS_REBASELINE @@ -76,7 +76,7 @@ result_dict['baselines'] = get_test_baselines(result.test_name(), self._test_config) new_tests_subtree[result.test_name()] = result_dict - LayoutTestResults(results_json).for_each_test(gather_baselines_for_test) + WebTestResults(results_json).for_each_test(gather_baselines_for_test) results_json['tests'] = new_tests_subtree def _prepare_config(self, options, args, tool):
diff --git a/third_party/blink/tools/blinkpy/tool/commands/rebaseline_unittest.py b/third_party/blink/tools/blinkpy/tool/commands/rebaseline_unittest.py index 91e779b..e54d5ee 100644 --- a/third_party/blink/tools/blinkpy/tool/commands/rebaseline_unittest.py +++ b/third_party/blink/tools/blinkpy/tool/commands/rebaseline_unittest.py
@@ -7,7 +7,7 @@ import unittest from blinkpy.common.net.buildbot import Build -from blinkpy.common.net.layout_test_results import LayoutTestResults +from blinkpy.common.net.web_test_results import WebTestResults from blinkpy.common.path_finder import RELATIVE_WEB_TESTS from blinkpy.common.system.executive_mock import MockExecutive from blinkpy.tool.commands.rebaseline import ( @@ -89,7 +89,7 @@ def _setup_mock_build_data(self): for builder in ['MOCK Win7', 'MOCK Win7 (dbg)', 'MOCK Mac10.11']: - self.tool.buildbot.set_results(Build(builder), LayoutTestResults({ + self.tool.buildbot.set_results(Build(builder), WebTestResults({ 'tests': { 'userscripts': { 'first-test.html': { @@ -178,7 +178,7 @@ }, **kwargs)) def test_rebaseline_test_passes_on_all_builders(self): - self.tool.buildbot.set_results(Build('MOCK Win7'), LayoutTestResults({ + self.tool.buildbot.set_results(Build('MOCK Win7'), WebTestResults({ 'tests': { 'userscripts': { 'first-test.html': { @@ -467,7 +467,7 @@ ('Bug(x) [ Mac ] userscripts/skipped-test.html [ WontFix ]\n' 'Bug(y) [ Win ] userscripts/skipped-test.html [ Skip ]\n')) self._write('userscripts/skipped-test.html', 'Dummy test contents') - self.tool.buildbot.set_results(Build('MOCK Mac10.11'), LayoutTestResults({ + self.tool.buildbot.set_results(Build('MOCK Mac10.11'), WebTestResults({ 'tests': { 'userscripts': { 'skipped-test.html': { @@ -477,7 +477,7 @@ } } })) - self.tool.buildbot.set_results(Build('MOCK Win7'), LayoutTestResults({ + self.tool.buildbot.set_results(Build('MOCK Win7'), WebTestResults({ 'tests': { 'userscripts': { 'skipped-test.html': { @@ -504,7 +504,7 @@ # Flaky expectations should be kept even if the test passes. self._write(self.test_expectations_path, 'Bug(x) userscripts/flaky-test.html [ Pass Failure ]\n') self._write('userscripts/flaky-test.html', 'Dummy test contents') - self.tool.buildbot.set_results(Build('MOCK Mac10.11'), LayoutTestResults({ + self.tool.buildbot.set_results(Build('MOCK Mac10.11'), WebTestResults({ 'tests': { 'userscripts': { 'flaky-test.html': { @@ -530,7 +530,7 @@ self._write(self.test_expectations_path, 'Bug(foo) userscripts/all-pass.html [ Failure ]\n') self._write('userscripts/all-pass.html', 'Dummy test contents') test_baseline_set = TestBaselineSet(self.tool) - self.tool.buildbot.set_results(Build('MOCK Mac10.11'), LayoutTestResults({ + self.tool.buildbot.set_results(Build('MOCK Mac10.11'), WebTestResults({ 'tests': { 'userscripts': { 'all-pass.html': { @@ -557,7 +557,7 @@ self._write('userscripts/all-pass.html', 'Dummy test contents') test_baseline_set = TestBaselineSet(self.tool) for builder in ['MOCK Win7', 'MOCK Win10', 'MOCK Mac10.10', 'MOCK Mac10.11', 'MOCK Precise', 'MOCK Trusty']: - self.tool.buildbot.set_results(Build(builder), LayoutTestResults({ + self.tool.buildbot.set_results(Build(builder), WebTestResults({ 'tests': { 'userscripts': { 'all-pass.html': { @@ -584,7 +584,7 @@ self._write(self.test_expectations_path, 'Bug(foo) userscripts/all-pass.html [ Failure ]\n') self._write('userscripts/all-pass.html', 'Dummy test contents') test_baseline_set = TestBaselineSet(self.tool) - self.tool.buildbot.set_results(Build('MOCK Mac10.11'), LayoutTestResults({ + self.tool.buildbot.set_results(Build('MOCK Mac10.11'), WebTestResults({ 'tests': { 'userscripts': { 'all-pass.html': {
diff --git a/third_party/blink/tools/blinkpy/w3c/wpt_expectations_updater.py b/third_party/blink/tools/blinkpy/w3c/wpt_expectations_updater.py index 6c71e5b..9ae21130 100644 --- a/third_party/blink/tools/blinkpy/w3c/wpt_expectations_updater.py +++ b/third_party/blink/tools/blinkpy/w3c/wpt_expectations_updater.py
@@ -151,7 +151,7 @@ Args: full_port_name: The fully-qualified port name, e.g. "win-win10". - layout_test_results: A list of LayoutTestResult objects. + layout_test_results: A list of WebTestResult objects. Returns: A dictionary with the structure: {
diff --git a/third_party/blink/tools/blinkpy/w3c/wpt_expectations_updater_unittest.py b/third_party/blink/tools/blinkpy/w3c/wpt_expectations_updater_unittest.py index cc6236c..1e0dcc8 100644 --- a/third_party/blink/tools/blinkpy/w3c/wpt_expectations_updater_unittest.py +++ b/third_party/blink/tools/blinkpy/w3c/wpt_expectations_updater_unittest.py
@@ -10,7 +10,7 @@ from blinkpy.common.net.buildbot_mock import MockBuildBot from blinkpy.common.net.git_cl import TryJobStatus from blinkpy.common.net.git_cl_mock import MockGitCL -from blinkpy.common.net.layout_test_results import LayoutTestResult, LayoutTestResults +from blinkpy.common.net.web_test_results import WebTestResult, WebTestResults from blinkpy.common.system.executive import ScriptError from blinkpy.common.system.log_testing import LoggingTestCase from blinkpy.w3c.wpt_expectations_updater import WPTExpectationsUpdater, SimpleTestResult, MARKER_COMMENT @@ -106,7 +106,7 @@ # of the tests passed. host.buildbot.set_results( Build('MOCK Try Mac10.10', 333), - LayoutTestResults({ + WebTestResults({ 'tests': { 'external': { 'wpt': { @@ -133,7 +133,7 @@ def test_get_failing_results_dict_only_passing_results(self): host = self.mock_host() - host.buildbot.set_results(Build('MOCK Try Mac10.10', 123), LayoutTestResults({ + host.buildbot.set_results(Build('MOCK Try Mac10.10', 123), WebTestResults({ 'tests': { 'external': { 'wpt': { @@ -153,7 +153,7 @@ def test_get_failing_results_dict_unexpected_pass(self): host = self.mock_host() - host.buildbot.set_results(Build('MOCK Try Mac10.10', 123), LayoutTestResults({ + host.buildbot.set_results(Build('MOCK Try Mac10.10', 123), WebTestResults({ 'tests': { 'external': { 'wpt': { @@ -182,7 +182,7 @@ def test_get_failing_results_dict_some_failing_results(self): host = self.mock_host() - host.buildbot.set_results(Build('MOCK Try Mac10.10', 123), LayoutTestResults({ + host.buildbot.set_results(Build('MOCK Try Mac10.10', 123), WebTestResults({ 'tests': { 'external': { 'wpt': { @@ -213,7 +213,7 @@ def test_get_failing_results_dict_non_wpt_test(self): host = self.mock_host() - host.buildbot.set_results(Build('MOCK Try Mac10.10', 123), LayoutTestResults({ + host.buildbot.set_results(Build('MOCK Try Mac10.10', 123), WebTestResults({ 'tests': { 'x': { 'failing-test.html': { @@ -470,7 +470,7 @@ def test_generate_results_dict(self): updater = WPTExpectationsUpdater(self.mock_host()) layout_test_list = [ - LayoutTestResult( + WebTestResult( 'external/wpt/test/name.html', { 'expected': 'bar', 'actual': 'foo',
diff --git a/third_party/blink/tools/blinkpy/web_tests/controllers/manager.py b/third_party/blink/tools/blinkpy/web_tests/controllers/manager.py index 0d0554a..dc09e868 100644 --- a/third_party/blink/tools/blinkpy/web_tests/controllers/manager.py +++ b/third_party/blink/tools/blinkpy/web_tests/controllers/manager.py
@@ -48,9 +48,9 @@ from blinkpy.common.path_finder import PathFinder from blinkpy.tool import grammar from blinkpy.w3c.wpt_manifest import WPTManifest -from blinkpy.web_tests.controllers.layout_test_finder import LayoutTestFinder -from blinkpy.web_tests.controllers.layout_test_runner import LayoutTestRunner from blinkpy.web_tests.controllers.test_result_writer import TestResultWriter +from blinkpy.web_tests.controllers.web_test_finder import WebTestFinder +from blinkpy.web_tests.controllers.web_test_runner import WebTestRunner from blinkpy.web_tests.layout_package import json_results_generator from blinkpy.web_tests.models import test_expectations from blinkpy.web_tests.models import test_failures @@ -89,9 +89,9 @@ self._websockets_server_started = False self._results_directory = self._port.results_directory() - self._finder = LayoutTestFinder(self._port, self._options) + self._finder = WebTestFinder(self._port, self._options) self._path_finder = PathFinder(port.host.filesystem) - self._runner = LayoutTestRunner(self._options, self._port, self._printer, self._results_directory, self._test_is_slow) + self._runner = WebTestRunner(self._options, self._port, self._printer, self._results_directory, self._test_is_slow) def run(self, args): """Runs the tests and return a RunDetails object with the results."""
diff --git a/third_party/blink/tools/blinkpy/web_tests/controllers/layout_test_finder.py b/third_party/blink/tools/blinkpy/web_tests/controllers/web_test_finder.py similarity index 99% rename from third_party/blink/tools/blinkpy/web_tests/controllers/layout_test_finder.py rename to third_party/blink/tools/blinkpy/web_tests/controllers/web_test_finder.py index 44921dcc..9a8c96e1 100644 --- a/third_party/blink/tools/blinkpy/web_tests/controllers/layout_test_finder.py +++ b/third_party/blink/tools/blinkpy/web_tests/controllers/web_test_finder.py
@@ -39,7 +39,7 @@ _log = logging.getLogger(__name__) -class LayoutTestFinder(object): +class WebTestFinder(object): def __init__(self, port, options): self._port = port
diff --git a/third_party/blink/tools/blinkpy/web_tests/controllers/layout_test_finder_unittest.py b/third_party/blink/tools/blinkpy/web_tests/controllers/web_test_finder_unittest.py similarity index 92% rename from third_party/blink/tools/blinkpy/web_tests/controllers/layout_test_finder_unittest.py rename to third_party/blink/tools/blinkpy/web_tests/controllers/web_test_finder_unittest.py index a3474ac48..f932b7c 100644 --- a/third_party/blink/tools/blinkpy/web_tests/controllers/layout_test_finder_unittest.py +++ b/third_party/blink/tools/blinkpy/web_tests/controllers/web_test_finder_unittest.py
@@ -8,7 +8,7 @@ from blinkpy.common import path_finder from blinkpy.common.host_mock import MockHost -from blinkpy.web_tests.controllers import layout_test_finder +from blinkpy.web_tests.controllers import web_test_finder _MOCK_ROOT = os.path.join( path_finder.get_chromium_src_dir(), 'third_party', 'pymock') @@ -16,7 +16,7 @@ import mock -class LayoutTestFinderTests(unittest.TestCase): +class WebTestFinderTests(unittest.TestCase): def test_find_fastest_tests(self): host = MockHost() @@ -37,7 +37,7 @@ port.tests = lambda paths: paths or all_tests - finder = layout_test_finder.LayoutTestFinder(port, {}) + finder = web_test_finder.WebTestFinder(port, {}) finder._times_trie = lambda: { 'fast': { 'css': { @@ -79,7 +79,7 @@ port.tests = lambda paths: paths or all_tests - finder = layout_test_finder.LayoutTestFinder(port, {}) + finder = web_test_finder.WebTestFinder(port, {}) finder._times_trie = lambda: { 'fast': { @@ -95,7 +95,7 @@ self.assertEqual(set(tests[1]), set(['fast/css/1.html'])) def test_split_chunks(self): - split = layout_test_finder.LayoutTestFinder._split_into_chunks # pylint: disable=protected-access + split = web_test_finder.WebTestFinder._split_into_chunks # pylint: disable=protected-access with mock.patch('__builtin__.hash', int):
diff --git a/third_party/blink/tools/blinkpy/web_tests/controllers/layout_test_runner.py b/third_party/blink/tools/blinkpy/web_tests/controllers/web_test_runner.py similarity index 99% rename from third_party/blink/tools/blinkpy/web_tests/controllers/layout_test_runner.py rename to third_party/blink/tools/blinkpy/web_tests/controllers/web_test_runner.py index c4f21406..1d7ec88 100644 --- a/third_party/blink/tools/blinkpy/web_tests/controllers/layout_test_runner.py +++ b/third_party/blink/tools/blinkpy/web_tests/controllers/web_test_runner.py
@@ -55,7 +55,7 @@ return self.__class__, (self.reason,) -class LayoutTestRunner(object): +class WebTestRunner(object): def __init__(self, options, port, printer, results_directory, test_is_slow_fn): self._options = options
diff --git a/third_party/blink/tools/blinkpy/web_tests/controllers/layout_test_runner_unittest.py b/third_party/blink/tools/blinkpy/web_tests/controllers/web_test_runner_unittes.py similarity index 98% rename from third_party/blink/tools/blinkpy/web_tests/controllers/layout_test_runner_unittest.py rename to third_party/blink/tools/blinkpy/web_tests/controllers/web_test_runner_unittes.py index 0df3ce4..bd90f36 100644 --- a/third_party/blink/tools/blinkpy/web_tests/controllers/layout_test_runner_unittest.py +++ b/third_party/blink/tools/blinkpy/web_tests/controllers/web_test_runner_unittes.py
@@ -32,7 +32,7 @@ from blinkpy.common.host_mock import MockHost from blinkpy.common.system.system_host_mock import MockSystemHost from blinkpy.web_tests import run_webkit_tests -from blinkpy.web_tests.controllers.layout_test_runner import LayoutTestRunner, Sharder, TestRunInterruptedException +from blinkpy.web_tests.controllers.web_test_runner import WebTestRunner, Sharder, TestRunInterruptedException from blinkpy.web_tests.models import test_expectations from blinkpy.web_tests.models import test_failures from blinkpy.web_tests.models.test_run_results import TestRunResults @@ -70,7 +70,7 @@ pass -class LockCheckingRunner(LayoutTestRunner): +class LockCheckingRunner(WebTestRunner): def __init__(self, port, options, printer, tester, http_lock): super(LockCheckingRunner, self).__init__(options, port, printer, port.results_directory(), lambda test_name: False) @@ -79,7 +79,7 @@ self._should_have_http_lock = http_lock -class LayoutTestRunnerTests(unittest.TestCase): +class WebTestRunnerTests(unittest.TestCase): # pylint: disable=protected-access
diff --git a/third_party/blink/tools/blinkpy/web_tests/models/test_expectations.py b/third_party/blink/tools/blinkpy/web_tests/models/test_expectations.py index c38853af..eaacaed 100644 --- a/third_party/blink/tools/blinkpy/web_tests/models/test_expectations.py +++ b/third_party/blink/tools/blinkpy/web_tests/models/test_expectations.py
@@ -1017,7 +1017,7 @@ return set(suffixes) @staticmethod - # test_result is an instance of blinkpy.common.net.layout_test_results.LayoutTestResult + # test_result is an instance of blinkpy.common.net.web_test_results.WebTestResult def suffixes_for_test_result(test_result): suffixes = set() actual_results = test_result.actual_results()
diff --git a/third_party/blink/tools/blinkpy/web_tests/try_flag_unittest.py b/third_party/blink/tools/blinkpy/web_tests/try_flag_unittest.py index 2283d8d..0c58636e 100644 --- a/third_party/blink/tools/blinkpy/web_tests/try_flag_unittest.py +++ b/third_party/blink/tools/blinkpy/web_tests/try_flag_unittest.py
@@ -8,7 +8,7 @@ from blinkpy.common.net.buildbot import Build from blinkpy.common.net.git_cl import TryJobStatus from blinkpy.common.net.git_cl_mock import MockGitCL -from blinkpy.common.net.layout_test_results import LayoutTestResults +from blinkpy.common.net.web_test_results import WebTestResults from blinkpy.common.path_finder import PathFinder from blinkpy.web_tests.try_flag import TryFlag @@ -69,7 +69,7 @@ self._run_trigger_test(regenerate=True) def _setup_mock_results(self, buildbot): - buildbot.set_results(self.linux_build, LayoutTestResults({ + buildbot.set_results(self.linux_build, WebTestResults({ 'tests': { 'something': { 'fail-everywhere.html': { @@ -85,7 +85,7 @@ } } })) - buildbot.set_results(self.win_build, LayoutTestResults({ + buildbot.set_results(self.win_build, WebTestResults({ 'tests': { 'something': { 'fail-everywhere.html': { @@ -101,7 +101,7 @@ } } })) - buildbot.set_results(self.mac_build, LayoutTestResults({ + buildbot.set_results(self.mac_build, WebTestResults({ 'tests': { 'something': { 'pass-unexpectedly-mac.html': {
diff --git a/third_party/blink/web_tests/TestExpectations b/third_party/blink/web_tests/TestExpectations index d86b2fc..56e6b7e 100644 --- a/third_party/blink/web_tests/TestExpectations +++ b/third_party/blink/web_tests/TestExpectations
@@ -744,6 +744,7 @@ # Maybe a Mac-specific rebaselining issue. crbug.com/846557 [ Mac ] virtual/layout_ng_experimental/css3/flexbox/button.html [ Skip ] +crbug.com/591099 [ Mac ] virtual/layout_ng_experimental/external/wpt/css/css-flexbox/flex-vertical-align-effect.html [ Failure ] crbug.com/835810 [ Win7 ] http/tests/devtools/startup/dom-storage-open.js [ Pass Timeout ] @@ -1537,7 +1538,7 @@ crbug.com/591099 virtual/layout_ng_experimental/css3/flexbox/flex-align-end.html [ Skip ] crbug.com/591099 virtual/layout_ng_experimental/css3/flexbox/flex-align-max.html [ Skip ] crbug.com/591099 virtual/layout_ng_experimental/css3/flexbox/flex-align-stretch.html [ Skip ] -crbug.com/591099 virtual/layout_ng_experimental/css3/flexbox/flex-align-vertical-writing-mode.html [ Skip ] +crbug.com/591099 virtual/layout_ng_experimental/css3/flexbox/flex-align-vertical-writing-mode.html [ Failure ] crbug.com/591099 virtual/layout_ng_experimental/css3/flexbox/flex-align.html [ Failure ] crbug.com/591099 virtual/layout_ng_experimental/css3/flexbox/flex-column-relayout-assert.html [ Skip ] crbug.com/591099 virtual/layout_ng_experimental/css3/flexbox/flex-factor-less-than-one.html [ Skip ] @@ -1564,17 +1565,14 @@ crbug.com/591099 virtual/layout_ng_experimental/css3/flexbox/flexbox-lines-must-be-stretched-by-default.html [ Failure ] crbug.com/591099 virtual/layout_ng_experimental/css3/flexbox/flexbox-overflow-auto.html [ Skip ] crbug.com/591099 virtual/layout_ng_experimental/css3/flexbox/flexbox-width-with-overflow-auto.html [ Skip ] -crbug.com/591099 virtual/layout_ng_experimental/css3/flexbox/flexbox-with-multi-column-property.html [ Skip ] crbug.com/591099 virtual/layout_ng_experimental/css3/flexbox/flexitem.html [ Skip ] crbug.com/591099 virtual/layout_ng_experimental/css3/flexbox/float-inside-flexitem.html [ Skip ] crbug.com/591099 virtual/layout_ng_experimental/css3/flexbox/floated-flexbox.html [ Skip ] -crbug.com/591099 virtual/layout_ng_experimental/css3/flexbox/inline-flex.html [ Skip ] crbug.com/591099 virtual/layout_ng_experimental/css3/flexbox/inline-flexbox-ignore-firstLine.html [ Skip ] crbug.com/591099 virtual/layout_ng_experimental/css3/flexbox/inline-flexbox-wrap-vertically-width-calculation.html [ Skip ] crbug.com/591099 virtual/layout_ng_experimental/css3/flexbox/intrinsic-min-width-applies-with-fixed-width.html [ Skip ] crbug.com/591099 virtual/layout_ng_experimental/css3/flexbox/intrinsic-width-orthogonal-writing-mode.html [ Skip ] crbug.com/591099 virtual/layout_ng_experimental/css3/flexbox/justify-content-space-between.html [ Skip ] -crbug.com/591099 virtual/layout_ng_experimental/css3/flexbox/large-flex-shrink-assert.html [ Skip ] crbug.com/591099 virtual/layout_ng_experimental/css3/flexbox/line-wrapping.html [ Skip ] crbug.com/591099 virtual/layout_ng_experimental/css3/flexbox/max-width-violation.html [ Skip ] crbug.com/591099 virtual/layout_ng_experimental/css3/flexbox/min-size-auto.html [ Skip ] @@ -1601,7 +1599,6 @@ crbug.com/591099 virtual/layout_ng_experimental/css3/flexbox/overflow-auto-dynamic-changes.html [ Skip ] crbug.com/591099 virtual/layout_ng_experimental/css3/flexbox/overflow-auto-resizes-correctly.html [ Skip ] crbug.com/591099 virtual/layout_ng_experimental/css3/flexbox/overflow-keep-scrollpos.html [ Failure ] -crbug.com/591099 virtual/layout_ng_experimental/css3/flexbox/percent-height-children-of-alignSelf-stretch-flex-item.html [ Skip ] crbug.com/591099 virtual/layout_ng_experimental/css3/flexbox/percent-margins.html [ Skip ] crbug.com/591099 virtual/layout_ng_experimental/css3/flexbox/percentage-height-replaced-element.html [ Skip ] crbug.com/591099 virtual/layout_ng_experimental/css3/flexbox/percentage-heights.html [ Skip ] @@ -1630,7 +1627,7 @@ crbug.com/591099 virtual/layout_ng_experimental/css3/flexbox/vertical-flexbox-percentage-ignored.html [ Skip ] crbug.com/591099 virtual/layout_ng_experimental/css3/flexbox/width-change-and-relayout-children.html [ Skip ] crbug.com/591099 virtual/layout_ng_experimental/css3/flexbox/wrapping-column-dynamic-changes.html [ Skip ] -crbug.com/591099 virtual/layout_ng_experimental/css3/flexbox/writing-modes.html [ Skip ] +crbug.com/591099 virtual/layout_ng_experimental/css3/flexbox/writing-modes.html [ Failure ] ### virtual/layout_ng_experimental/css3/flexbox/mozilla/ crbug.com/591099 virtual/layout_ng_experimental/css3/flexbox/mozilla/flexbox-items-as-stacking-contexts-2.html [ Failure ] @@ -1651,7 +1648,7 @@ crbug.com/591099 virtual/layout_ng_experimental/external/wpt/css/css-flexbox/align-content-006.htm [ Failure ] crbug.com/591099 virtual/layout_ng_experimental/external/wpt/css/css-flexbox/align-content-wrap-001.html [ Skip ] crbug.com/591099 virtual/layout_ng_experimental/external/wpt/css/css-flexbox/align-content-wrap-002.html [ Skip ] -crbug.com/591099 virtual/layout_ng_experimental/external/wpt/css/css-flexbox/align-content-wrap-003.html [ Skip ] +crbug.com/591099 virtual/layout_ng_experimental/external/wpt/css/css-flexbox/align-content-wrap-003.html [ Failure ] crbug.com/591099 virtual/layout_ng_experimental/external/wpt/css/css-flexbox/align-content-wrap-004.html [ Skip ] crbug.com/591099 virtual/layout_ng_experimental/external/wpt/css/css-flexbox/align-items-001.htm [ Failure ] crbug.com/591099 virtual/layout_ng_experimental/external/wpt/css/css-flexbox/align-items-003.htm [ Failure ] @@ -1666,18 +1663,18 @@ crbug.com/591099 virtual/layout_ng_experimental/external/wpt/css/css-flexbox/anonymous-flex-item-004.html [ Skip ] crbug.com/807497 virtual/layout_ng_experimental/external/wpt/css/css-flexbox/anonymous-flex-item-005.html [ Skip ] crbug.com/591099 virtual/layout_ng_experimental/external/wpt/css/css-flexbox/anonymous-flex-item-006.html [ Skip ] -crbug.com/591099 virtual/layout_ng_experimental/external/wpt/css/css-flexbox/auto-margins-001.html [ Skip ] +crbug.com/591099 virtual/layout_ng_experimental/external/wpt/css/css-flexbox/auto-margins-001.html [ Failure ] crbug.com/591099 virtual/layout_ng_experimental/external/wpt/css/css-flexbox/css-flexbox-column-reverse-wrap-reverse.html [ Skip ] crbug.com/591099 virtual/layout_ng_experimental/external/wpt/css/css-flexbox/css-flexbox-column-reverse-wrap.html [ Skip ] crbug.com/591099 virtual/layout_ng_experimental/external/wpt/css/css-flexbox/css-flexbox-column-reverse.html [ Skip ] crbug.com/591099 virtual/layout_ng_experimental/external/wpt/css/css-flexbox/css-flexbox-column-wrap-reverse.html [ Skip ] crbug.com/591099 virtual/layout_ng_experimental/external/wpt/css/css-flexbox/css-flexbox-column-wrap.html [ Skip ] crbug.com/591099 virtual/layout_ng_experimental/external/wpt/css/css-flexbox/css-flexbox-column.html [ Skip ] -crbug.com/591099 virtual/layout_ng_experimental/external/wpt/css/css-flexbox/css-flexbox-row-reverse-wrap-reverse.html [ Skip ] -crbug.com/591099 virtual/layout_ng_experimental/external/wpt/css/css-flexbox/css-flexbox-row-reverse-wrap.html [ Skip ] +crbug.com/591099 virtual/layout_ng_experimental/external/wpt/css/css-flexbox/css-flexbox-row-reverse-wrap-reverse.html [ Failure ] +crbug.com/591099 virtual/layout_ng_experimental/external/wpt/css/css-flexbox/css-flexbox-row-reverse-wrap.html [ Failure ] crbug.com/591099 virtual/layout_ng_experimental/external/wpt/css/css-flexbox/css-flexbox-row-reverse.html [ Skip ] -crbug.com/591099 virtual/layout_ng_experimental/external/wpt/css/css-flexbox/css-flexbox-row-wrap-reverse.html [ Skip ] -crbug.com/591099 virtual/layout_ng_experimental/external/wpt/css/css-flexbox/css-flexbox-row-wrap.html [ Skip ] +crbug.com/591099 virtual/layout_ng_experimental/external/wpt/css/css-flexbox/css-flexbox-row-wrap-reverse.html [ Failure ] +crbug.com/591099 virtual/layout_ng_experimental/external/wpt/css/css-flexbox/css-flexbox-row-wrap.html [ Failure ] crbug.com/591099 virtual/layout_ng_experimental/external/wpt/css/css-flexbox/css-flexbox-row.html [ Skip ] crbug.com/591099 virtual/layout_ng_experimental/external/wpt/css/css-flexbox/css-flexbox-test1.html [ Skip ] crbug.com/591099 virtual/layout_ng_experimental/external/wpt/css/css-flexbox/display_inline-flex_exist.html [ Skip ] @@ -1721,7 +1718,6 @@ crbug.com/249112 virtual/layout_ng_experimental/external/wpt/css/css-flexbox/flex-minimum-width-flex-items-007.xht [ Failure ] crbug.com/467127 virtual/layout_ng_experimental/external/wpt/css/css-flexbox/flex-minimum-width-flex-items-008.xht [ Failure ] crbug.com/591099 virtual/layout_ng_experimental/external/wpt/css/css-flexbox/flex-order.html [ Failure ] -crbug.com/591099 [ Mac ] virtual/layout_ng_experimental/external/wpt/css/css-flexbox/flex-vertical-align-effect.html [ Failure ] crbug.com/591099 virtual/layout_ng_experimental/external/wpt/css/css-flexbox/flex-wrap-002.html [ Skip ] crbug.com/591099 virtual/layout_ng_experimental/external/wpt/css/css-flexbox/flex-wrap-003.html [ Skip ] crbug.com/591099 virtual/layout_ng_experimental/external/wpt/css/css-flexbox/flexbox-flex-direction-column-reverse.htm [ Skip ] @@ -1793,7 +1789,6 @@ crbug.com/591099 virtual/layout_ng_experimental/external/wpt/css/css-flexbox/flexbox_wrap-long.html [ Failure ] crbug.com/591099 virtual/layout_ng_experimental/external/wpt/css/css-flexbox/flexbox_wrap-reverse.html [ Failure ] crbug.com/591099 virtual/layout_ng_experimental/external/wpt/css/css-flexbox/flexbox_wrap.html [ Failure ] -crbug.com/591099 virtual/layout_ng_experimental/external/wpt/css/css-flexbox/flexbox_writing_mode_vertical_lays_out_contents_from_top_to_bottom.html [ Skip ] crbug.com/591099 virtual/layout_ng_experimental/external/wpt/css/css-flexbox/flexible-box-float.html [ Skip ] crbug.com/591099 virtual/layout_ng_experimental/external/wpt/css/css-flexbox/layout-algorithm_algo-cross-line-002.html [ Skip ] crbug.com/467127 virtual/layout_ng_experimental/external/wpt/css/css-flexbox/negative-margins-001.html [ Skip ] @@ -1804,9 +1799,8 @@ crbug.com/467127 virtual/layout_ng_experimental/external/wpt/css/css-flexbox/percentage-heights-003.html [ Skip ] crbug.com/591099 virtual/layout_ng_experimental/external/wpt/css/css-flexbox/percentage-heights-004.html [ Skip ] crbug.com/591099 virtual/layout_ng_experimental/external/wpt/css/css-flexbox/percentage-heights-005.html [ Skip ] -crbug.com/591099 virtual/layout_ng_experimental/external/wpt/css/css-flexbox/percentage-heights-quirks-node.html [ Skip ] -crbug.com/591099 virtual/layout_ng_experimental/external/wpt/css/css-flexbox/percentage-size-subitems-001.html [ Skip ] -crbug.com/591099 virtual/layout_ng_experimental/external/wpt/css/css-flexbox/percentage-widths-001.html [ Skip ] +crbug.com/591099 virtual/layout_ng_experimental/external/wpt/css/css-flexbox/percentage-heights-quirks-node.html [ Failure ] +crbug.com/591099 virtual/layout_ng_experimental/external/wpt/css/css-flexbox/percentage-size-subitems-001.html [ Failure ] crbug.com/591099 virtual/layout_ng_experimental/external/wpt/css/css-flexbox/position-absolute-001.html [ Skip ] crbug.com/591099 virtual/layout_ng_experimental/external/wpt/css/css-flexbox/position-absolute-002.html [ Skip ] crbug.com/591099 virtual/layout_ng_experimental/external/wpt/css/css-flexbox/position-absolute-003.html [ Skip ]
diff --git a/third_party/blink/web_tests/http/tests/activedomobject/media-expected.txt b/third_party/blink/web_tests/http/tests/activedomobject/media-expected.txt index 36a0816..c4b80177 100644 --- a/third_party/blink/web_tests/http/tests/activedomobject/media-expected.txt +++ b/third_party/blink/web_tests/http/tests/activedomobject/media-expected.txt
@@ -1,8 +1,8 @@ Tests that reparenting media elements also reparents ActiveDOMObject. Before Reparenting -PASS: internals.pausableObjectCount(document) should be '2' and is. -PASS: internals.pausableObjectCount(iframe) should be '2' and is. -After Reparenting -PASS: internals.pausableObjectCount(document) should be '3' and is. +PASS: internals.pausableObjectCount(document) should be '1' and is. PASS: internals.pausableObjectCount(iframe) should be '1' and is. +After Reparenting +PASS: internals.pausableObjectCount(document) should be '2' and is. +PASS: internals.pausableObjectCount(iframe) should be '0' and is.
diff --git a/third_party/blink/web_tests/http/tests/activedomobject/media.html b/third_party/blink/web_tests/http/tests/activedomobject/media.html index f4e2aa8..8e7439a6 100644 --- a/third_party/blink/web_tests/http/tests/activedomobject/media.html +++ b/third_party/blink/web_tests/http/tests/activedomobject/media.html
@@ -10,14 +10,14 @@ window.iframe = document.querySelector('iframe').contentDocument; log('Before Reparenting'); - shouldBe('internals.pausableObjectCount(document)', 2); - shouldBe('internals.pausableObjectCount(iframe)', 2); + shouldBe('internals.pausableObjectCount(document)', 1); + shouldBe('internals.pausableObjectCount(iframe)', 1); document.body.appendChild(window.iframe.querySelector('video')); log('After Reparenting'); - shouldBe('internals.pausableObjectCount(document)', 3); - shouldBe('internals.pausableObjectCount(iframe)', 1); + shouldBe('internals.pausableObjectCount(document)', 2); + shouldBe('internals.pausableObjectCount(iframe)', 0); } </script> </body>
diff --git a/third_party/blink/web_tests/http/tests/origin_trials/webexposed/xr/webvr-gamepad-origin-trial-interfaces.html b/third_party/blink/web_tests/http/tests/origin_trials/webexposed/xr/webvr-gamepad-origin-trial-interfaces.html index 80f3d41..ce951f6 100644 --- a/third_party/blink/web_tests/http/tests/origin_trials/webexposed/xr/webvr-gamepad-origin-trial-interfaces.html +++ b/third_party/blink/web_tests/http/tests/origin_trials/webexposed/xr/webvr-gamepad-origin-trial-interfaces.html
@@ -14,7 +14,6 @@ properties_to_check = { 'Gamepad': ['pose', 'hand', 'displayId'], - 'GamepadButton': ['touched'], }; interfaces_to_check = [
diff --git a/third_party/blink/web_tests/http/tests/origin_trials/webexposed/xr/webxr-gamepad-origin-trial-interfaces.html b/third_party/blink/web_tests/http/tests/origin_trials/webexposed/xr/webxr-gamepad-origin-trial-interfaces.html index 4026582e..c8bf24c 100644 --- a/third_party/blink/web_tests/http/tests/origin_trials/webexposed/xr/webxr-gamepad-origin-trial-interfaces.html +++ b/third_party/blink/web_tests/http/tests/origin_trials/webexposed/xr/webxr-gamepad-origin-trial-interfaces.html
@@ -14,7 +14,6 @@ const token="AmQCIm7DYplQu/Vuep/62Rwyu+gYKwA1kz4CkNQWwtUnkr4o+kHqiSBZYD6APsbzyDDKm5xKi4BH4MxnheS8qwIAAABbeyJvcmlnaW4iOiAiaHR0cDovLzEyNy4wLjAuMTo4MDAwIiwgImZlYXR1cmUiOiAiV2ViWFJHYW1lcGFkU3VwcG9ydCIsICJleHBpcnkiOiAyMDAwMDAwMDAwfQ=="; const properties_to_check = { 'Gamepad': ['hand', 'displayId'], - 'GamepadButton': ['touched'], } // Skip this test if flags are not set properly.
diff --git a/third_party/blink/web_tests/virtual/stable/webexposed/global-interface-listing-expected.txt b/third_party/blink/web_tests/virtual/stable/webexposed/global-interface-listing-expected.txt index a0f8026c..5eba8fac 100644 --- a/third_party/blink/web_tests/virtual/stable/webexposed/global-interface-listing-expected.txt +++ b/third_party/blink/web_tests/virtual/stable/webexposed/global-interface-listing-expected.txt
@@ -1776,6 +1776,7 @@ interface GamepadButton attribute @@toStringTag getter pressed + getter touched getter value method constructor interface GamepadEvent : Event
diff --git a/third_party/closure_compiler/externs/autofill_private.js b/third_party/closure_compiler/externs/autofill_private.js index 1c089d2..d905d06 100644 --- a/third_party/closure_compiler/externs/autofill_private.js +++ b/third_party/closure_compiler/externs/autofill_private.js
@@ -192,6 +192,11 @@ chrome.autofillPrivate.migrateCreditCards = function() {}; /** + * Logs that the server cards edit link was clicked. + */ +chrome.autofillPrivate.logServerCardLinkClicked = function() {}; + +/** * Fired when the address list has changed, meaning that an entry has been * added, removed, or changed. |entries| The updated list of entries. * @type {!ChromeEvent}
diff --git a/third_party/sqlite/BUILD.gn b/third_party/sqlite/BUILD.gn index 7c6e8a1..6fd42dc 100644 --- a/third_party/sqlite/BUILD.gn +++ b/third_party/sqlite/BUILD.gn
@@ -5,6 +5,7 @@ import("//build/config/dcheck_always_on.gni") import("//build/config/sanitizers/sanitizers.gni") import("//testing/libfuzzer/fuzzer_test.gni") +import("//third_party/protobuf/proto_library.gni") # Compile-time options passed to SQLite. # @@ -415,6 +416,7 @@ } } +# Libfuzzer-based fuzzer test from SQLite source tree. fuzzer_test("sqlite3_ossfuzz_fuzzer") { include_dirs = [ "." ] sources = [ @@ -426,6 +428,127 @@ dict = "fuzz/sql.dict" } +source_set("sqlite3_lpm_fuzzer_core") { + sources = [ + "fuzz/sql_run_queries.cc", + "fuzz/sql_run_queries.h", + ] + deps = [ + ":sqlite", + ] + public_deps = [ + ":sqlite3_lpm_fuzzer_input", + ] + configs += [ + ":sqlite_warnings", + ":chromium_sqlite3_compile_options", + ] + all_dependent_configs = [ + ":lpm_fuzzer_omit_non_websql", + ":chromium_sqlite3_compile_options", + ] +} + +# LPM-based fuzzer test. +fuzzer_test("sqlite3_lpm_fuzzer") { + sources = [ + "fuzz/sql_fuzzer.cc", + "fuzz/sql_query_proto_to_string.cc", + "fuzz/sql_query_proto_to_string.h", + ] + deps = [ + ":sqlite3_lpm_fuzzer_core", + "//third_party/libprotobuf-mutator", + ] + additional_configs = [ ":sqlite_warnings" ] + libfuzzer_options = [ + "max_len=2111000", + "len_control=0", + ] +} + +# FTS3-focused LPM-based fuzzer test. +fuzzer_test("sqlite3_fts3_lpm_fuzzer") { + sources = [ + "fuzz/sql_fuzzer.cc", + "fuzz/sql_query_proto_to_string.cc", + "fuzz/sql_query_proto_to_string.h", + ] + deps = [ + ":sqlite3_lpm_fuzzer_core", + "//third_party/libprotobuf-mutator", + ] + additional_configs = [ + ":sqlite_warnings", + ":sqlite3_fts3_lpm_fuzzer_config", + ] + libfuzzer_options = [ + "max_len=2111000", + "len_control=0", + ] +} + +fuzzer_test("sqlite3_select_printf_lpm_fuzzer") { + sources = [ + "fuzz/sql_printf_fuzzer.cc", + "fuzz/sql_query_proto_to_string.cc", + "fuzz/sql_query_proto_to_string.h", + ] + deps = [ + ":sqlite3_lpm_fuzzer_core", + "//third_party/libprotobuf-mutator", + ] + libfuzzer_options = [ "max_len=111000" ] +} + +fuzzer_test("sqlite3_select_strftime_lpm_fuzzer") { + sources = [ + "fuzz/sql_query_proto_to_string.cc", + "fuzz/sql_query_proto_to_string.h", + "fuzz/sql_strftime_fuzzer.cc", + ] + deps = [ + ":sqlite3_lpm_fuzzer_core", + "//third_party/libprotobuf-mutator", + ] + libfuzzer_options = [ "max_len=111000" ] +} + +fuzzer_test("sqlite3_select_expr_lpm_fuzzer") { + sources = [ + "fuzz/sql_expr_fuzzer.cc", + "fuzz/sql_query_proto_to_string.cc", + "fuzz/sql_query_proto_to_string.h", + ] + deps = [ + ":sqlite3_lpm_fuzzer_core", + "//third_party/libprotobuf-mutator", + ] + libfuzzer_options = [ + "max_len=111000", + "len_control=0", + ] +} + +config("sqlite3_fts3_lpm_fuzzer_config") { + defines = [ "FUZZ_FTS3" ] +} + +config("lpm_fuzzer_omit_non_websql") { + defines = [ + "FUZZ_OMIT_SAVEPOINT", + "FUZZ_OMIT_PRAGMA", + ] +} + +proto_library("sqlite3_lpm_fuzzer_input") { + sources = [ + "fuzz/icu_codes.proto", + "fuzz/sql_queries.proto", + "fuzz/sql_query_grammar.proto", + ] +} + config("sqlite3_dbfuzz2_config") { cflags = [ "-Wno-sign-compare" ] configs = [ ":sqlite_warnings" ]
diff --git a/third_party/sqlite/fuzz/DEPS b/third_party/sqlite/fuzz/DEPS new file mode 100644 index 0000000..5199d44 --- /dev/null +++ b/third_party/sqlite/fuzz/DEPS
@@ -0,0 +1 @@ +include_rules = [ '+testing/libfuzzer/proto' ]
diff --git a/third_party/sqlite/fuzz/icu_codes.proto b/third_party/sqlite/fuzz/icu_codes.proto new file mode 100644 index 0000000..d3d470a --- /dev/null +++ b/third_party/sqlite/fuzz/icu_codes.proto
@@ -0,0 +1,189 @@ +syntax = "proto2"; + +package sql_query_grammar; + +enum IsoLangCode { + ISO_LANG_CODE_ab = 1; + ISO_LANG_CODE_af = 2; + ISO_LANG_CODE_ak = 3; + ISO_LANG_CODE_sq = 4; + ISO_LANG_CODE_am = 5; + ISO_LANG_CODE_ar = 6; + ISO_LANG_CODE_an = 7; + ISO_LANG_CODE_hy = 8; + ISO_LANG_CODE_as = 9; + ISO_LANG_CODE_av = 10; + ISO_LANG_CODE_ae = 11; + ISO_LANG_CODE_ay = 12; + ISO_LANG_CODE_az = 13; + ISO_LANG_CODE_ba = 14; + ISO_LANG_CODE_bm = 15; + ISO_LANG_CODE_eu = 16; + ISO_LANG_CODE_be = 17; + ISO_LANG_CODE_bn = 18; + ISO_LANG_CODE_bh = 19; + ISO_LANG_CODE_bi = 20; + ISO_LANG_CODE_bs = 21; + ISO_LANG_CODE_br = 22; + ISO_LANG_CODE_bg = 23; + ISO_LANG_CODE_my = 24; + ISO_LANG_CODE_ca = 25; + ISO_LANG_CODE_ch = 26; + ISO_LANG_CODE_ce = 27; + ISO_LANG_CODE_zh = 28; + ISO_LANG_CODE_cu = 29; + ISO_LANG_CODE_cv = 30; + ISO_LANG_CODE_kw = 31; + ISO_LANG_CODE_co = 32; + ISO_LANG_CODE_cr = 33; + ISO_LANG_CODE_cs = 34; + ISO_LANG_CODE_da = 35; + ISO_LANG_CODE_dv = 36; + ISO_LANG_CODE_nl = 37; + ISO_LANG_CODE_dz = 38; + ISO_LANG_CODE_en = 39; + ISO_LANG_CODE_eo = 40; + ISO_LANG_CODE_et = 41; + ISO_LANG_CODE_ee = 42; + ISO_LANG_CODE_fo = 43; + ISO_LANG_CODE_fj = 44; + ISO_LANG_CODE_fi = 45; + ISO_LANG_CODE_fr = 46; + ISO_LANG_CODE_fy = 47; + ISO_LANG_CODE_ff = 48; + ISO_LANG_CODE_ka = 49; + ISO_LANG_CODE_de = 50; + ISO_LANG_CODE_gd = 51; + ISO_LANG_CODE_ga = 52; + ISO_LANG_CODE_gl = 53; + ISO_LANG_CODE_gv = 54; + ISO_LANG_CODE_el = 55; + ISO_LANG_CODE_gn = 56; + ISO_LANG_CODE_gu = 57; + ISO_LANG_CODE_ht = 58; + ISO_LANG_CODE_ha = 59; + ISO_LANG_CODE_he = 60; + ISO_LANG_CODE_hz = 61; + ISO_LANG_CODE_hi = 62; + ISO_LANG_CODE_ho = 63; + ISO_LANG_CODE_hr = 64; + ISO_LANG_CODE_hu = 65; + ISO_LANG_CODE_ig = 66; + ISO_LANG_CODE_is = 67; + ISO_LANG_CODE_io = 68; + ISO_LANG_CODE_ii = 69; + ISO_LANG_CODE_iu = 70; + ISO_LANG_CODE_ie = 71; + ISO_LANG_CODE_ia = 72; + ISO_LANG_CODE_id = 73; + ISO_LANG_CODE_ik = 74; + ISO_LANG_CODE_it = 75; + ISO_LANG_CODE_jv = 76; + ISO_LANG_CODE_ja = 77; + ISO_LANG_CODE_kl = 78; + ISO_LANG_CODE_kn = 79; + ISO_LANG_CODE_ks = 80; + ISO_LANG_CODE_kr = 81; + ISO_LANG_CODE_kk = 82; + ISO_LANG_CODE_km = 83; + ISO_LANG_CODE_ki = 84; + ISO_LANG_CODE_rw = 85; + ISO_LANG_CODE_ky = 86; + ISO_LANG_CODE_kv = 87; + ISO_LANG_CODE_kg = 88; + ISO_LANG_CODE_ko = 89; + ISO_LANG_CODE_kj = 90; + ISO_LANG_CODE_ku = 91; + ISO_LANG_CODE_lo = 92; + ISO_LANG_CODE_la = 93; + ISO_LANG_CODE_lv = 94; + ISO_LANG_CODE_li = 95; + ISO_LANG_CODE_ln = 96; + ISO_LANG_CODE_lt = 97; + ISO_LANG_CODE_lb = 98; + ISO_LANG_CODE_lu = 99; + ISO_LANG_CODE_lg = 100; + ISO_LANG_CODE_mk = 101; + ISO_LANG_CODE_mh = 102; + ISO_LANG_CODE_ml = 103; + ISO_LANG_CODE_mi = 104; + ISO_LANG_CODE_mr = 105; + ISO_LANG_CODE_ms = 106; + ISO_LANG_CODE_mg = 107; + ISO_LANG_CODE_mt = 108; + ISO_LANG_CODE_mn = 109; + ISO_LANG_CODE_na = 110; + ISO_LANG_CODE_nv = 111; + ISO_LANG_CODE_nr = 112; + ISO_LANG_CODE_nd = 113; + ISO_LANG_CODE_ng = 114; + ISO_LANG_CODE_ne = 115; + ISO_LANG_CODE_nn = 116; + ISO_LANG_CODE_nb = 117; + ISO_LANG_CODE_no = 118; + ISO_LANG_CODE_ny = 119; + ISO_LANG_CODE_oc = 120; + ISO_LANG_CODE_oj = 121; + ISO_LANG_CODE_or = 122; + ISO_LANG_CODE_om = 123; + ISO_LANG_CODE_os = 124; + ISO_LANG_CODE_pa = 125; + ISO_LANG_CODE_fa = 126; + ISO_LANG_CODE_pi = 127; + ISO_LANG_CODE_pl = 128; + ISO_LANG_CODE_pt = 129; + ISO_LANG_CODE_ps = 130; + ISO_LANG_CODE_qu = 131; + ISO_LANG_CODE_rm = 132; + ISO_LANG_CODE_ro = 133; + ISO_LANG_CODE_rn = 134; + ISO_LANG_CODE_ru = 135; + ISO_LANG_CODE_sg = 136; + ISO_LANG_CODE_sa = 137; + ISO_LANG_CODE_si = 138; + ISO_LANG_CODE_sk = 139; + ISO_LANG_CODE_sl = 140; + ISO_LANG_CODE_se = 141; + ISO_LANG_CODE_sm = 142; + ISO_LANG_CODE_sn = 143; + ISO_LANG_CODE_sd = 144; + ISO_LANG_CODE_so = 145; + ISO_LANG_CODE_st = 146; + ISO_LANG_CODE_es = 147; + ISO_LANG_CODE_sc = 148; + ISO_LANG_CODE_sr = 149; + ISO_LANG_CODE_ss = 150; + ISO_LANG_CODE_su = 151; + ISO_LANG_CODE_sw = 152; + ISO_LANG_CODE_sv = 153; + ISO_LANG_CODE_ty = 154; + ISO_LANG_CODE_ta = 155; + ISO_LANG_CODE_tt = 156; + ISO_LANG_CODE_te = 157; + ISO_LANG_CODE_tg = 158; + ISO_LANG_CODE_tl = 159; + ISO_LANG_CODE_th = 160; + ISO_LANG_CODE_bo = 161; + ISO_LANG_CODE_ti = 162; + ISO_LANG_CODE_to = 163; + ISO_LANG_CODE_tn = 164; + ISO_LANG_CODE_ts = 165; + ISO_LANG_CODE_tk = 166; + ISO_LANG_CODE_tr = 167; + ISO_LANG_CODE_tw = 168; + ISO_LANG_CODE_ug = 169; + ISO_LANG_CODE_uk = 170; + ISO_LANG_CODE_ur = 171; + ISO_LANG_CODE_uz = 172; + ISO_LANG_CODE_ve = 173; + ISO_LANG_CODE_vi = 174; + ISO_LANG_CODE_vo = 175; + ISO_LANG_CODE_cy = 176; + ISO_LANG_CODE_wa = 177; + ISO_LANG_CODE_wo = 178; + ISO_LANG_CODE_xh = 179; + ISO_LANG_CODE_yi = 180; + ISO_LANG_CODE_yo = 181; + ISO_LANG_CODE_za = 182; + ISO_LANG_CODE_zu = 183; +}
diff --git a/third_party/sqlite/fuzz/sql_expr_fuzzer.cc b/third_party/sqlite/fuzz/sql_expr_fuzzer.cc new file mode 100644 index 0000000..75431f3f --- /dev/null +++ b/third_party/sqlite/fuzz/sql_expr_fuzzer.cc
@@ -0,0 +1,30 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include <iostream> +#include <string> +#include <vector> + +#include "testing/libfuzzer/proto/lpm_interface.h" +#include "third_party/sqlite/fuzz/sql_query_grammar.pb.h" +#include "third_party/sqlite/fuzz/sql_query_proto_to_string.h" +#include "third_party/sqlite/fuzz/sql_run_queries.h" + +using namespace sql_query_grammar; + +DEFINE_BINARY_PROTO_FUZZER(const Expr& expr) { + std::string expr_str = sql_fuzzer::ExprToString(expr); + // Convert printf command into runnable SQL query. + expr_str = "SELECT " + expr_str + ";"; + + if (getenv("LPM_DUMP_NATIVE_INPUT")) { + std::cout << "_________________________" << std::endl; + std::cout << expr_str << std::endl; + std::cout << "------------------------" << std::endl; + } + + std::vector<std::string> queries; + queries.push_back(expr_str); + sql_fuzzer::RunSqlQueries(queries); +}
diff --git a/third_party/sqlite/fuzz/sql_fuzzer.cc b/third_party/sqlite/fuzz/sql_fuzzer.cc new file mode 100644 index 0000000..e7fdafc --- /dev/null +++ b/third_party/sqlite/fuzz/sql_fuzzer.cc
@@ -0,0 +1,42 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include <iostream> +#include <string> +#include <vector> + +#include "testing/libfuzzer/proto/lpm_interface.h" +#include "third_party/sqlite/fuzz/sql_query_grammar.pb.h" +#include "third_party/sqlite/fuzz/sql_query_proto_to_string.h" +#include "third_party/sqlite/fuzz/sql_run_queries.h" + +using namespace sql_query_grammar; + +// TODO(mpdenton) Fuzzing tasks +// 5. Definitely fix a lot of the syntax errors that SQlite spits out +// 12. CORPUS Indexes on expressions (https://www.sqlite.org/expridx.html) and +// other places using functions on columns??? +// 17. Generate a nice big random, well-formed corpus. + +// FIXME in the future +// 1. Rest of the pragmas +// 2. Make sure defensive config is off +// 3. Fuzz the recover extension from the third patch +// 5. Temp-file database, for better fuzzing of VACUUM and journalling. + +DEFINE_BINARY_PROTO_FUZZER(const SQLQueries& sql_queries) { + std::vector<std::string> queries = sql_fuzzer::SQLQueriesToVec(sql_queries); + + if (getenv("LPM_DUMP_NATIVE_INPUT") && queries.size() != 0) { + std::cout << "_________________________" << std::endl; + for (std::string query : queries) { + if (query == ";") + continue; + std::cout << query << std::endl; + } + std::cout << "------------------------" << std::endl; + } + + sql_fuzzer::RunSqlQueries(queries); +}
diff --git a/third_party/sqlite/fuzz/sql_multithreaded_fuzzer.cc b/third_party/sqlite/fuzz/sql_multithreaded_fuzzer.cc new file mode 100644 index 0000000..0f7ff82 --- /dev/null +++ b/third_party/sqlite/fuzz/sql_multithreaded_fuzzer.cc
@@ -0,0 +1,79 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Unused because SQLite is so serialized and concurrency-unfriendly that this +// really wouldn't test anything. + +#include <condition_variable> +#include <iostream> +#include <mutex> +#include <string> +#include <thread> +#include <vector> + +#include "testing/libfuzzer/proto/lpm_interface.h" +#include "third_party/sqlite/fuzz/sql_query_grammar.pb.h" +#include "third_party/sqlite/fuzz/sql_query_proto_to_string.h" +#include "third_party/sqlite/fuzz/sql_run_queries.h" +#include "third_party/sqlite/sqlite3.h" + +using namespace sql_query_grammar; + +namespace { +constexpr int kNumThreads = 4; // Must change with MultipleSQLQueries protobuf. +} + +DEFINE_BINARY_PROTO_FUZZER(const MultipleSQLQueries& multiple_sql_queries) { + assert(multiple_sql_queries.GetDescriptor()->field_count() == kNumThreads); + + sqlite3* db = sql_fuzzer::InitConnectionForFuzzing(); + if (!db) + return; + + std::vector<std::string> query_strs[kNumThreads]; + query_strs[0] = sql_fuzzer::SQLQueriesToVec(multiple_sql_queries.queries1()); + query_strs[1] = sql_fuzzer::SQLQueriesToVec(multiple_sql_queries.queries2()); + query_strs[2] = sql_fuzzer::SQLQueriesToVec(multiple_sql_queries.queries3()); + query_strs[3] = sql_fuzzer::SQLQueriesToVec(multiple_sql_queries.queries4()); + + if (getenv("LPM_DUMP_NATIVE_INPUT")) { + std::cout << "_________________________" << std::endl; + for (int i = 0; i < kNumThreads; i++) { + std::cout << "Thread " << i << ":" << std::endl; + for (std::string query : query_strs[i]) { + if (query == ";") + continue; + std::cout << query << std::endl; + } + } + std::cout << "------------------------" << std::endl; + } + + int num_threads_started = 0; + std::mutex m; + std::condition_variable cv; + + std::vector<std::thread> threads; + + auto to_run = [&](std::vector<std::string> queries) { + // Wait for all the threads to start. + std::unique_lock<std::mutex> lk(m); + num_threads_started++; + cv.notify_all(); + cv.wait(lk, [&] { return num_threads_started == kNumThreads; }); + m.unlock(); + + sql_fuzzer::RunSqlQueriesOnConnection(db, queries); + }; + + for (int i = 0; i < kNumThreads; i++) { + threads.emplace_back(to_run, query_strs[i]); + } + + for (int i = 0; i < kNumThreads; i++) { + threads[i].join(); + } + + sql_fuzzer::CloseConnection(db); +}
diff --git a/third_party/sqlite/fuzz/sql_printf_fuzzer.cc b/third_party/sqlite/fuzz/sql_printf_fuzzer.cc new file mode 100644 index 0000000..bdfdb6d --- /dev/null +++ b/third_party/sqlite/fuzz/sql_printf_fuzzer.cc
@@ -0,0 +1,30 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include <iostream> +#include <string> +#include <vector> + +#include "testing/libfuzzer/proto/lpm_interface.h" +#include "third_party/sqlite/fuzz/sql_query_grammar.pb.h" +#include "third_party/sqlite/fuzz/sql_query_proto_to_string.h" +#include "third_party/sqlite/fuzz/sql_run_queries.h" + +using namespace sql_query_grammar; + +DEFINE_BINARY_PROTO_FUZZER(const Printf& sql_printf) { + std::string printf_str = sql_fuzzer::PrintfToString(sql_printf); + // Convert printf command into runnable SQL query. + printf_str = "SELECT " + printf_str + ";"; + + if (getenv("LPM_DUMP_NATIVE_INPUT")) { + std::cout << "_________________________" << std::endl; + std::cout << printf_str << std::endl; + std::cout << "------------------------" << std::endl; + } + + std::vector<std::string> queries; + queries.push_back(printf_str); + sql_fuzzer::RunSqlQueries(queries); +}
diff --git a/third_party/sqlite/fuzz/sql_queries.proto b/third_party/sqlite/fuzz/sql_queries.proto new file mode 100644 index 0000000..d12ebe7 --- /dev/null +++ b/third_party/sqlite/fuzz/sql_queries.proto
@@ -0,0 +1,23 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +syntax = "proto2"; + +import "sql_query_grammar.proto"; + +package sql_query_grammar; + +message MultipleSQLQueries { + required SQLQueries queries1 = 1; + required SQLQueries queries2 = 2; + required SQLQueries queries3 = 3; + required SQLQueries queries4 = 4; +} + +message SQLQueries { + // Always have a CreateTable first because otherwise the queries are + // pointless. + required CreateTable create_table = 1; + repeated SQLQuery extra_queries = 2; +}
diff --git a/third_party/sqlite/fuzz/sql_query_grammar.proto b/third_party/sqlite/fuzz/sql_query_grammar.proto new file mode 100644 index 0000000..87eb96e6 --- /dev/null +++ b/third_party/sqlite/fuzz/sql_query_grammar.proto
@@ -0,0 +1,1653 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +syntax = "proto2"; + +import "icu_codes.proto"; + +package sql_query_grammar; + +/* Generates SQL queries in protobuf format, using enums for the tables and + integers for column names. The column name integers will be wrapped. + Relies heavily on the sqlite grammar from here: + https://www.sqlite.org/lang.html + + Yes, it is all in one big blobby proto file, as everything is extremely + mutually recursive and there is no such thing as circular imports or forward + declarations in protobuf. +*/ + +message SQLQuery { + // No comments generated, nor EXPLAIN queries + oneof query_oneof { + Select select = 1; + CreateTable create_table = 2; + Insert insert = 3; + Delete delete = 4; + CreateFTS3Table fts3_table = 5; + FTS3SpecificQuery fts_query = 6; + BeginTransaction begin_txn = 7; + CommitTransaction commit_txn = 8; + RollbackStatement rollback_stmt = 9; + CreateSavePoint create_save_point = 10; + ReleaseSavePoint release_save_point = 11; + Analyze analyze = 12; + Vacuum vacuum = 13; + Pragma pragma = 14; + Update update = 15; + CreateIndex create_index = 16; + CreateView create_view = 17; + CreateTrigger create_trigger = 18; + ReIndex reindex = 19; + Drop drop = 20; + AlterTable alter_table = 21; + AttachDatabase attach_db = 22; + DetachDatabase detach_db = 23; + FTS3HiddenTableInsert fts3_insert = 24; + FTS3HiddenTableUpdate fts3_update = 25; + FTS3HiddenTableDelete fts3_delete = 26; + } +} + +// ~~~~FTS3~~~ + +message FTS3SpecificQuery { + oneof query_oneof { + FTS3SpecialCommand command = 1; + // The following exists to increase the probability of hitting MATCH + // queries. + FTS3SelectMatch select = 2; + } +} + +message FTS3SelectMatch { + // SELECT * FROM |table| WHERE |col| MATCH |match_pattern| + required FTS3Table table = 1; + required Column col = 2; + required FTS3MatchFormat match_pattern = 3; +} + +message FTS3SpecialCommand { + // INSERT INTO xyz(xyz) VALUES('optimize'); + // is a special command that optimizes FTS table xyz. + required FTS3Table table = 1; + enum Command { + OPTIMIZE = 0; + REBUILD = 1; + INTEGRITY_CHECK = 2; + MERGE = 3; + AUTOMERGE = 4; + } + required Command command = 2; + required uint32 val1 = 3; + required uint32 val2 = 4; +} + +message ICULocale { + required IsoLangCode iso_lang_code = 1; + // least significant 2 bytes will each be clamped to within 'A' and + // 'Z' and then concatenated together to form a country code. + required uint32 country_code = 2; + // TODO(mpdenton) generate anything else here? Will sqlite care? +} + +enum TokenizerType { + TT_SIMPLE = 0; + TT_PORTER = 1; + TT_ICU = 2; + TT_UNICODE61 = 3; // FIXME in the future: remove_diacritics, separators, + // token_chars.... (not supported in Chrome) +} + +// FIXME in the future: maybe also fuzz the tokenizer type/icu locales with +// random strings??? +message CreateFTS3Table { + required bool if_not_exists = 1; + optional Schema schema = 6; + required FTS3Table table = 2; + optional ColumnList col_list = 3; + optional TokenizerType tokenizer_type = 4; + required ICULocale locale = 5; // used if tokenizer_type == TT_ICU. +} + +message FTS3Table { + required uint32 table = 1; +} + +// TODO(mpdenton) query by row id? + +message FTS3MatchFormat { + repeated FTS3MatchCompoundFormat ft = 1; +} + +message FTS3MatchCompoundFormat { + required FTS3MatchFormatCore core = 1; + repeated FTS3CompoundAndCore compound_and_cores = 2; +} + +message FTS3CompoundAndCore { + enum CompoundOp { + OR = 0; + // Chrome does not enable the enhanced query syntax. FIXME in the future. + // AND = 1; + // NOT = 2; + } + required CompoundOp op = 1; + required FTS3MatchFormatCore core = 2; +} + +message FTS3MatchFormatCore { + oneof ft_oneof { + FTS3PhraseQuery pq = 1; + FTS3NearQuery nq = 2; + } + required FTS3MatchToken mt_fallback = 3; +} + +message FTS3NearQuery { + // May generate into another NEAR query, this is fine. + required FTS3MatchFormatCore format_core1 = 1; + optional uint32 num_tokens_near = 2; + required FTS3MatchFormatCore format_core2 = 3; +} + +message FTS3PhraseQuery { + required FTS3MatchToken mt = 1; + repeated FTS3MatchToken extra_mts = 2; +} + +message FTS3MatchToken { + optional Column col = 1; // search in this column specifically + required bool negate = 4; + required string token = 2; // token (or prefix) to search for + required bool prefix = 3; // append star to end +} + +// FIXME in the future: https://www.sqlite.org/fts3.html Section 8.2: Query +// tokenizers themselves. Unsupported by Chrome. + +message FTS3OffsetsFn { + required FTS3Table table = 1; +} + +message FTS3SnippetsFn { + required FTS3Table table = 1; + enum NumArgs { + A0 = 0; + A1 = 1; + A2 = 2; + A3 = 3; + A4 = 4; + A5 = 5; + } + required NumArgs num_optional_args = 2; + required string start_match = 3; + required string end_match = 4; + required string ellipses = 5; + optional uint32 col_number = 6; // capped by KMaxColumnNumber + required uint32 num_tokens = 7; // in [-64, 64]. +} + +message FTS3MatchInfoFn { + required FTS3Table table = 1; + + // The following will be wrapped to any of the characters p,c,n,a,,l,s,x,y,b. + repeated uint32 chars = 2; +} + +// FTS3 Auxiliary function format +message FTS3AuxiliaryFn { + required FTS3OffsetsFn offsets_fallback = 1; + oneof fts_aux_fn_oneof { + FTS3SnippetsFn snippets = 2; + FTS3MatchInfoFn matchinfo = 3; + } +} + +// Types of hidden tables in FTS3 +message FTS3HiddenTable { + enum HiddenTableVal { + // CONTENT = 0; // Taken care of in |Table| + SEGDIR = 1; + SEGMENTS = 2; + // stat and docsize are FTS4 + } + required HiddenTableVal htv = 1; + required FTS3Table table = 2; +} + +// The different columns that go into the FTS3 hidden tables above +enum FTS3HiddenTableColumn { + FTS3_HT_BLOCKID = 0; + FTS3_HT_BLOCK = 1; + FTS3_HT_LEVEL = 2; + FTS3_HT_IDX = 3; + FTS3_HT_START_BLOCK = 4; + FTS3_HT_LEAVES_END_BLOCK = 5; + FTS3_HT_END_BLOCK = 6; + FTS3_HT_ROOT = 7; +} + +// Some extra stuff to modify the FTS3 Hidden tables, only used for FTS3 +// Fuzzing. + +// Used to insert single values in. +message FTS3HiddenTableInsert { + required FTS3HiddenTable fht = 1; + repeated FTS3HiddenTableColumnValue col_vals = 2; +} + +message FTS3HiddenTableUpdate { + required FTS3HiddenTable fht = 1; + repeated FTS3HiddenTableColumnValue col_vals = 2; + + // mini WHERE clause with some BinOp + optional FTS3HiddenTableColumn col_where = 3; + required BinaryOperator bin_op = 4; + required Expr comp_expr = 5; +} + +message FTS3HiddenTableDelete { + required FTS3HiddenTable fht = 1; + optional FTS3HiddenTableColumn col_where = 2; + required BinaryOperator bin_op = 3; + required Expr comp_expr = 4; +} + +message FTS3HiddenTableColumnValue { + required FTS3HiddenTableColumn col = 1; + required Expr expr = 2; +} + +// ~~~~TRANSACTIONs~~~~ +// TODO(mpdenton) these could be meta-statements that enclose a bunch of other +// statements. Is that worthwhile or should I just let the fuzzer generate them +// haphazardly? +message BeginTransaction { + enum TransactionType { + DEFERRED = 0; + IMMEDIATE = 1; + EXCLUSIVE = 2; + } + optional TransactionType type = 1; +} + +message CommitTransaction { + enum CommitText { + COMMIT = 0; + END = 1; + COMMIT_TRANSACTION = 2; + END_TRANSACTION = 3; + } + required CommitText text = 1; +} + +message SavePoint { + required uint32 savepoint_num = 1; +} + +message RollbackStatement { + optional SavePoint save_point = 1; +} + +message CreateSavePoint { + required SavePoint save_point = 1; +} + +message ReleaseSavePoint { + required SavePoint save_point = 1; +} + +// ~~~~ANALYZE~~~~ +message Analyze { + optional Schema schema_name = 1; + optional Table table_name = 2; + optional Index index_name = 3; +} + +// ~~~~VACUUM~~~~ +message Vacuum { + optional Schema schema = 1; +} + +// ~~~~PRAGMA~~~~ +message Pragma { + // FIXME in the future: full list here: https://www.sqlite.org/pragma.html + // These are the ones I've seen in Chrome + enum PragmaCommand { + // QUICK_CHECK = 0; + // INTEGRITY_CHECK = 1; + AUTO_VACUUM = 2; + WRITEABLE_SCHEMA = 3; + LOCKING_MODE = 4; + TEMP_STORE = 5; + PAGE_SIZE_ = 6; + TABLE_INFO = 7; + JOURNAL_MODE = 8; + MMAP_SIZE = 9; + } + required PragmaCommand command = 1; + optional Schema schema = 2; + required int32 arg1 = 3; +} + +// ~~~~CREATE_TABLE~~~~ +enum TempModifier { + TM_TEMP = 3; + TM_TEMPORARY = 4; +} + +message CreateTable { + optional TempModifier temp_modifier = 1; + required bool if_not_exists = 2; + required ExprSchemaTable schema_table = 3; + oneof create_table_oneof { + CreateTableOpt1 op1 = 4; + Select as_select_stmt = 5; // AS select-stmt + } + required CreateTableOpt1 op = 6; // used only if the above oneof is empty +} + +message CreateTableOpt1 { + required ColumnDef col_def = 1; + repeated ColumnDef extra_col_defs = 2; + repeated TableConstraint table_constraints = 3; + required bool without_rowid = 4; +} + +message ColumnDef { + required Column col = 1; + optional TypeName type_name = 2; + repeated ColumnConstraint col_constraints = 3; +} + +message TypeName { + // Things like VARCHAR(100) are simply not enforced by SQLite (this example + // would end up with a column affinity of TEXT). So I don't make much effort + // to generate them. + required CastTypeName ctn = 1; + optional uint32 sn = 2; +} + +message ColumnConstraint { + optional ColumnConstraintName constraint_name = 1; + oneof col_constraint_oneof { + ColConstraintOpt1 opt1 = 2; + ConflictClause not_null_conf_clause = 3; + ConflictClause unique_conf_clause = 4; + Expr check_expr = 5; // CORPUS specialize?? + ColConstraintOpt2 opt2 = 6; + CollateType collate = 7; + ForeignKeyClause fkey_clause = 8; + } + required ColConstraintOpt2 opt2_fallback = 9; +} + +message ColConstraintOpt1 { + required AscDesc asc_desc = 1; + required ConflictClause conflict = 2; + required bool autoincrement = 3; +} + +message ColConstraintOpt2 { + required LiteralValue lit_val = 1; + optional Expr expr = 2; // CORPUS specialize? +} + +message ConflictClause { + enum OnConflict { + ROLLBACK = 0; + ABORT = 1; + FAIL = 2; + IGNORE = 3; + REPLACE = 4; + } + optional OnConflict on_conflict = 1; +} + +message TableConstraint { + optional TableConstraintName name = 1; + oneof table_constraint_oneof { + TableConstraintOpt1 opt1 = 2; + Expr check_expr = 3; // CORPUS specialize? + TableConstraintOpt2 opt2 = 4; + } +} + +message TableConstraintOpt1 { + enum ConstraintType { + PRIMARY_KEY = 0; + UNIQUE = 1; + } + required ConstraintType constraint_type = 1; + required IndexedColumnList indexed_col_list = 2; + required ConflictClause conf_clause = 3; +} + +message TableConstraintOpt2 { + required ColumnList cols = 1; + required ForeignKeyClause fkey_clause = 2; +} + +message IndexedColumn { + optional Expr expr = 1; // CORPUS specialize? + required Column col = 2; // only used if expr non-existent + optional CollateType collate_type = 3; + required AscDesc asc_desc = 4; +} + +message IndexedColumnList { + required IndexedColumn indexed_col = 1; + repeated IndexedColumn extra_indexed_cols = 2; +} + +message ForeignKeyClause { + required Table foreign_table = 1; + optional ColumnList col_list = 2; + repeated ForeignKeyClauseCore fkey_cores = 3; + optional DeferStrategy defer_strat = 4; +} + +message ForeignKeyClauseCore { + optional ForeignKeyClauseNotMatch fkey_not_match = 1; + // Sqlite doesn't obey MATCH expressions, MATCH SIMPLE is always assumed +} + +message ForeignKeyClauseNotMatch { + enum DeleteOrUpdate { + DELETE = 0; + UPDATE = 1; + } + required DeleteOrUpdate del_or_update = 1; + + enum Action { + SET_NULL = 0; + SET_DEFAULT = 1; + CASCADE = 2; + RESTRICT = 3; + NO_ACTION = 4; + } + required Action action = 2; +} + +message DeferStrategy { + required bool not = 1; + enum DeferStratEnum { + INITIALLY_DEFERRED = 0; + INITIALLY_IMMEDIATE = 1; + NONE = 2; + } + required DeferStratEnum strat = 2; +} + +// ~~~~DELETE~~~~ +// FIXME in the future: SQL_ENABLE_UPDATE_DELETE_LIMIT +message Delete { + optional WithStatement with = 1; + required QualifiedTableName qtn = 2; + optional WhereStatement where = 3; +} + +message QualifiedTableName { + required SchemaTableAsAlias staa = 1; + required bool indexed = 2; + required bool not_indexed = 3; + required Index indexed_by = 4; +} + +// ~~~~INSERT~~~~ + +message UpsertClausePart1 { + required IndexedColumnList icol_list = 1; + optional WhereStatement where_stmt = 2; +} + +message ColEqualsExpr { + oneof uclause_p2_oneof { + Column col = 1; + ColumnList col_list = 2; + } + required Expr expr = 3; +} + +message UpsertClausePart2 { + required ColEqualsExpr cee = 1; + repeated ColEqualsExpr extra_cees = 2; + optional WhereStatement where_stmt = 3; +} + +message UpsertClause { + optional UpsertClausePart1 uclause_p1 = 1; + optional UpsertClausePart2 uclause_p2 = 2; +} + +message SchemaTableAsAlias { + required ExprSchemaTable schema_table = 1; + optional Table as_table_alias = 2; +} + +message Insert { + optional WithStatement with = 1; + enum InsertType { + INSERT = 0; + REPLACE = 1; + INSERT_OR_REPLACE = 2; + INSERT_OR_ROLLBACK = 3; + INSERT_OR_ABORT = 4; + INSERT_OR_FAIL = 5; + INSERT_IGNORE = 6; + } + required InsertType insert_type = 2; + required SchemaTableAsAlias staa = 3; + optional ColumnList col_list = 5; + oneof insert_oneof { + ValuesStatement values = 6; + Select select = 7; + } // if empty, DEFAULT VALUES + optional UpsertClause upsert_clause = 8; +} + +// ~~~~UPDATE~~~~ +message Update { + optional WithStatement with = 1; + enum UpdateType { + OR_ROLLBACK = 0; + OR_ABORT = 1; + OR_REPLACE = 2; + OR_FAIL = 3; + OR_IGNORE = 4; + } + optional UpdateType update_type = 2; + required QualifiedTableName qtn = 3; + required UpsertClausePart2 ucp2 = 4; +} + +// ~~~~CREATE INDEX~~~~ +message CreateIndex { + required bool unique = 1; + required bool if_not_exists = 2; + optional Schema schema = 3; + required Index index = 4; + required Table table = 5; + required IndexedColumnList icol_list = 6; + optional WhereStatement where = 7; +} + +// ~~~~CREATE VIEW~~~~ +message View { + required uint32 view = 1; +} +message CreateView { + optional TempModifier temp_modifier = 1; + required bool if_not_exists = 2; + optional Schema schema = 3; + required View view = 4; + optional ColumnList col_list = 5; + required Select select = 6; +} + +// ~~~~CREATE TRIGGER~~~~ +message Trigger { + required uint32 trigger = 1; +} + +message CreateTrigger { + optional TempModifier temp_modifier = 1; + required bool if_not_exists = 2; + optional Schema schema = 3; + required Trigger trigger = 4; + enum TriggerType { + BEFORE = 0; + AFTER = 1; + INSTEAD_OF = 2; + } + optional TriggerType trigger_type = 5; + enum TriggerInstr { + DELETE = 0; + UPDATE = 1; + INSERT = 2; + } + optional TriggerInstr trigger_instr = 6; + required ColumnList col_list = 7; // CORPUS create corpus item with an Update + // using the same ColumnList as this + required Table table = 8; + required bool for_each_row = 9; + optional ExprComparisonHighProbability when = 10; // for the WHEN statement + // There are significant restrictions on update, insert, select, and delete + // expressions used in triggers. However, we might as well generate normal + // queries and see if these restrictions are adequately enforced. + + // Also, from https://www.sqlite.org/lang_createtrigger.html: "If a BEFORE + // UPDATE or BEFORE DELETE trigger modifies or deletes a row that was to have + // been updated or deleted, then the result of the subsequent update or delete + // operation is undefined. Furthermore, if a BEFORE trigger modifies or + // deletes a row, then it is undefined whether or not AFTER triggers that + // would have otherwise run on those rows will in fact run." + + // It is unclear what is meant by "undefined". Are we talking memory + // corruption? I suppose the fuzzer will find it and we'll see. + required TypicalQuery tq = 11; + repeated TypicalQuery extra_tqs = 12; +} + +message TypicalQuery { + oneof tq_oneof { + Update update = 1; + Insert insert = 2; + Select select = 3; + } + required Delete delete_fallback = 4; +} + +// ~~~~REINDEX~~~~ +message ReIndex { + required bool empty = 5; + optional CollateType collate_type = 4; // used if schema does not exist + optional Schema schema = 1; + optional Table table = 2; + required Index index = 3; // used if table does not exist. +} + +// ~~~~DROP *~~~~ +message Drop { + required bool if_exists = 5; + optional Schema schema = 6; + oneof drop_oneof { + Index index = 1; + Table table = 2; + Trigger trigger = 3; + } + required View view_fallback = 4; +} + +// ~~~~ALTER TABLE~~~~ +message AlterTable { + required ExprSchemaTable schema_table = 1; + required bool column = 2; + optional Column col = 4; + required Column col_to = 5; + optional ColumnDef col_def = 6; + required Table table_fallback = 3; +} + +// ~~~~ATTACH DATABASE~~~~ + +// SEE: https://www.sqlite.org/inmemorydb.html +// Lots of different options. +// TODO(mpdenton) may want to experiment with on-filesystem main dbs as well... +message AttachDatabase { + required bool in_memory = 1; + required bool file_uri = 2; + optional Schema db_name = 3; + required bool shared_cache = 4; + required Schema schema = 5; +} + +// ~~~~DETACH DATABASE~~~~ +message DetachDatabase { + required Schema schema = 1; +} + +// ~~~~SELECT~~~~ +/* + Select is obviously the most complicated syntax in the language, and the + fuzzer will likely generate plenty of invalid SELECT statements. As long as + it does not generate too many, we should still be perfectly fine. + + From sqlite docs: + Note that there are paths through the syntax diagrams that are not allowed in + practice. Some examples: + + A VALUES clause can be the first element in a compound SELECT that uses a WITH + clause, but a simple SELECT that consists of just a VALUES clause cannot be + preceded by a WITH clause. The WITH clause must occur on the first SELECT of a + compound SELECT. It cannot follow a compound-operator. + + + See https://www.sqlite.org/lang_select.html. +*/ +message Select { + optional WithStatement with = 1; + + // SQL grammar specifies SelectSubStatement here but that just leads + // to a bunch of unparseable VALUES ... ; statements. So require + // SelectCore here. + required SelectStatementCore select_core = 2; + repeated ExtraSelectSubStatement extra_select_substatements = 3; + optional OrderByStatement orderby = 4; + optional LimitStatement limit = 5; +} + +message OrderByStatement { + required ExprOrderingTerm ord_term = 1; + repeated ExprOrderingTerm extra_ord_terms = 2; +} + +message LimitStatement { + // CORPUS specialize these exprs??? + required Expr limit_expr = 1; + required bool offset = 2; // this is only used if second_expr exists + optional Expr second_expr = 3; +} + +message ExtraSelectSubStatement { + required CompoundOperator compound_op = 1; + required SelectSubStatement select_substatement = 2; +} + +enum CompoundOperator { + CO_UNION = 0; + CO_UNION_ALL = 1; + CO_INTERSECT = 2; + CO_EXCEPT = 3; +} + +message SelectSubStatement { + oneof select_subexpr_oneof { + SelectStatementCore select_core = 1; + ValuesStatement values = 2; + } + required ValuesStatement values_fallback = 3; +} + +message ValuesStatement { + required ExprList expr_list = 1; + repeated ExprList extra_expr_lists = 2; // CORPUS specialize? +} + +message ExprColAlias { + required Expr expr = 1; + optional Column col_alias = 2; + required bool as = 3; +} + +message ResultColumn { + oneof result_col_oneof { + Column col = 1; + ExprColAlias eca = 2; + Table table_star = 3; + FTS3AuxiliaryFn fts3_fn = 4; // Only emitted when FUZZ_FTS3 enabled + } // if nothing, use star * +} + +message SelectStatementCore { + enum SelectOrDistinct { + SELECT_DISTINCT = 0; + SELECT = 1; + SELECT_ALL = 2; + } + required SelectOrDistinct s_or_d = 1; + repeated ResultColumn result_columns = 2; + optional FromStatement from = 3; + optional WhereStatement where = 4; + optional GroupByStatement groupby = 5; + optional WindowStatement window = 6; +} + +message WithStatement { + required bool recursive = 1; + required CommonTableExpr table_expr = 2; + repeated CommonTableExpr extra_table_exprs = 3; +} + +message FromStatement { + required TableOrSubqueryOption3 tos3 = 1; +} + +message WindowStatement { + required WindowStatementNaming win = 1; + repeated WindowStatementNaming extra_wins = 2; +} + +message WindowStatementNaming { + required WindowName name = 1; + required WindowDefn defn = 2; +} + +message GroupByStatement { + // CORPUS specialize all these exprs???? + required ExprList exprs = 1; + optional Expr having_expr = 3; +} + +message WhereStatement { + required ExprComparisonHighProbability expr = 1; +} + +message CommonTableExpr { + required Table table = 1; + repeated Column columns = 2; + required Select select = 3; +} + +// ~~~~Join stuff~~~~~ +message JoinClause { + required TableOrSubquery tos = 1; + repeated JoinClauseCore clauses = 2; +} + +message JoinClauseCore { + required JoinOperator join_op = 1; + required TableOrSubquery tos = 2; + required JoinConstraint join_constraint = 3; +} + +message JoinOperator { + required bool comma = 1; + // the following fields only used if comma is false + required bool natural = 2; + enum JoinType { + LEFT = 0; + LEFT_OUTER = 1; + INNER = 2; + CROSS = 3; + NONE = 4; + } + required JoinType join_type = 3; +} + +message JoinConstraint { + oneof join_constraint_oneof { + Expr on_expr = 1; + UsingExpr using_expr = 2; + } // fine if empty +} + +message UsingExpr { + required ColumnList col_list = 1; +} + +// ~~~~~Table names etc.~~~~~ + +// First checks if main is set. Then checks if temp is set. Then checks if +// other schema number is set. +message Schema { + required uint32 schema = 1; + required bool main = 2; + required bool temp = 3; +} + +message Table { + required uint32 table = 1; + optional bool fts3_content_table = 2; // only used for FTS3 fuzzing +} + +message Column { + required uint32 column = 1; + optional bool rowid = 2; // can also have "rowid" column + + // FTS has a hidden column with the same name as the table. + optional FTS3Table fts3_table = 3; + // FTS3 tables have "docid" as an alias for "rowid". + optional bool fts3_docid = 4; +} + +message WindowName { + required uint32 window_name = 1; +} + +message ColumnConstraintName { + required uint32 constraint_name = 1; +} + +message TableConstraintName { + required uint32 constraint_name = 1; +} + +message Index { + required uint32 index = 1; +} + +// Example: +// column1, column2, column3 +message ColumnList { + required Column col = 1; + repeated Column extra_cols = 2; +} + +// ~~~~table-or-subquery~~~~ +message TableOrSubquery { + oneof tos_oneof { + QualifiedTableName qtn = 1; + TableOrSubqueryOption2 toso2 = 2; + TableOrSubqueryOption3 toso3 = 3; + TableOrSubqueryOption4 toso4 = 4; + } + required ExprSchemaTable schema_table_expr = 5; // used if the oneof is empty +} + +message TableOrSubqueryOption2 { + required ExprSchemaTableFn schema_table_fn = 1; + optional AsTableAlias as_table_alias = 2; +} + +message TableOrSubqueryOption3 { + repeated TableOrSubquery tos_list = 1; // if empty, use the join clause + required JoinClause join_clause = 2; +} + +message TableOrSubqueryOption4 { + required Select select = 1; + optional AsTableAlias as_table_alias = 2; +} + +message AsTableAlias { + required bool as = 2; + required Table table_alias = 3; +} + +// ~~~~Expressions~~~~ +message Expr { + oneof expr_oneof { + LiteralValue lit_val = 1; + ComplicatedExpr comp_expr = 2; + } +} + +message LiteralValue { + enum SpecialVal { + VAL_NULL = 0; // using just "NULL" vauses it not to compile. + TRUE = 1; + FALSE = 2; + CURRENT_TIME = 3; + CURRENT_DATE = 4; + CURRENT_TIMESTAMP = 5; + } + oneof lit_val_oneof { + int64 num_lit = 1; + string string_lit = 2; + bytes blob_lit = 3; + SpecialVal special_val = 4; + } // If no value, just use int64(1) +} + +enum UnaryOperator { + UNOP_MINUS = 1; + UNOP_PLUS = 2; + UNOP_TILDE = 3; + UNOP_NOT = 4; +} + +message UnaryExpr { + required UnaryOperator unary_op = 1; + required Expr expr = 2; +} + +enum BinaryOperator { + BINOP_CONCAT = 1; // double pipe + BINOP_STAR = 2; + BINOP_SLASH = 3; + BINOP_PERCENT = 4; + BINOP_PLUS = 5; + BINOP_MINUS = 6; + BINOP_LELE = 7; // << + BINOP_GRGR = 8; // >> + BINOP_AMPERSAND = 9; + BINOP_PIPE = 10; + BINOP_LE = 11; + BINOP_LEQ = 12; + BINOP_GR = 13; + BINOP_GREQ = 14; + BINOP_EQ = 15; + BINOP_EQEQ = 16; + BINOP_NOTEQ = 17; + BINOP_LEGR = 18; // <> (not equal) + BINOP_IS = 19; + BINOP_ISNOT = 20; + BINOP_IN = 21; + BINOP_LIKE = 22; + BINOP_GLOB = 23; + BINOP_MATCH = 24; + BINOP_REGEXP = 25; + BINOP_AND = 26; + BINOP_OR = 27; +} + +message BinaryExpr { + required Expr lhs = 1; + required BinaryOperator op = 2; + required Expr rhs = 3; + + // In FUZZ_FTS3 mode, if |fmt| exists we will use it instead of rhs to + // help generate better MATCH queries. + optional FTS3MatchFormat fmt = 4; +} + +// Used to inflate the probability that we get a comparison of a column with an +// expr. This is useful, as an example, for WHERE expressions. +message ExprComparisonHighProbability { + oneof expr_comp_oneof { + ColumnComparison cc = 1; + Expr expr = 2; + } +} + +// Special version of expr that only generates predicates with a column on the +// left. +message ColumnComparison { + required ExprSchemaTableColumn col = 1; + required BinaryOperator op = 2; + required Expr expr = 3; + // In FUZZ_FTS3 mode, if |fmt| exists we will use it instead of rhs to + // help generate better MATCH queries. + optional FTS3MatchFormat fmt = 4; +} + +message ExprSchemaTableColumn { + optional Schema schema = 1; + optional Table table = 2; + required Column col = 3; +} + +// Separate this out to inflate the probability of having a literal value +message ComplicatedExpr { + // Don't want bind-parameter, unless fuzzing sql_bind + oneof complicated_expr_oneof { + ExprSchemaTableColumn expr_stc = 2; + UnaryExpr unary_expr = 3; + BinaryExpr binary_expr = 4; + Fn fn_expr = 5; + ParenthesesExpr par_expr = 6; + CastExpr cast_expr = 7; + CollateExpr collate_expr = 8; + Expr1 expr1 = 9; + ExprNullTests expr_null_tests = 10; + ExprIs expr_is = 11; + ExprBetween expr_between = 12; + ExprIn expr_in = 17; + ExprExists expr_exists = 13; + ExprCase expr_case = 14; + ExprRaiseFn expr_raise = 15; + } + required LiteralValue lit_val = 16; // used if oneof is empty. +} + +message ExprRaiseFn { + required bool ignore = 3; + enum RaiseFnEnum { + ROLLBACK = 0; + ABORT = 1; + FAIL = 2; + } + required RaiseFnEnum raise_fn = 1; + required string error_msg = 2; +} + +message ExprCase { + optional Expr expr = 1; + required ExprWhenThen when_then = 2; + repeated ExprWhenThen extra_when_thens = 3; + optional Expr else_expr = 4; +} + +message ExprWhenThen { + required Expr when_expr = 1; + required Expr then_expr = 2; +} + +message ExprExists { + required bool not = 1; + required bool exists = 2; + required Select select = 3; +} + +message ExprIn { + required Expr expr = 5; + required bool not = 1; + oneof exprin_oneof { + ExprInParen expr_in_paren = 2; + ExprSchemaTable schema_table = 3; + ExprSchemaTableFn schema_table_fn = 4; + } +} + +message ExprSchemaTable { + optional Schema schema_name = 1; + required Table table_name = 2; +} + +message ExprSchemaTableFn { + required TableFn table_fn = 2; + // FIXME in the future add more. For now, no exprs. +} + +message ExprInParen { + oneof exprin_paren_oneof { + Select select = 1; + ExprList exprs = 2; + } // if zero, can just emit closed parentheses +} + +message ExprList { + required Expr expr = 1; + repeated Expr extra_exprs = 2; +} + +message Expr1 { + required Expr expr1 = 5; + required bool not = 1; + enum PossibleKeywords { + LIKE = 0; + GLOB = 1; + REGEXP = 2; + MATCH = 3; + } + required PossibleKeywords keyword = 2; + required Expr expr2 = 3; + optional Expr escape_expr = 4; // CORPUS specialize? +} + +message ExprNullTests { + required Expr expr = 1; + enum PossibleKeywords { + ISNULL = 0; + NOTNULL = 1; + NOT_NULL = 2; + } + required PossibleKeywords keyword = 2; +} + +message ExprIs { + required bool not = 1; + required Expr expr1 = 2; + required Expr expr2 = 3; +} + +message ExprBetween { + required bool not = 1; + required Expr expr1 = 2; + required Expr expr2 = 3; + required Expr expr3 = 4; +} + +enum CollateType { + COLLATE_BINARY = 1; + COLLATE_NOCASE = 2; + COLLATE_RTRIM = 3; +} + +message CollateExpr { + required Expr expr = 1; + required CollateType collate_type = 2; +} + +message CastTypeName { + enum CastTypeNameEnum { + NONE = 0; + TEXT = 1; + REAL = 2; + INTEGER = 3; + NUMERIC = 4; + } + required CastTypeNameEnum type_enum = 1; +} + +message CastExpr { + required Expr expr = 1; + required CastTypeName type_name = 2; +} + +message ParenthesesExpr { + required Expr expr = 1; + repeated Expr other_exprs = 2; +} + +message Fn { + oneof fn_oneof { + SimpleFn simple_fn = 1; + FTS3AuxiliaryFn fts_aux_fn = 2; + DateAndTimeFn dat_fn = 3; + AggregateFn aggregate_fn = 4; + Printf printf = 5; + } + // FIXME in the future: JSON functions. Not used in Chrome. +} + +// Aggregate FNs +message AggregateFn { + optional bool count_star = 7; + enum FnName { + AVG = 0; + COUNT = 1; + GROUP_CONCAT = 2; + MAX = 3; + MIN = 4; + SUM = 5; + TOTAL = 6; + } + required FnName fn_name = 6; + required bool distinct = 5; + optional Column col1 = 1; + optional Column col2 = 2; + required Expr expr1 = 3; + optional Expr expr2 = 4; +} + +// Date and Time Functions +message DateAndTimeFn { + optional SimpleDateAndTimeFn simple = 1; + required StrftimeFn strftime = 2; +} + +message StrftimeFn { + repeated StrftimeFormat fmts = 1; + required TimeString time_string = 2; + repeated TimeModifier modifiers = 3; +} + +message StrftimeFormat { + enum Substitution { + D = 0; + F = 1; + H = 2; + J = 3; + M = 4; + S = 5; + W = 6; + Y = 7; + } + required bool lowercase = 1; + optional Substitution subs = 2; + required string bytes = 3; +} + +message SimpleDateAndTimeFn { + enum FnName { + DATE = 0; + TIME = 1; + DATETIME = 2; + JULIANDAY = 3; + } + required FnName fn_name = 1; + required TimeString time_string = 2; + repeated TimeModifier modifiers = 3; +} + +message HoursStuff { + optional uint32 hh = 1; + optional uint32 mm = 2; + optional uint32 ss = 3; + optional uint32 sss = 4; +} + +message TimeString { + optional uint32 yyyy = 1; + optional uint32 mm = 2; + optional uint32 dd = 3; + optional HoursStuff hs = 4; + required bool extra_t = 6; + + optional uint32 dddddddddd = 7; + + required bool now = 8; + + optional string random_bytes = 9; + + required bool z = 13; + required bool plus = 14; + optional bool tz_plus = 10; + optional uint32 tz_hh = 11; + optional uint32 tz_mm = 12; +} + +message TimeModifier { + enum NumberedModifiers { + DAYS = 0; + HOURS = 1; + MINUTES = 2; + SECONDS = 3; + MONTHS = 4; + YEARS = 5; + } + required uint32 num = 4; + optional uint32 dot_num = 5; + optional NumberedModifiers nm = 1; + enum OtherModifiers { + START_OF_MONTH = 0; + START_OF_YEAR = 1; + START_OF_DAY = 2; + WEEKDAY = 3; + UNIXEPOCH = 4; + LOCALTIME = 5; + UTC = 6; + } + required OtherModifiers om = 2; + required uint32 weekday = 3; +} + +// Simple Functions finish +message SimpleFn { + oneof simple_fn_oneof { + ZeroArgFn zero_arg_fn = 1; + OneArgFn one_arg_fn = 2; + TwoArgFn two_arg_fn = 3; + ThreeArgFn three_arg_fn = 4; + VarNumFn varnum_fn = 5; + CharFn char_fn = 6; + } +} + +// Zero arguments fn +enum ZeroArgFn { + ZFN_CHANGES = 0; + ZFN_LAST_INSERT_ROWID = 1; + ZFN_RANDOM = 2; + ZFN_SQLITE_SOURCE_ID = 3; + ZFN_SQLITE_VERSION = 4; + ZFN_TOTAL_CHANGES = 5; +} + +message OneArgFn { + enum OneArgFnEnum { + ABS = 1; + HEX = 2; + LENGTH = 3; + LIKELY = 4; + LOWER = 5; + LTRIM = 6; + LOAD_EXTENSION = 7; + QUOTE = 8; + ROUND = 9; + RTRIM = 10; + RANDOMBLOB = 11; + SOUNDEX = 12; + SQLITE_COMPILE_OPTION_GET = 13; + SQLITE_COMPILE_OPTION_USED = 14; + SQLITE_OFFSET = 15; + TRIM = 16; + TYPEOF = 17; + UNICODE_ = 18; + UNLIKELY = 19; + UPPER = 20; + ZEROBLOB = 21; + } + required OneArgFnEnum fn_enum = 1; + required Expr arg1 = 2; +} + +message TwoArgFn { + enum TwoArgFnEnum { + GLOB = 1; + IFNULL = 2; + INSTR = 3; + LIKE = 4; + LIKELIHOOD = 5; + LOAD_EXTENSION = 6; + LTRIM = 7; + NULLIF = 8; + ROUND = 9; + RTRIM = 10; + SUBSTR = 11; + TRIM = 12; + } + required TwoArgFnEnum fn_enum = 1; + required Expr arg1 = 2; + required Expr arg2 = 3; +} + +message ThreeArgFn { + enum ThreeArgFnEnum { + LIKE = 0; + REPLACE = 1; + SUBSTR = 2; + } + required ThreeArgFnEnum fn_enum = 1; + required Expr arg1 = 2; + required Expr arg2 = 3; + required Expr arg3 = 4; +} + +// Fns with two args required + an arbitrary number of other args. +message VarNumFn { + enum VarNumFnEnum { + COALESCE = 1; + MAX = 2; + MIN = 3; + } + required VarNumFnEnum fn_enum = 1; + required Expr arg1 = 2; + required Expr arg2 = 3; + repeated Expr other_args = 4; +} + +message CharFn { + required uint64 char = 1; + repeated uint64 extra_chars = 2; +} + +message Printf { + repeated string strings = 1; + repeated PrintfFormatSpecifier specifiers = 2; + repeated Expr exprs = 3; +} + +message PrintfFormatSpecifier { + enum Flags { + MINUS = 0; + PLUS = 1; + SPACE = 2; + ZERO = 3; + HASH = 4; + COMMA = 5; + BANG = 6; + } + repeated Flags flags = 1; + optional uint32 precision = 2; + optional uint32 width = 3; + optional bool width_star = 4; + // The length modifiers make no difference for the sqlite function. + optional uint32 length = 5; + enum SubType { + I = 0; + D = 1; + U = 2; + F = 3; + E = 4; + G = 5; + X = 6; + O = 7; + S = 8; + Z = 9; + C = 10; + P = 11; + N = 12; + Q = 13; + W = 14; + } + optional bool percent = 8; + required SubType sub_type = 6; + required bool lowercase = 7; +} + +// Window fns! +// FIXME in the future: this may only be in the result set and the ORDER_BY +// clause of a SELECT statement. +message WindowFnInvocation { + oneof window_fn_oneof { + ZeroArgWinFn zero_arg_fn = 1; + OneArgWinFn one_arg_fn = 2; + NthValueFn nth_value_fn = 4; + MiscWinFn misc_fn = 3; + } + + // Used if the above oneof produces zero values. + required ZeroArgWinFn fallback_zero_arg_fn = 5; + + // FIXME in the future: may just replace with a WHERE expr. + optional ExprFilter expr_filter = 6; + optional WindowDefn win_defn = 7; + required WindowName win_name = 8; // used only if win_defn above is unused. +} + +message WindowDefn { + // FIXME in the future: change to specialized expr + optional ExprList partition_exprs = 1; + optional MultipleOrderingTerm ordering_terms = 2; + optional ExprFrameSpec frame_spec = 3; +} + +message ExprFrameSpec { + enum RangeRows { + RANGE = 0; + ROWS = 1; + } + required RangeRows range_rows = 1; + required FrameSpecSubExpr left_expr = 2; + // if this exists, then this is a BETWEEN statement. + optional FrameSpecSubExprRight right_expr = 3; +} + +message FrameSpecSubExpr { + enum Which { + UNBOUNDED_PRECEDING = 0; + EXPR_PRECEDING = 1; + CURRENT_ROW = 2; + EXPR_FOLLOWING = 3; + } + required Which which = 1; + // only used if which is EXPR_PRECEDING or EXPR_FOLLOWING + optional Expr expr = 2; // CORPUS specialize? integer? +} + +message FrameSpecSubExprRight { + enum Which { + UNBOUNDED_FOLLOWING = 0; + EXPR_PRECEDING = 1; + CURRENT_ROW = 2; + EXPR_FOLLOWING = 3; + } + required Which which = 1; + // only used if which is EXPR_PRECEDING or EXPR_FOLLOWING + optional Expr expr = 2; // CORPUS specialize? integer? +} + +message MultipleOrderingTerm { + repeated ExprOrderingTerm terms = 1; +} + +message ExprOrderingTerm { + required Expr expr = 1; // CORPUS specialize??? + optional CollateType collate_type = 2; + required AscDesc asc_desc = 3; +} + +enum AscDesc { + ASCDESC_NONE = 0; + ASCDESC_ASC = 1; + ASCDESC_DESC = 2; +} + +message ExprFilter { + required Expr expr = 1; +} + +message ZeroArgWinFn { + enum ZeroArgWinFnEnum { + ROW_NUMBER = 0; + RANK = 1; + DENSE_RANK = 2; + PERCENT_RANK = 3; + CUME_DIST = 4; + } + required ZeroArgWinFnEnum win_fn = 1; +} + +message OneArgWinFn { + enum OneArgWinFnEnum { + NTILE = 0; + FIRST_VALUE = 1; + LAST_VALUE = 2; + } + required OneArgWinFnEnum win_fn = 1; + required Expr expr = 2; +} + +message NthValueFn { + required Expr expr = 1; + required uint32 row_num = 2; +} + +message MiscWinFn { + enum MiscWinFnEnum { + LAG = 0; + LEAD = 1; + } + required MiscWinFnEnum fn = 1; + required Expr expr = 2; + optional uint32 offset = 3; + optional Expr default = 4; // unused if offset non-existent +} +// FIXME in the future: all aggregate functions may be used as window aggregate +// functions! + +// Table-valued FNs, including pragma table-valued fns. +enum PragmaFnZeroArgOneResult { + PFN_ZO_APPLICATION_ID = 0; + PFN_ZO_AUTO_VACUUM = 1; + PFN_ZO_AUTOMATIC_INDEX = 2; + PFN_ZO_BUSY_TIMEOUT = 3; + PFN_ZO_CACHE_SIZE = 4; + PFN_ZO_CACHE_SPILL = 5; + PFN_ZO_CELL_SIZE_CHECK = 6; + PFN_ZO_CHECKPOINT_FULL_FSYNC = 7; + PFN_ZO_COLLATION_LIST = 8; + PFN_ZO_COMPILE_OPTIONS = 9; + PFN_ZO_COUNT_CHANGES = 10; + PFN_ZO_DATA_VERSION = 11; + PFN_ZO_DATABASE_LIST = 12; + PFN_ZO_DEFAULT_CACHE_SIZE = 13; + PFN_ZO_DEFER_FOREIGN_KEYS = 14; + PFN_ZO_EMPTY_RESULT_CALLBACKS = 15; + PFN_ZO_ENCODING = 16; + PFN_ZO_FOREIGN_KEY_CHECK = 17; + PFN_ZO_FOREIGN_KEYS = 18; + PFN_ZO_FREELIST_COUNT = 19; + PFN_ZO_FULL_COLUMN_NAMES = 20; + PFN_ZO_FULLFSYNC = 21; + PFN_ZO_FUNCTION_LIST = 22; + PFN_ZO_IGNORE_CHECK_CONSTRAINTS = 23; + PFN_ZO_INTEGRITY_CHECK = 24; + PFN_ZO_JOURNAL_SIZE_LIMIT = 25; + PFN_ZO_LEGACY_ALTER_TABLE = 26; + PFN_ZO_LEGACY_FILE_FORMAT = 27; + PFN_ZO_LOCK_STATUS = 28; + PFN_ZO_LOCKING_MODE = 29; + PFN_ZO_MAX_PAGE_COUNT = 30; + PFN_ZO_MODULE_LIST = 31; + PFN_ZO_PAGE_COUNT = 32; + PFN_ZO_PAGE_SIZE = 33; + PFN_ZO_PRAGMA_LIST = 34; + PFN_ZO_QUERY_ONLY = 35; + PFN_ZO_QUICK_CHECK = 36; + PFN_ZO_READ_UNCOMMITTED = 37; + PFN_ZO_RECURSIVE_TRIGGERS = 38; + PFN_ZO_REVERSE_UNORDERED_SELECTS = 39; + PFN_ZO_SCHEMA_VERSION = 40; + PFN_ZO_SECURE_DELETE = 41; + PFN_ZO_SHORT_COLUMN_NAMES = 42; + PFN_ZO_SOFT_HEAP_LIMIT = 43; + PFN_ZO_SQL_TRACE = 44; + PFN_ZO_STATS = 45; + PFN_ZO_SYNCHRONOUS = 46; + PFN_ZO_TEMP_STORE = 47; + PFN_ZO_THREADS = 48; + PFN_ZO_USER_VERSION = 49; + // omit vdbe_* debug pragmas + PFN_ZO_WRITEABLE_SCHEMA = 50; +} + +message TableFn { + required PragmaFnZeroArgOneResult no_arg_one_result = 10; + oneof pragma_fn_oneof { + Table foreign_key_list = 1; + Index index_info = 2; + Table index_list = 3; + Index index_xinfo = 4; + uint32 integrity_check = 5; + uint32 optimize = 6; + uint32 quick_check = 7; + Table table_info = 8; + Table table_xinfo = 9; + } +}
diff --git a/third_party/sqlite/fuzz/sql_query_proto_to_string.cc b/third_party/sqlite/fuzz/sql_query_proto_to_string.cc new file mode 100644 index 0000000..7bd9682 --- /dev/null +++ b/third_party/sqlite/fuzz/sql_query_proto_to_string.cc
@@ -0,0 +1,2667 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include <algorithm> +#include <array> +#include <cctype> +#include <cstdint> +#include <iomanip> +#include <map> +#include <sstream> +#include <string> +#include <vector> + +#include "third_party/sqlite/fuzz/icu_codes.pb.h" +#include "third_party/sqlite/fuzz/sql_queries.pb.h" +#include "third_party/sqlite/fuzz/sql_query_grammar.pb.h" +#include "third_party/sqlite/fuzz/sql_query_proto_to_string.h" + +using namespace sql_query_grammar; + +#define CONV_FN(TYPE, VAR_NAME) std::string TYPE##ToString(const TYPE& VAR_NAME) + +namespace sql_fuzzer { + +namespace { +constexpr uint32_t kMaxColumnNumber = 20; +#if !defined(FUZZ_FTS3) +constexpr uint32_t kMaxTableNumber = 8; +#endif +constexpr uint32_t kMaxSchemaNumber = 4; +constexpr uint32_t kMaxWindowNumber = 5; + +constexpr uint32_t kMaxColumnConstraintNumber = 10; +constexpr uint32_t kMaxTableConstraintNumber = 10; + +constexpr uint32_t kMaxIndexNumber = 10; + +// should be less than kMaxTableNumber +constexpr uint32_t kMaxFTS3TableNumber = 2; + +constexpr uint32_t kMaxStrLength = + 200; // So these are readable and somewhat performant, keep a maximum + // string length...... + +#if !defined(FUZZ_OMIT_SAVEPOINT) +constexpr uint32_t kMaxSavePointNumber = 10; +#endif + +constexpr uint32_t kMaxViewNumber = 5; +constexpr uint32_t kMaxTriggerNumber = 10; +} // namespace + +CONV_FN(Expr, expr); +CONV_FN(Select, select); +CONV_FN(TableOrSubquery, tos); +CONV_FN(FTS3Table, ft); +CONV_FN(FTS3NearQuery, fnq); +CONV_FN(FTS3AuxiliaryFn, faf); +CONV_FN(FTS3MatchFormat, fmf); +CONV_FN(DateAndTimeFn, sfn); +CONV_FN(ExprSchemaTableFn, estf); + +// ~~~~Numbered values to string~~~ + +// WARNING does not include space at the end +CONV_FN(Column, col) { + if (col.has_rowid() && col.rowid()) + return "rowid"; +#if defined(FUZZ_FTS3) + if (col.has_fts3_docid() && col.fts3_docid()) + return "docid"; + if (col.has_fts3_table()) + return FTS3TableToString(col.fts3_table()); +#endif + std::string ret("Col"); + ret += std::to_string(col.column() % kMaxColumnNumber); + return ret; +} + +// WARNING does not include space at the end +CONV_FN(Table, table) { + std::string ret("Table"); +#if defined(FUZZ_FTS3) + // only fuzzing FTS3 tables, clamp to the max FTS3 table num. + ret += std::to_string(table.table() & kMaxFTS3TableNumber); + if (table.fts3_content_table()) + ret += "_content"; +#else + ret += std::to_string(table.table() % kMaxTableNumber); +#endif + return ret; +} + +// WARNING does not include space at the end +CONV_FN(Schema, schema) { + if (schema.main()) { + return "main"; + } + if (schema.temp()) { + return "temp"; + } + std::string ret("Schema"); + ret += std::to_string(schema.schema() % kMaxSchemaNumber); + return ret; +} + +// WARNING does not include space at the end +CONV_FN(WindowName, win) { + std::string ret("Window"); + ret += std::to_string(win.window_name() % kMaxWindowNumber); + return ret; +} + +// WARNING does not include space at the end +CONV_FN(ColumnConstraintName, cc) { + std::string ret("ColConstraint"); + ret += std::to_string(cc.constraint_name() % kMaxColumnConstraintNumber); + return ret; +} + +// WARNING does not include space at the end +CONV_FN(TableConstraintName, tc) { + std::string ret("TableConstraint"); + ret += std::to_string(tc.constraint_name() % kMaxTableConstraintNumber); + return ret; +} + +// WARNING does not include space at the end +CONV_FN(Index, index) { + std::string ret("Index"); + ret += std::to_string(index.index() % kMaxIndexNumber); + return ret; +} + +#if !defined(FUZZ_OMIT_SAVEPOINT) +CONV_FN(SavePoint, sp) { + std::string ret("SavePoint"); + ret += std::to_string(sp.savepoint_num() % kMaxSavePointNumber); + return ret; +} +#endif + +CONV_FN(View, v) { + std::string ret("View"); + ret += std::to_string(v.view() % kMaxViewNumber); + return ret; +} + +CONV_FN(Trigger, t) { + std::string ret("Trigger"); + ret += std::to_string(t.trigger() % kMaxTriggerNumber); + return ret; +} + +// ~~~~Utility functions~~~~ + +std::string AscDescToString(AscDesc a) { + switch (a) { + case ASCDESC_NONE: + return " "; + case ASCDESC_ASC: + return "ASC "; + case ASCDESC_DESC: + return "DESC "; + default: + return " "; + } +} + +std::string StrToLower(std::string s) { + std::transform( + s.begin(), s.end(), s.begin(), + [](unsigned char c) -> unsigned char { return std::tolower(c); }); + return s; +} + +std::string StripTrailingUnderscores(std::string s) { + s.erase(std::find_if(s.rbegin(), s.rend(), + [](unsigned char ch) { return ch != '_'; }) + .base(), + s.end()); + return s; +} + +// Converts underscores to spaces in a string. +// This is because many enums like SET_NULL will be displayed at SET NULL in +// the query, and I want to use protobuf's enum to string function to save time. +std::string EnumStrReplaceUnderscores(std::string s) { + std::transform(s.begin(), s.end(), s.begin(), + [](unsigned char c) -> unsigned char { + if (c == '_') + return ' '; + return c; + }); + return s; +} + +// Takes garbage data and produces a string, with quotes escaped. +// Caps the number of bytes received from the protobuf at kMaxStrLength. +// The final string could be as much as kMaxStrLength*2 as we added an extra +// single quote for every single quote in the input string. +std::string ConvertToSqlString(const std::string& s) { + std::string ret; + ret.reserve(kMaxStrLength * 2); + for (size_t i = 0; i < s.length() && i < kMaxStrLength; i++) { + ret += s[i]; + if (s[i] == '\'') + ret += '\''; + } + return ret; +} + +// WARNING does not include space +std::string BytesToHex(const std::string& str) { + std::ostringstream ss; + ss << std::hex << std::setfill('0'); + for (size_t i = 0; i < str.size() && i < kMaxStrLength; i++) { + ss << std::setw(2) << static_cast<int>(str[i]); + } + return ss.str(); +} + +// WARNING no space at end +CONV_FN(ExprSchemaTable, st) { + std::string ret; + if (st.has_schema_name()) { + ret += SchemaToString(st.schema_name()); + ret += "."; + } + ret += TableToString(st.table_name()); + return ret; +} + +CONV_FN(ExprSchemaTableColumn, stc) { + std::string ret; + if (stc.has_schema()) { + ret += SchemaToString(stc.schema()); + ret += "."; + } + if (stc.has_table()) { + ret += TableToString(stc.table()); + ret += "."; + } + ret += ColumnToString(stc.col()); + return ret; +} + +// WARNING does not include parentheses, nor a space at the end +CONV_FN(ColumnList, cl) { + std::string ret = ColumnToString(cl.col()); + for (int i = 0; i < cl.extra_cols_size(); i++) { + ret += ", "; + ret += ColumnToString(cl.extra_cols(i)); + } + return ret; +} + +CONV_FN(ExprList, me) { + std::string ret = ExprToString(me.expr()); + for (int i = 0; i < me.extra_exprs_size(); i++) { + ret += ", "; + ret += ExprToString(me.extra_exprs(i)); + } + return ret; +} + +// WARNING does not include space +CONV_FN(CollateType, collate_type) { + std::string ct = CollateType_Name(collate_type); + ct.erase(0, std::string("COLLATE_").length()); + return ct; +} + +// WARNING does not include space +CONV_FN(IndexedColumn, ic) { + std::string ret; + if (ic.has_expr()) { + ret += ExprToString(ic.expr()); + } else { + ret += ColumnToString(ic.col()); + } + ret += " "; + if (ic.has_collate_type()) { + ret += "COLLATE "; + ret += CollateTypeToString(ic.collate_type()); + ret += " "; + } + ret += AscDescToString(ic.asc_desc()); + + return ret; +} + +CONV_FN(IndexedColumnList, ic_list) { + std::string ret; + ret += IndexedColumnToString(ic_list.indexed_col()); + for (int i = 0; i < ic_list.extra_indexed_cols_size(); i++) { + ret += ", "; + ret += IndexedColumnToString(ic_list.extra_indexed_cols(i)); + } + return ret; +} + +CONV_FN(SchemaTableAsAlias, staa) { + std::string ret; + ret += ExprSchemaTableToString(staa.schema_table()); + ret += " "; + + if (staa.has_as_table_alias()) { + ret += "AS "; + ret += TableToString(staa.as_table_alias()); + ret += " "; + } + return ret; +} + +// ~~~~Expression stuff~~~~ + +// WARNING does not include space +CONV_FN(LiteralValue, lit_val) { + std::string ret; + using LitValType = LiteralValue::LitValOneofCase; + switch (lit_val.lit_val_oneof_case()) { + case LitValType::kNumLit: + return std::to_string(lit_val.num_lit()); + case LitValType::kStringLit: + ret += '\''; + ret += ConvertToSqlString(lit_val.string_lit()); + ret += '\''; + return ret; + case LitValType::kBlobLit: + ret += "x\'"; + ret += BytesToHex(lit_val.blob_lit()); + ret += '\''; + return ret; + case LitValType::kSpecialVal: + // special case for NULL + if (lit_val.special_val() == LiteralValue::VAL_NULL) + return "NULL"; + // do not remove underscores + return LiteralValue_SpecialVal_Name(lit_val.special_val()); + default: + return "1"; + } +} + +CONV_FN(UnaryExpr, uexpr) { + std::string ret; + switch (uexpr.unary_op()) { + case UNOP_MINUS: + ret += "-"; + break; + case UNOP_PLUS: + ret += "+"; + break; + case UNOP_TILDE: + ret += "~"; + break; + case UNOP_NOT: + ret += "NOT "; + break; + default: + break; + } + ret += ExprToString(uexpr.expr()); + return ret; +} + +CONV_FN(BinaryOperator, bop) { + switch (bop) { + case BINOP_CONCAT: + return " || "; + break; + case BINOP_STAR: + return " * "; + break; + case BINOP_SLASH: + return " / "; + break; + case BINOP_PERCENT: + return " % "; + break; + case BINOP_PLUS: + return " + "; + break; + case BINOP_MINUS: + return " - "; + break; + case BINOP_LELE: + return " << "; + break; + case BINOP_GRGR: + return " >> "; + break; + case BINOP_AMPERSAND: + return " & "; + break; + case BINOP_PIPE: + return " | "; + break; + case BINOP_LE: + return " < "; + break; + case BINOP_LEQ: + return " <= "; + break; + case BINOP_GR: + return " > "; + break; + case BINOP_GREQ: + return " >= "; + break; + case BINOP_EQ: + return " = "; + break; + case BINOP_EQEQ: + return " == "; + break; + case BINOP_NOTEQ: + return " != "; + break; + case BINOP_LEGR: + return " <> "; + break; + case BINOP_IS: + return " IS "; + break; + case BINOP_ISNOT: + return " IS NOT "; + break; + case BINOP_IN: + return " IN "; // CORPUS specialize? + break; + case BINOP_LIKE: + return " LIKE "; // CORPUS specialize? + break; + case BINOP_GLOB: + return " GLOB "; // CORPUS + break; + case BINOP_MATCH: + return " MATCH "; // CORPUS + break; + case BINOP_REGEXP: + return " REGEXP "; // CORPUS + break; + case BINOP_AND: + return " AND "; + break; + case BINOP_OR: + return " OR "; + break; + default: + return " AND "; + break; + } +} + +// TODO(mpdenton) generate better REGEXP queries in non-fts3 case. (in +// ColumnComparison as well) +// TODO(mpdenton) generate better MATCH queries in non-fts3 case. +CONV_FN(BinaryExpr, bexpr) { + std::string ret; + ret += ExprToString(bexpr.lhs()); + ret += BinaryOperatorToString(bexpr.op()); +#if defined(FUZZ_FTS3) + if (bexpr.op() == BINOP_MATCH && bexpr.has_fmt()) { + ret += FTS3MatchFormatToString(bexpr.fmt()); + return ret; + } +#endif + ret += ExprToString(bexpr.rhs()); + return ret; +} + +CONV_FN(AggregateFn, af) { + std::string ret; + ret += StrToLower(AggregateFn_FnName_Name(af.fn_name())); + ret += "("; + if (af.fn_name() == AggregateFn::COUNT && af.count_star()) + return ret + "*) "; + if (af.distinct()) + ret += "DISTINCT "; + if (af.has_col1()) { + ret += ColumnToString(af.col1()); + if (af.fn_name() == AggregateFn::GROUP_CONCAT && af.has_col2()) { + ret += ", "; + ret += ColumnToString(af.col2()); + } + } else { + ret += ExprToString(af.expr1()); + if (af.fn_name() == AggregateFn::GROUP_CONCAT && af.has_expr2()) { + ret += ", "; + ret += ExprToString(af.expr2()); + } + } + + ret += ") "; + return ret; +} + +CONV_FN(ZeroArgFn, zaf) { + std::string func = ZeroArgFn_Name(zaf); + // Remove ZFN_ prefix + func.erase(0, std::string("ZFN_").length()); + return StrToLower(func) + "() "; +} + +CONV_FN(OneArgFn, oaf) { + std::string ret; + ret += StripTrailingUnderscores( + StrToLower(OneArgFn_OneArgFnEnum_Name(oaf.fn_enum()))); + ret += "("; + ret += ExprToString(oaf.arg1()); + ret += ") "; + return ret; +} + +CONV_FN(TwoArgFn, taf) { + std::string ret; + ret += StrToLower(TwoArgFn_TwoArgFnEnum_Name(taf.fn_enum())); + ret += "("; + ret += ExprToString(taf.arg1()); + ret += ", "; + ret += ExprToString(taf.arg2()); + ret += ") "; + return ret; +} + +CONV_FN(ThreeArgFn, taf) { + std::string ret; + ret += StrToLower(ThreeArgFn_ThreeArgFnEnum_Name(taf.fn_enum())); + ret += "("; + ret += ExprToString(taf.arg1()); + ret += ", "; + ret += ExprToString(taf.arg2()); + ret += ", "; + ret += ExprToString(taf.arg3()); + ret += ") "; + return ret; +} + +CONV_FN(VarNumFn, vfn) { + std::string ret; + ret += StrToLower(VarNumFn_VarNumFnEnum_Name(vfn.fn_enum())); + ret += "("; + ret += ExprToString(vfn.arg1()); + ret += ", "; + ret += ExprToString(vfn.arg2()); + for (int i = 0; i < vfn.other_args_size(); i++) { + ret += ", "; + ret += ExprToString(vfn.other_args(i)); + } + ret += ") "; + return ret; +} + +CONV_FN(CharFn, cfn) { + std::string ret("char("); + ret += std::to_string(cfn.char_()); + for (int i = 0; i < cfn.extra_chars_size(); i++) { + ret += ", "; + ret += std::to_string(cfn.extra_chars(i)); + } + ret += ") "; + return ret; +} + +CONV_FN(SimpleFn, sfn) { + // oneof + if (sfn.has_zero_arg_fn()) { + return ZeroArgFnToString(sfn.zero_arg_fn()); + } else if (sfn.has_one_arg_fn()) { + return OneArgFnToString(sfn.one_arg_fn()); + } else if (sfn.has_two_arg_fn()) { + return TwoArgFnToString(sfn.two_arg_fn()); + } else if (sfn.has_three_arg_fn()) { + return ThreeArgFnToString(sfn.three_arg_fn()); + } else if (sfn.has_varnum_fn()) { + return VarNumFnToString(sfn.varnum_fn()); + } else if (sfn.has_char_fn()) { + return CharFnToString(sfn.char_fn()); + } else { + return "changes() "; + } +} + +CONV_FN(PrintfFormatSpecifier, pfs) { + std::string ret("%"); + for (int i = 0; i < pfs.flags_size(); i++) { + switch (pfs.flags(i)) { + case PrintfFormatSpecifier::MINUS: + ret += "-"; + break; + case PrintfFormatSpecifier::PLUS: + ret += "+"; + break; + case PrintfFormatSpecifier::SPACE: + ret += " "; + break; + case PrintfFormatSpecifier::ZERO: + ret += "0"; + break; + case PrintfFormatSpecifier::HASH: + ret += "#"; + break; + case PrintfFormatSpecifier::COMMA: + ret += ","; + break; + case PrintfFormatSpecifier::BANG: + ret += "!"; + break; + } + } + if (pfs.has_width()) { + ret += std::to_string(pfs.width()); + } else if (pfs.width_star()) { + ret += "*"; + } + if (pfs.has_precision()) { + ret += "."; + ret += std::to_string(pfs.precision()); + } + if (pfs.has_length()) { + if (pfs.length() % 3 == 1) { + ret += "l"; + } else if (pfs.length() % 3 == 2) { + ret += "ll"; + } + } + if (pfs.percent()) { + ret += "%"; + } else { + std::string specifier = PrintfFormatSpecifier_SubType_Name(pfs.sub_type()); + if (pfs.lowercase()) + specifier = StrToLower(specifier); + ret += specifier; + } + return ret; +} + +CONV_FN(Printf, p) { + std::string ret("printf(\'"); + for (int i = 0; i < p.specifiers_size(); i++) { + ret += PrintfFormatSpecifierToString(p.specifiers(i)); + if (i < p.strings_size()) { + ret += ConvertToSqlString(p.strings(i)); + } + } + ret += "\'"; + for (int i = 0; i < p.exprs_size(); i++) { + ret += ", "; + ret += ExprToString(p.exprs(i)); + } + ret += ") "; + return ret; +} + +CONV_FN(Fn, fn) { + // oneof + if (fn.has_simple_fn()) { + return SimpleFnToString(fn.simple_fn()); + } else if (fn.has_fts_aux_fn()) { +#if defined(FUZZ_FTS3) + return FTS3AuxiliaryFnToString(fn.fts_aux_fn()) + " "; +#else + return "changes() "; +#endif + } else if (fn.has_dat_fn()) { + return DateAndTimeFnToString(fn.dat_fn()); + } else if (fn.has_aggregate_fn()) { + return AggregateFnToString(fn.aggregate_fn()); + } else if (fn.has_printf()) { + return PrintfToString(fn.printf()); + } else { + return "changes() "; + } +} + +CONV_FN(ParenthesesExpr, pexpr) { + std::string ret("("); + ret += ExprToString(pexpr.expr()); + for (int i = 0; i < pexpr.other_exprs_size(); i++) { + ret += ", "; + ret += ExprToString(pexpr.other_exprs(i)); + } + ret += ") "; + return ret; +} + +CONV_FN(CastExpr, cexpr) { + std::string ret("CAST("); + ret += ExprToString(cexpr.expr()); + ret += " AS "; + ret += EnumStrReplaceUnderscores( + CastTypeName_CastTypeNameEnum_Name(cexpr.type_name().type_enum())); + ret += ") "; + return ret; +} + +CONV_FN(CollateExpr, cexpr) { + std::string ret; + ret += ExprToString(cexpr.expr()); + ret += " COLLATE "; + ret += CollateTypeToString(cexpr.collate_type()); + return ret; +} + +CONV_FN(Expr1, e) { + std::string ret; + ret += ExprToString(e.expr1()); + ret += " "; + if (e.not_()) + ret += "NOT "; + ret += EnumStrReplaceUnderscores(Expr1_PossibleKeywords_Name(e.keyword())); + ret += " "; + ret += ExprToString(e.expr2()); + ret += " "; // + if (e.has_escape_expr()) { + ret += "ESCAPE "; + ret += ExprToString(e.escape_expr()); + ret += " "; // + } + return ret; +} + +CONV_FN(ExprNullTests, e) { + std::string ret = ExprToString(e.expr()); + ret += " "; + ret += EnumStrReplaceUnderscores( + ExprNullTests_PossibleKeywords_Name(e.keyword())); + ret += " "; + return ret; +} + +CONV_FN(ExprIs, e) { + std::string ret = ExprToString(e.expr1()); + ret += " IS "; + if (e.not_()) + ret += "NOT "; + ret += ExprToString(e.expr2()); + ret += " "; // + return ret; +} + +CONV_FN(ExprBetween, e) { + std::string ret; + ret += ExprToString(e.expr1()); + ret += " "; + if (e.not_()) + ret += "NOT "; + ret += "BETWEEN "; + ret += ExprToString(e.expr2()); + ret += " AND "; + ret += ExprToString(e.expr3()); + return ret; +} + +CONV_FN(ExprInParen, e) { + std::string ret("("); + // oneof + if (e.has_select()) { + ret += SelectToString(e.select()); + } else if (e.has_exprs()) { + ret += ExprListToString(e.exprs()); + } + + ret += ") "; + return ret; +} + +CONV_FN(ExprIn, e) { + std::string ret = ExprToString(e.expr()); + ret += " "; + if (e.not_()) + ret += "NOT "; + if (e.has_expr_in_paren()) { + ret += ExprInParenToString(e.expr_in_paren()); + } else if (e.has_schema_table()) { + ret += ExprSchemaTableToString(e.schema_table()); + } else if (e.has_schema_table_fn()) { + ret += ExprSchemaTableFnToString(e.schema_table_fn()); + } else { + ret += "()"; + } + return ret + " "; +} + +CONV_FN(ExprExists, e) { + std::string ret; + if (e.not_()) + ret += "NOT EXISTS "; + else if (e.exists()) + ret += "EXISTS "; + ret += "("; + ret += SelectToString(e.select()); + ret += ") "; + return ret; +} + +// WARNING no space at end +CONV_FN(ExprWhenThen, e) { + std::string ret("WHEN "); + ret += ExprToString(e.when_expr()); + ret += " THEN "; + ret += ExprToString(e.then_expr()); + return ret; +} + +CONV_FN(ExprCase, e) { + std::string ret("CASE "); + if (e.has_expr()) { + ret += ExprToString(e.expr()); + ret += " "; + } + ret += ExprWhenThenToString(e.when_then()); + ret += " "; + for (int i = 0; i < e.extra_when_thens_size(); i++) { + ret += ExprWhenThenToString(e.extra_when_thens(i)); + ret += " "; + } + if (e.has_else_expr()) { + ret += "ELSE "; + ret += ExprToString(e.else_expr()); + ret += " "; + } + ret += "END "; + return ret; +} + +CONV_FN(ExprRaiseFn, e) { + std::string ret("RAISE("); + if (e.ignore()) { + ret += "IGNORE"; + } else { + ret += + EnumStrReplaceUnderscores(ExprRaiseFn_RaiseFnEnum_Name(e.raise_fn())); + ret += " "; + ret += ", \'"; + ret += ConvertToSqlString(e.error_msg()); + ret += "\'"; + } + ret += ") "; + return ret; +} + +CONV_FN(ComplicatedExpr, expr) { + using ExprType = ComplicatedExpr::ComplicatedExprOneofCase; + switch (expr.complicated_expr_oneof_case()) { + case ExprType::kExprStc: + return ExprSchemaTableColumnToString(expr.expr_stc()); + case ExprType::kUnaryExpr: + return UnaryExprToString(expr.unary_expr()); + case ExprType::kBinaryExpr: + return BinaryExprToString(expr.binary_expr()); + case ExprType::kFnExpr: + return FnToString(expr.fn_expr()); + case ExprType::kParExpr: + return ParenthesesExprToString(expr.par_expr()); + case ExprType::kCastExpr: + return CastExprToString(expr.cast_expr()); + case ExprType::kCollateExpr: + return CollateExprToString(expr.collate_expr()); + case ExprType::kExpr1: + return Expr1ToString(expr.expr1()); + case ExprType::kExprNullTests: + return ExprNullTestsToString(expr.expr_null_tests()); + case ExprType::kExprIs: + return ExprIsToString(expr.expr_is()); + case ExprType::kExprBetween: + return ExprBetweenToString(expr.expr_between()); + case ExprType::kExprIn: + return ExprInToString(expr.expr_in()); + case ExprType::kExprExists: + return ExprExistsToString(expr.expr_exists()); + case ExprType::kExprCase: + return ExprCaseToString(expr.expr_case()); + case ExprType::kExprRaise: + return ExprRaiseFnToString(expr.expr_raise()); + default: + return "1"; + } +} + +// TODO(mpdenton) wrap in parentheses??? +CONV_FN(Expr, expr) { + if (expr.has_lit_val()) { + return LiteralValueToString(expr.lit_val()); + } else if (expr.has_comp_expr()) { + return ComplicatedExprToString(expr.comp_expr()); + } else { // default + return "1"; + } +} + +// ~~~~Other~~~~ + +std::string ForeignKeyClauseNotMatchToString( + const ForeignKeyClauseNotMatch& nm) { + std::string ret("ON "); + ret += EnumStrReplaceUnderscores( + ForeignKeyClauseNotMatch_DeleteOrUpdate_Name(nm.del_or_update())); + ret += " "; + ret += EnumStrReplaceUnderscores( + ForeignKeyClauseNotMatch_Action_Name(nm.action())); + ret += " "; + return ret; +} + +CONV_FN(ForeignKeyClauseCore, fkc) { + if (fkc.has_fkey_not_match()) + return ForeignKeyClauseNotMatchToString(fkc.fkey_not_match()); + + return "MATCH PARTIAL"; // Sqlite does not actually parse MATCH clauses. This + // is assumed to be MATCH SIMPLE. +} + +CONV_FN(DeferStrategy, ds) { + std::string ret; + if (ds.not_()) { + ret += "NOT "; + } + ret += "DEFERRABLE "; + ret += + EnumStrReplaceUnderscores(DeferStrategy_DeferStratEnum_Name(ds.strat())); + return ret; +} + +CONV_FN(ForeignKeyClause, fkey_clause) { + std::string ret("REFERENCES "); + ret += TableToString(fkey_clause.foreign_table()); + if (fkey_clause.has_col_list()) { + ret += "("; + ret += ColumnListToString(fkey_clause.col_list()); + ret += ")"; + } + ret += " "; + for (int i = 0; i < fkey_clause.fkey_cores_size(); i++) { + ret += ForeignKeyClauseCoreToString(fkey_clause.fkey_cores(i)); + ret += " "; + } + if (fkey_clause.has_defer_strat()) { + ret += DeferStrategyToString(fkey_clause.defer_strat()); + ret += " "; + } + return ret; +} + +CONV_FN(ConflictClause, conf) { + if (!conf.has_on_conflict()) + return " "; + + std::string ret("ON CONFLICT "); + ret += EnumStrReplaceUnderscores( + ConflictClause_OnConflict_Name(conf.on_conflict())); + ret += " "; + return ret; +} + +CONV_FN(ColConstraintOpt1, opt1) { + std::string ret("PRIMARY KEY "); + ret += AscDescToString(opt1.asc_desc()); + // space at the end already + ret += ConflictClauseToString(opt1.conflict()); + if (opt1.autoincrement()) + ret += "AUTOINCREMENT "; + + return ret; +} + +CONV_FN(ColConstraintOpt2, opt2) { + std::string ret("DEFAULT "); + if (opt2.has_expr()) { + ret += "("; + ret += ExprToString(opt2.expr()); + ret += ")"; + } else { + ret += LiteralValueToString(opt2.lit_val()); + } + + ret += " "; + return ret; +} + +CONV_FN(ColumnConstraint, col_constr) { + std::string ret; + if (col_constr.has_constraint_name()) { + ret += "CONSTRAINT "; + ret += ColumnConstraintNameToString(col_constr.constraint_name()); + ret += " "; + } + + using ColConstrType = ColumnConstraint::ColConstraintOneofCase; + switch (col_constr.col_constraint_oneof_case()) { + case ColConstrType::kOpt1: + ret += ColConstraintOpt1ToString(col_constr.opt1()); + break; + case ColConstrType::kNotNullConfClause: + ret += "NOT NULL "; + ret += ConflictClauseToString(col_constr.not_null_conf_clause()); + break; + case ColConstrType::kUniqueConfClause: + ret += "UNIQUE "; + ret += ConflictClauseToString(col_constr.unique_conf_clause()); + break; + case ColConstrType::kCheckExpr: + ret += "CHECK("; + ret += ExprToString(col_constr.check_expr()); + ret += ") "; + break; + case ColConstrType::kOpt2: + ret += ColConstraintOpt2ToString(col_constr.opt2()); + break; + case ColConstrType::kCollate: + ret += "COLLATE "; + ret += CollateTypeToString(col_constr.collate()); + ret += " "; + break; + case ColConstrType::kFkeyClause: + ret += ForeignKeyClauseToString(col_constr.fkey_clause()); + break; + default: + ret += ColConstraintOpt2ToString(col_constr.opt2_fallback()); + } + + return ret; +} + +CONV_FN(TypeName, type_name) { + std::string ret; + ret += EnumStrReplaceUnderscores( + CastTypeName_CastTypeNameEnum_Name(type_name.ctn().type_enum())); + if (type_name.has_sn()) { + ret += "("; + ret += std::to_string(type_name.sn()); + ret += ")"; + } + ret += " "; + return ret; +} + +CONV_FN(ColumnDef, col_def) { + std::string ret; + ret += ColumnToString(col_def.col()); + ret += " "; + if (col_def.has_type_name()) { + ret += TypeNameToString(col_def.type_name()); + ret += " "; + } + + for (int i = 0; i < col_def.col_constraints_size(); i++) { + ret += ColumnConstraintToString(col_def.col_constraints(i)); + ret += " "; + } + + return ret; +} + +CONV_FN(TableConstraintOpt1, opt1) { + std::string ret; + ret += EnumStrReplaceUnderscores( + TableConstraintOpt1_ConstraintType_Name(opt1.constraint_type())); + ret += "("; + ret += IndexedColumnListToString(opt1.indexed_col_list()); + ret += ") "; + ret += ConflictClauseToString(opt1.conf_clause()); + + return ret; +} + +CONV_FN(TableConstraintOpt2, opt2) { + std::string ret("FOREIGN KEY ("); + ret += ColumnListToString(opt2.cols()); + ret += ") "; + + ret += ForeignKeyClauseToString(opt2.fkey_clause()); + return ret; +} + +CONV_FN(TableConstraint, t_constr) { + std::string ret; + if (t_constr.has_name()) { + ret += "CONSTRAINT "; + ret += TableConstraintNameToString(t_constr.name()); + ret += " "; + } + + if (t_constr.has_opt1()) { + ret += TableConstraintOpt1ToString(t_constr.opt1()); + } else if (t_constr.has_check_expr()) { + ret += "CHECK("; + ret += ExprToString(t_constr.check_expr()); // TODO(mpdenton) + ret += ") "; + } else if (t_constr.has_opt2()) { + ret += TableConstraintOpt2ToString(t_constr.opt2()); + } else { + // default to no constraint + ret += "CHECK(1)"; + } + + ret += " "; + return ret; +} + +CONV_FN(CreateTableOpt1, opt1) { + std::string ret("("); + ret += ColumnDefToString(opt1.col_def()); + for (int i = 0; i < opt1.extra_col_defs_size(); i++) { + ret += ", "; + ret += ColumnDefToString(opt1.extra_col_defs(i)); + } + for (int i = 0; i < opt1.table_constraints_size(); i++) { + ret += ", "; + ret += TableConstraintToString(opt1.table_constraints(i)); + } + ret += ") "; + + if (opt1.without_rowid()) + ret += "WITHOUT ROWID "; + + return ret; +} + +CONV_FN(CreateTable, create_table) { +#if defined(FUZZ_FTS3) + return ""; // Don't create normal tables in FTS3 fuzzing mode. +#endif + std::string ret("CREATE "); + if (create_table.has_temp_modifier()) { + ret += EnumStrReplaceUnderscores( + TempModifier_Name(create_table.temp_modifier())) + .erase(0, std::string("TM_").length()); + ret += " "; + } + ret += "TABLE "; + if (create_table.if_not_exists()) + ret += "IF NOT EXISTS "; + + ret += ExprSchemaTableToString(create_table.schema_table()); + ret += " "; + + // TODO(mpdenton) need spaces at the end here??? + using TableCreationType = CreateTable::CreateTableOneofCase; + switch (create_table.create_table_oneof_case()) { + case TableCreationType::kOp1: + ret += CreateTableOpt1ToString(create_table.op1()); + break; + case TableCreationType::kAsSelectStmt: + ret += SelectToString(create_table.as_select_stmt()); + break; + default: + ret += CreateTableOpt1ToString(create_table.op()); + break; + } + + return ret; // TODO(mpdenton) +} + +// ~~~~For INSERT and SELECT~~~~ + +CONV_FN(CommonTableExpr, cte) { + std::string ret; + ret += TableToString(cte.table()); + if (cte.columns_size() > 0) { + ret += "("; + ret += ColumnToString(cte.columns(0)); + for (int i = 1; i < cte.columns_size(); i++) { + ret += ", "; + ret += ColumnToString(cte.columns(i)); + } + ret += ")"; + } + ret += " AS ("; + ret += SelectToString(cte.select()); + ret += ") "; + return ret; +} + +CONV_FN(WithStatement, ws) { + std::string ret("WITH "); + if (ws.recursive()) + ret += "RECURSIVE "; + ret += CommonTableExprToString(ws.table_expr()); + ret += " "; + for (int i = 0; i < ws.extra_table_exprs_size(); i++) { + ret += CommonTableExprToString(ws.extra_table_exprs(i)); + ret += " "; + } + ret += " "; + return ret; +} + +// ~~~~INSERT~~~~ + +// WARNING no space at end +CONV_FN(ColumnComparison, cc) { + std::string ret; + ret += ExprSchemaTableColumnToString(cc.col()); + ret += BinaryOperatorToString(cc.op()); +#if defined(FUZZ_FTS3) + if (cc.op() == BINOP_MATCH && cc.has_fmt()) { + ret += FTS3MatchFormatToString(cc.fmt()); + return ret; + } +#endif + ret += ExprToString(cc.expr()); + return ret; +} + +// WARNING no space at end +CONV_FN(ExprComparisonHighProbability, echp) { + if (echp.has_cc()) { + return ColumnComparisonToString(echp.cc()); + } else if (echp.has_expr()) { + return ExprToString(echp.expr()); + } else { + return "Col0 = 1"; // default + } +} + +CONV_FN(WhereStatement, ws) { + return "WHERE " + ExprComparisonHighProbabilityToString(ws.expr()) + " "; +} + +#ifndef SQLITE_OMIT_UPSERT +CONV_FN(UpsertClausePart1, uc1) { + std::string ret; + ret += "("; + ret += IndexedColumnListToString(uc1.icol_list()); + ret += ") "; + if (uc1.has_where_stmt()) { + ret += WhereStatementToString(uc1.where_stmt()); + ret += " "; + } + return ret; +} +#endif + +// WARNING no space at end +CONV_FN(ColEqualsExpr, cee) { + std::string ret; + if (cee.has_col()) { + ret += ColumnToString(cee.col()); + } else if (cee.has_col_list()) { + ret += ColumnListToString(cee.col_list()); + } else { + ret += "Col0"; // default + } + ret += " = "; + ret += ExprToString(cee.expr()); + return ret; +} + +CONV_FN(UpsertClausePart2, uc2) { + std::string ret("SET "); + ret += ColEqualsExprToString(uc2.cee()); + for (int i = 0; i < uc2.extra_cees_size(); i++) { + ret += ", "; + ret += ColEqualsExprToString(uc2.extra_cees(i)); + } + if (uc2.has_where_stmt()) { + ret += " "; + ret += WhereStatementToString(uc2.where_stmt()); + } + ret += " "; + return ret; +} + +CONV_FN(UpsertClause, uc) { +#ifndef SQLITE_OMIT_UPSERT + std::string ret("ON CONFLICT "); + if (uc.has_uclause_p1()) { + ret += UpsertClausePart1ToString(uc.uclause_p1()); + } + ret += "DO "; + if (uc.has_uclause_p2()) { + ret += "UPDATE "; + ret += UpsertClausePart2ToString(uc.uclause_p2()); + } else { + ret += "NOTHING "; + } + return ret; +#else + return ""; // fine to return empty string here +#endif +} + +CONV_FN(ValuesStatement, values) { + std::string ret("VALUES ("); + ret += ExprListToString(values.expr_list()); + ret += ")"; + for (int i = 0; i < values.extra_expr_lists_size(); i++) { + ret += ", ("; + ret += ExprListToString(values.extra_expr_lists(i)); + ret += ")"; + } + ret += " "; + return ret; +} + +CONV_FN(Insert, insert) { + std::string ret; + if (insert.has_with()) { + ret += WithStatementToString(insert.with()); + ret += " "; + } + + ret += + EnumStrReplaceUnderscores(Insert_InsertType_Name(insert.insert_type())); + ret += " INTO "; + ret += SchemaTableAsAliasToString(insert.staa()); + + if (insert.has_col_list()) { + ret += "("; + ret += ColumnListToString(insert.col_list()); + ret += ") "; + } + + // oneof + if (insert.has_values()) { + ret += ValuesStatementToString(insert.values()); + ret += " "; + } else if (insert.has_select()) { + ret += SelectToString(insert.select()); + ret += " "; + } else { + ret += "DEFAULT VALUES "; + } + + if (insert.has_upsert_clause()) { + ret += UpsertClauseToString(insert.upsert_clause()); + ret += " "; + } + return ret; +} + +// ~~~~DELETE~~~~ + +CONV_FN(QualifiedTableName, qtn) { + std::string ret; + ret += SchemaTableAsAliasToString(qtn.staa()); + ret += " "; + if (qtn.indexed()) { + if (qtn.not_indexed()) { + ret += "NOT INDEXED "; + } else { + ret += "INDEXED BY "; + ret += IndexToString(qtn.indexed_by()); + ret += " "; + } + } + return ret; +} + +CONV_FN(Delete, delete_) { + std::string ret; + if (delete_.has_with()) { + ret += WithStatementToString(delete_.with()); + ret += " "; + } + ret += "DELETE FROM "; + ret += QualifiedTableNameToString(delete_.qtn()); + if (delete_.has_where()) { + ret += WhereStatementToString(delete_.where()); + } + ret += " "; + return ret; +} + +// ~~~~UPDATE~~~~ +// WARNING no space at end +CONV_FN(Update, update) { + std::string ret; + if (update.has_with()) { + ret += WithStatementToString(update.with()); + ret += " "; + } + ret += "UPDATE "; + if (update.has_update_type()) { + ret += + EnumStrReplaceUnderscores(Update_UpdateType_Name(update.update_type())); + ret += " "; + } + ret += QualifiedTableNameToString(update.qtn()); + ret += " SET "; + ret += UpsertClausePart2ToString(update.ucp2()); + return ret; +} +// TODO(mpdenton) restrictions on UPDATEs in CREATE TRIGGER???? + +// ~~~~SELECT~~~~ + +CONV_FN(ExprColAlias, eca) { + std::string ret; + ret += ExprToString(eca.expr()); + ret += " "; + if (eca.has_col_alias()) { + if (eca.as()) { + ret += "AS "; + } + ret += ColumnToString(eca.col_alias()); + ret += " "; + } + return ret; +} + +// WARNING no space at end +CONV_FN(ResultColumn, rc) { + std::string ret; + // oneof + if (rc.has_col()) { + return ColumnToString(rc.col()); + } else if (rc.has_eca()) { + return ExprColAliasToString(rc.eca()); + } else if (rc.has_table_star()) { + return TableToString(rc.table_star()) + ".*"; + } else if (rc.has_fts3_fn()) { +#if defined(FUZZ_FTS3) + return FTS3AuxiliaryFnToString(rc.fts3_fn()); +#else + return "*"; +#endif + } else { + return "*"; + } +} + +CONV_FN(AsTableAlias, ata) { + std::string ret; + if (ata.as()) { + ret += "AS "; + } + ret += TableToString(ata.table_alias()); + ret += " "; + return ret; +} + +// WARNING no space at end +CONV_FN(JoinOperator, jo) { + if (jo.comma()) + return ","; + + std::string ret; + if (jo.natural()) + ret += "NATURAL "; + + if (jo.join_type() != JoinOperator::NONE) { + ret += + EnumStrReplaceUnderscores(JoinOperator_JoinType_Name(jo.join_type())); + } + ret += "JOIN "; + return ret; +} + +CONV_FN(JoinConstraint, jc) { + // oneof + if (jc.has_on_expr()) { + return "ON " + ExprToString(jc.on_expr()) + " "; + } else if (jc.has_using_expr()) { + std::string ret("("); + ret += ColumnListToString(jc.using_expr().col_list()); + ret += ") "; + return ret; + } + return " "; +} + +CONV_FN(JoinClauseCore, jcc) { + std::string ret; + ret += JoinOperatorToString(jcc.join_op()); + ret += " "; + ret += TableOrSubqueryToString(jcc.tos()); + ret += " "; + ret += JoinConstraintToString(jcc.join_constraint()); + ret += " "; + return ret; +} + +CONV_FN(JoinClause, jc) { + std::string ret; + ret += TableOrSubqueryToString(jc.tos()); + ret += " "; + for (int i = 1; i < jc.clauses_size(); i++) { + ret += JoinClauseCoreToString(jc.clauses(i)); + } + ret += " "; + return ret; +} + +// TODO(mpdenton) ExprIn needs it schematablefn!!!!! + +CONV_FN(ExprSchemaTableFn, estf) { + std::string ret; + const TableFn& tfn = estf.table_fn(); + // oneof for pragma fns + if (tfn.has_foreign_key_list()) { + ret += "pragma_foreign_key_list(\'"; + ret += TableToString(tfn.foreign_key_list()); + ret += "\') "; + } else if (tfn.has_index_info()) { + ret += "pragma_index_info(\'"; + ret += IndexToString(tfn.index_info()); + ret += "\') "; + } else if (tfn.has_index_list()) { + ret += "pragma_index_list(\'"; + ret += TableToString(tfn.index_list()); + ret += "\') "; + } else if (tfn.has_index_xinfo()) { + ret += "pragma_index_xinfo(\'"; + ret += IndexToString(tfn.index_xinfo()); + ret += "\') "; + } else if (tfn.has_integrity_check()) { + ret += "pragma_integrity_check(\'"; + ret += std::to_string(tfn.integrity_check()); + ret += "\') "; + } else if (tfn.has_optimize()) { + ret += "pragma_optimize(\'"; + ret += std::to_string(tfn.optimize()); + ret += "\') "; + } else if (tfn.has_quick_check()) { + ret += "pragma_quick_check(\'"; + ret += std::to_string(tfn.quick_check()); + ret += "\') "; + } else if (tfn.has_table_info()) { + ret += "pragma_table_info(\'"; + ret += TableToString(tfn.table_info()); + ret += "\') "; + } else if (tfn.has_table_xinfo()) { + ret += "pragma_table_xinfo(\'"; + ret += TableToString(tfn.table_xinfo()); + ret += "\') "; + } else { + ret += StrToLower(PragmaFnZeroArgOneResult_Name(tfn.no_arg_one_result())) + .erase(0, std::string("PFN_ZO_").length()); + ret += "() "; + } + return ret; +} + +CONV_FN(TableOrSubqueryOption2, toso2) { + std::string ret; + ret += ExprSchemaTableFnToString(toso2.schema_table_fn()); + ret += " "; + if (toso2.has_as_table_alias()) { + ret += AsTableAliasToString(toso2.as_table_alias()); + } + return ret; +} + +CONV_FN(TableOrSubqueryOption3, tos3) { + std::string ret; + if (tos3.tos_list_size() > 0) { + ret += TableOrSubqueryToString(tos3.tos_list(0)); + for (int i = 1; i < tos3.tos_list_size(); i++) { + ret += ", "; + ret += TableOrSubqueryToString(tos3.tos_list(i)); + } + } else { + ret += JoinClauseToString(tos3.join_clause()); + } + return ret; +} + +CONV_FN(TableOrSubqueryOption4, tos4) { + std::string ret("("); + ret += SelectToString(tos4.select()); + ret += ") "; + if (tos4.has_as_table_alias()) { + ret += AsTableAliasToString(tos4.as_table_alias()); + ret += " "; + } + return ret; +} + +CONV_FN(TableOrSubquery, tos) { + // oneof + if (tos.has_qtn()) { + return QualifiedTableNameToString(tos.qtn()) + " "; + } else if (tos.has_toso2()) { + return TableOrSubqueryOption2ToString(tos.toso2()) + " "; + } else if (tos.has_toso3()) { + return "(" + TableOrSubqueryOption3ToString(tos.toso3()) + ") "; + } else if (tos.has_toso4()) { + return TableOrSubqueryOption4ToString(tos.toso4()) + " "; + } else { + return ExprSchemaTableToString(tos.schema_table_expr()) + " "; + } +} + +CONV_FN(FromStatement, fs) { + return TableOrSubqueryOption3ToString(fs.tos3()); +} + +CONV_FN(GroupByStatement, gbs) { + std::string ret("GROUP BY "); + ret += ExprListToString(gbs.exprs()); + ret += " "; + if (gbs.has_having_expr()) { + ret += "HAVING "; + ret += ExprToString(gbs.having_expr()); + ret += " "; + } + return ret; +} + +CONV_FN(WindowStatement, ws) { +#if !defined(SQLITE_OMIT_WINDOWFUNC) + return ""; +#else + return ""; +#endif +} + +CONV_FN(SelectStatementCore, ssc) { + std::string ret; + ret += EnumStrReplaceUnderscores( + SelectStatementCore_SelectOrDistinct_Name(ssc.s_or_d())); + ret += " "; + if (ssc.result_columns_size() == 0) { + ret += "* "; + } else { + ret += ResultColumnToString(ssc.result_columns(0)); + for (int i = 1; i < ssc.result_columns_size(); i++) { + ret += ", "; + ret += ResultColumnToString(ssc.result_columns(i)); + } + ret += " "; + } + if (ssc.has_from()) { + ret += FromStatementToString(ssc.from()); + ret += " "; + } + if (ssc.has_where()) { + ret += WhereStatementToString(ssc.where()); + ret += " "; + } + if (ssc.has_groupby()) { + ret += GroupByStatementToString(ssc.groupby()); + ret += " "; + } + if (ssc.has_window()) { + ret += WindowStatementToString(ssc.window()); + ret += " "; + } + return ret; +} + +CONV_FN(SelectSubStatement, sss) { + // oneof + if (sss.has_select_core()) { + return SelectStatementCoreToString(sss.select_core()); + } else if (sss.has_values()) { + return ValuesStatementToString(sss.values()); + } else { + return ValuesStatementToString(sss.values_fallback()); + } +} + +CONV_FN(ExprOrderingTerm, eot) { + std::string ret = ExprToString(eot.expr()); + ret += " "; + if (eot.has_collate_type()) { + ret += "COLLATE "; + ret += CollateTypeToString(eot.collate_type()); + ret += " "; + } + ret += AscDescToString(eot.asc_desc()); + return ret; +} + +CONV_FN(OrderByStatement, obs) { + std::string ret("ORDER BY "); + ret += ExprOrderingTermToString(obs.ord_term()); + for (int i = 0; i < obs.extra_ord_terms_size(); i++) { + ret += ", "; + ret += ExprOrderingTermToString(obs.extra_ord_terms(i)); + } + ret += " "; + return ret; +} + +CONV_FN(LimitStatement, ls) { + std::string ret("LIMIT "); + ret += ExprToString(ls.limit_expr()); + ret += " "; + if (ls.has_second_expr()) { + if (ls.offset()) { + ret += "OFFSET "; + } else { + ret += ", "; + } + ret += ExprToString(ls.second_expr()); + ret += " "; + } + return ret; +} + +CONV_FN(ExtraSelectSubStatement, esss) { + std::string ret, enum1; + enum1 = CompoundOperator_Name(esss.compound_op()); + // erase prefix + enum1.erase(0, std::string("CO_").length()); + ret += EnumStrReplaceUnderscores(enum1); + ret += " "; + ret += SelectSubStatementToString(esss.select_substatement()); + return ret; +} + +CONV_FN(Select, select) { + std::string ret; + if (select.has_with()) { + ret += WithStatementToString(select.with()); + ret += " "; + } + ret += SelectStatementCoreToString(select.select_core()); + for (int i = 0; i < select.extra_select_substatements_size(); i++) { + ret += + ExtraSelectSubStatementToString(select.extra_select_substatements(i)); + ret += " "; + } + if (select.has_orderby()) { + ret += OrderByStatementToString(select.orderby()); + ret += " "; + } + if (select.has_limit()) { + ret += LimitStatementToString(select.limit()); + } + return ret; +} + +// ~~~~FTS3~~~~ + +// CORPUS currently relying on normal SELECTs to generate good compound +// queries for FTS, like AND, OR, and NOT. Generate a corpus entry with a lot of +// creative FTS queries. + +CONV_FN(FTS3Table, ft) { + // std::string ret("FTS3Table"); + std::string ret( + "Table"); // for now, use the same naming scheme as normal tables. + ret += std::to_string(ft.table() % kMaxFTS3TableNumber); + return ret; +} + +CONV_FN(FTS3MatchToken, fmt) { + std::string ret; + if (fmt.has_col()) { + ret += ColumnToString(fmt.col()); + ret += ":"; + } + if (fmt.negate()) { + ret += "-"; + } + if (fmt.token().length() == 0) + ret += "a"; + else + ret += ConvertToSqlString( + fmt.token()); // TODO(mpdenton) good enough? Need something better???? + if (fmt.prefix()) + ret += "*"; + return ret; +} + +CONV_FN(FTS3PhraseQuery, fpq) { + std::string ret("\""); + ret += FTS3MatchTokenToString(fpq.mt()); + for (int i = 0; i < fpq.extra_mts_size(); i++) { + ret += " "; + ret += FTS3MatchTokenToString(fpq.extra_mts(i)); + } + ret += "\""; + return ret; +} + +CONV_FN(FTS3MatchFormatCore, fmfc) { + // oneof + if (fmfc.has_pq()) { + return FTS3PhraseQueryToString(fmfc.pq()); + } else if (fmfc.has_nq()) { + return FTS3NearQueryToString(fmfc.nq()); + } else { + return FTS3MatchTokenToString(fmfc.mt_fallback()); + } +} + +CONV_FN(FTS3NearQuery, fnq) { + std::string ret = FTS3MatchFormatCoreToString(fnq.format_core1()); + ret += " NEAR"; + if (fnq.has_num_tokens_near()) { + ret += "/"; + ret += std::to_string(fnq.num_tokens_near()); + } + ret += " "; + ret += FTS3MatchFormatCoreToString(fnq.format_core2()); + return ret; +} + +CONV_FN(FTS3CompoundAndCore, fcac) { + std::string ret(" "); + ret += FTS3CompoundAndCore_CompoundOp_Name(fcac.op()); + ret += " "; + ret += FTS3MatchFormatCoreToString(fcac.core()); + return ret; +} + +CONV_FN(FTS3MatchCompoundFormat, fmcf) { + std::string ret = FTS3MatchFormatCoreToString(fmcf.core()); + for (int i = 0; i < fmcf.compound_and_cores_size(); i++) { + ret += FTS3CompoundAndCoreToString(fmcf.compound_and_cores(i)); + } + return ret; +} + +CONV_FN(FTS3MatchFormat, fmf) { + std::string ret("\'"); + if (fmf.ft_size() > 0) { + ret += FTS3MatchCompoundFormatToString(fmf.ft(0)); + } + for (int i = 1; i < fmf.ft_size(); i++) { + ret += " "; + ret += FTS3MatchCompoundFormatToString(fmf.ft(i)); + } + ret += "\'"; + return ret; +} + +CONV_FN(FTS3SpecialCommand, fsc) { + std::string ret("INSERT INTO "); + ret += FTS3TableToString(fsc.table()); + ret += "("; + ret += FTS3TableToString(fsc.table()); + ret += ") VALUES(\'"; + switch (fsc.command()) { + case FTS3SpecialCommand::OPTIMIZE: + ret += "optimize"; + break; + case FTS3SpecialCommand::REBUILD: + ret += "rebuild"; + break; + case FTS3SpecialCommand::INTEGRITY_CHECK: + ret += "integrity-check"; + break; + case FTS3SpecialCommand::MERGE: + ret += "merge="; + ret += std::to_string(fsc.val1()); + ret += ","; + ret += std::to_string(fsc.val2()); + break; + case FTS3SpecialCommand::AUTOMERGE: + ret += "automerge="; + ret += std::to_string(fsc.val1() % 16); + break; + } + ret += "\')"; + return ret; +} + +// WARNING no space at end +CONV_FN(FTS3SelectMatch, fsm) { + std::string ret("SELECT * FROM "); + ret += FTS3TableToString(fsm.table()); + ret += " WHERE "; + ret += ColumnToString(fsm.col()); + ret += " MATCH "; + ret += FTS3MatchFormatToString(fsm.match_pattern()); + return ret; +} + +CONV_FN(FTS3SpecificQuery, fsq) { +#if defined(FUZZ_FTS3) + // oneof + if (fsq.has_command()) { + return FTS3SpecialCommandToString(fsq.command()); + } else if (fsq.has_select()) { + return FTS3SelectMatchToString(fsq.select()); + } else { + return ""; + } + +#else + return ""; +#endif +} + +CONV_FN(ICULocale, il) { + std::string ret; + std::string lc = IsoLangCode_Name(il.iso_lang_code()); + lc.erase(0, std::string("ISO_LANG_CODE_").length()); + ret += lc; + ret += "_"; + // extract country code from integer + ret += (char)((il.country_code() & 0xFF) % 26) + 'A'; + ret += (char)(((il.country_code() & 0xFF00) >> 8) % 26) + 'A'; + return ret; +} + +CONV_FN(CreateFTS3Table, cft) { + std::string ret("CREATE VIRTUAL TABLE "); + if (cft.if_not_exists()) + ret += "IF NOT EXISTS "; + if (cft.has_schema()) { + ret += SchemaToString(cft.schema()); + ret += "."; + } + ret += FTS3TableToString(cft.table()); + ret += " USING fts3("; + // TODO(mpdenton) not using schema here, should I??? + if (cft.has_col_list()) { + ret += ColumnListToString(cft.col_list()); + if (cft.has_tokenizer_type()) + ret += ", "; + } + if (cft.has_tokenizer_type()) { + ret += "tokenize="; + std::string tt = TokenizerType_Name(cft.tokenizer_type()); + tt.erase(0, std::string("TT_").length()); + tt = StrToLower(tt); +#if defined(SQLITE_DISABLE_FTS3_UNICODE) + if (tt == "unicode61") + tt = "porter"; +#endif + ret += tt; + // now generate locales for ICU + if (cft.tokenizer_type() == TokenizerType::TT_ICU) { + ret += " "; + ret += ICULocaleToString(cft.locale()); + } else if (cft.tokenizer_type() == TokenizerType::TT_UNICODE61) { + // Chrome does not actually enable this option. FIXME in the future. + } + } + ret += ")"; + return ret; +} + +// WARNING no space at end +CONV_FN(FTS3OffsetsFn, fof) { + return "offsets(" + FTS3TableToString(fof.table()) + ")"; +} + +// WARNING no space at end +CONV_FN(FTS3SnippetsFn, fsf) { + std::string ret("snippets("); + ret += FTS3TableToString(fsf.table()); + // Now (possibly) emit the five optional arguments. + int num_args = (int)fsf.num_optional_args(); + if (num_args >= 1) { + ret += ", \'"; + ret += ConvertToSqlString(fsf.start_match()); + ret += "\'"; + } + if (num_args >= 2) { + ret += ", \'"; + ret += ConvertToSqlString(fsf.end_match()); + ret += "\'"; + } + if (num_args >= 3) { + ret += ", \'"; + ret += ConvertToSqlString(fsf.ellipses()); + ret += "\'"; + } + if (num_args >= 4) { + ret += ", "; + if (fsf.has_col_number()) { + ret += std::to_string(fsf.col_number() % kMaxColumnNumber); + } else { + ret += "-1"; + } + } + if (num_args >= 5) { + ret += ", "; + ret += + std::to_string((fsf.num_tokens() % 129) - 64); // clamp into [-64, 64] + } + ret += ")"; + return ret; +} + +// WARNING no space at end +CONV_FN(FTS3MatchInfoFn, fmi) { + constexpr static char matchinfo_chars[] = { + 'p', 'c', 's', 'x', 'y', 'b', + // 'n', 'a', 'l', // These characters only available for FTS4. + }; + std::string ret("matchinfo("); + ret += FTS3TableToString(fmi.table()); + if (fmi.chars_size() > 0) { + ret += ", \'"; + for (int i = 0; i < fmi.chars_size(); i++) { + ret += matchinfo_chars[fmi.chars(i) % sizeof(matchinfo_chars)]; + } + ret += "\'"; + } + ret += ")"; + return ret; +} + +// WARNING no space at end +CONV_FN(FTS3AuxiliaryFn, faf) { + if (faf.has_snippets()) { + return FTS3SnippetsFnToString(faf.snippets()); + } else if (faf.has_matchinfo()) { + return FTS3MatchInfoFnToString(faf.matchinfo()); + } else { + return FTS3OffsetsFnToString(faf.offsets_fallback()); + } +} + +CONV_FN(FTS3HiddenTable, fht) { + std::string tab = FTS3HiddenTable_HiddenTableVal_Name(fht.htv()); + tab = StrToLower(tab); + return FTS3TableToString(fht.table()) + "_" + tab; +} + +CONV_FN(FTS3HiddenTableColumn, fhtc) { + std::string tab = FTS3HiddenTableColumn_Name(fhtc); + tab = tab.erase(0, std::string("FTS3_HT_").length()); + tab = StrToLower(tab); + return tab; +} + +CONV_FN(FTS3HiddenTableInsert, fi) { + std::string ret("INSERT INTO "); + ret += FTS3HiddenTableToString(fi.fht()); + if (fi.col_vals_size() == 0) { + ret += " DEFAULT VALUES"; + return ret; + } + ret += "("; + ret += FTS3HiddenTableColumnToString(fi.col_vals(0).col()); + for (int i = 1; i < fi.col_vals_size(); i++) { + ret += ", "; + ret += FTS3HiddenTableColumnToString(fi.col_vals(i).col()); + } + ret += ") VALUES("; + ret += ExprToString(fi.col_vals(0).expr()); + for (int i = 0; i < fi.col_vals_size(); i++) { + ret += ", "; + ret += ExprToString(fi.col_vals(i).expr()); + } + ret += ")"; + return ret; +} + +CONV_FN(FTS3HiddenTableUpdate, fu) { + std::string ret("UPDATE "); + ret += FTS3HiddenTableToString(fu.fht()); + ret += " "; + if (fu.col_vals_size() == 0) { + ret += "start_block = 0"; + return ret; + } + ret += "SET "; + ret += FTS3HiddenTableColumnToString(fu.col_vals(0).col()); + ret += " = "; + ret += ExprToString(fu.col_vals(0).expr()); + for (int i = 1; i < fu.col_vals_size(); i++) { + ret += ", "; + ret += FTS3HiddenTableColumnToString(fu.col_vals(i).col()); + ret += " = "; + ret += ExprToString(fu.col_vals(i).expr()); + } + if (fu.has_col_where()) { + ret += " WHERE "; + ret += FTS3HiddenTableColumnToString(fu.col_where()); + ret += BinaryOperatorToString(fu.bin_op()); + ret += ExprToString(fu.comp_expr()); + } + return ret; +} + +CONV_FN(FTS3HiddenTableDelete, fd) { + std::string ret("DELETE FROM "); + ret += FTS3HiddenTableToString(fd.fht()); + if (fd.has_col_where()) { + ret += " WHERE "; + ret += FTS3HiddenTableColumnToString(fd.col_where()); + ret += BinaryOperatorToString(fd.bin_op()); + ret += ExprToString(fd.comp_expr()); + } + return ret; +} + +// ~~~~TRANSACTIONS/SAVEPOINTS +CONV_FN(BeginTransaction, bt) { + std::string ret("BEGIN "); + if (bt.has_type()) { + ret += BeginTransaction_TransactionType_Name(bt.type()); + ret += " "; + } + ret += "TRANSACTION"; + return ret; +} + +CONV_FN(CommitTransaction, ct) { + return EnumStrReplaceUnderscores( + CommitTransaction_CommitText_Name(ct.text())); +} + +CONV_FN(RollbackStatement, rt) { +#if !defined(FUZZ_OMIT_SAVEPOINT) + if (rt.has_save_point()) { + return "ROLLBACK TO SAVEPOINT " + SavePointToString(rt.save_point()); + } +#endif + return "ROLLBACK TRANSACTION"; +} + +#if !defined(FUZZ_OMIT_SAVEPOINT) +CONV_FN(CreateSavePoint, csp) { + return "SAVEPOINT " + SavePointToString(csp.save_point()); +} + +CONV_FN(ReleaseSavePoint, rsp) { + return "RELEASE SAVEPOINT " + SavePointToString(rsp.save_point()); +} +#endif + +CONV_FN(Analyze, a) { + std::string ret("ANALYZE"); + if (a.has_schema_name()) { + ret += " "; + ret += SchemaToString(a.schema_name()); + if (a.has_table_name()) { + ret += "."; + ret += TableToString(a.table_name()); + } else if (a.has_index_name()) { + ret += "."; + ret += IndexToString(a.index_name()); + } + } else if (a.has_table_name()) { + ret += " "; + ret += TableToString(a.table_name()); + } else if (a.has_index_name()) { + ret += " "; + ret += IndexToString(a.index_name()); + } + + return ret; +} + +// ~~~~VACUUM~~~~ +CONV_FN(Vacuum, v) { + std::string ret("VACUUM"); + if (v.has_schema()) { + ret += " "; + ret += SchemaToString(v.schema()); + } + return ret; +} + +// ~~~~PRAGMA~~~~ +CONV_FN(Pragma, p) { +#if defined(FUZZ_OMIT_PRAGMA) + return ""; +#else + constexpr static const char* locking_modes[] = {"NORMAL", "EXCLUSIVE"}; + constexpr static const char* journal_modes[] = { + "DELETE", "TRUNCATE", "PERSIST", "MEMORY", "WAL", "OFF"}; + + Table table; + std::string ret("PRAGMA "); + if (p.has_schema()) { + ret += SchemaToString(p.schema()); + ret += "."; + } + ret += StripTrailingUnderscores( + StrToLower(Pragma_PragmaCommand_Name(p.command()))); + switch (p.command()) { + case Pragma::AUTO_VACUUM: + ret += " = "; + ret += std::to_string((uint32_t)p.arg1() % 3); + break; + case Pragma::WRITEABLE_SCHEMA: + ret += " = "; + ret += std::to_string((uint32_t)p.arg1() % 2); + break; + case Pragma::LOCKING_MODE: + ret += " = "; + ret += locking_modes[(uint32_t)p.arg1() % 2]; + break; + case Pragma::TEMP_STORE: + ret += " = "; + ret += std::to_string((uint32_t)p.arg1() % 3); + break; + case Pragma::PAGE_SIZE_: + ret += " = "; + ret += std::to_string(p.arg1()); + break; + case Pragma::TABLE_INFO: + ret += "(\'"; + table.set_table((uint32_t)p.arg1()); + ret += TableToString(table); + ret += "\')"; + break; + case Pragma::JOURNAL_MODE: + ret += " = "; + ret += journal_modes[(uint32_t)p.arg1() % 6]; + break; + case Pragma::MMAP_SIZE: + ret += " = "; + ret += std::to_string(p.arg1()); + break; + } + return ret; +#endif +} + +// ~~~~CREATE INDEX~~~~ +CONV_FN(CreateIndex, ci) { + std::string ret("CREATE "); + if (ci.unique()) + ret += "UNIQUE "; + ret += "INDEX "; + if (ci.if_not_exists()) + ret += "IF NOT EXISTS "; + if (ci.has_schema()) { + ret += SchemaToString(ci.schema()); + ret += "."; + } + ret += IndexToString(ci.index()); + ret += " ON "; + ret += TableToString(ci.table()); + ret += "("; + ret += IndexedColumnListToString(ci.icol_list()); + ret += ")"; + if (ci.has_where()) + ret += WhereStatementToString(ci.where()); + return ret; +} + +// ~~~~CREATE VIEW~~~~ +CONV_FN(CreateView, cv) { + std::string ret("CREATE "); + if (cv.has_temp_modifier()) { + ret += EnumStrReplaceUnderscores(TempModifier_Name(cv.temp_modifier())) + .erase(0, std::string("TM_").length()); + ret += " "; + } + ret += "VIEW "; + if (cv.if_not_exists()) + ret += "IF NOT EXISTS "; + + if (cv.has_schema()) { + ret += SchemaToString(cv.schema()); + ret += "."; + } + ret += ViewToString(cv.view()); + ret += " "; + if (cv.has_col_list()) { + ret += "("; + ret += ColumnListToString(cv.col_list()); + ret += ") "; + } + ret += SelectToString(cv.select()); + return ret; +} + +// ~~~~CREATE TRIGGER~~~~ + +CONV_FN(TypicalQuery, tq) { + // oneof + if (tq.has_update()) + return UpdateToString(tq.update()); + else if (tq.has_insert()) + return InsertToString(tq.insert()); + else if (tq.has_select()) + return SelectToString(tq.select()); + else + return DeleteToString(tq.delete_fallback()); +} + +// WARNING no space at end +CONV_FN(CreateTrigger, ct) { + std::string ret("CREATE "); + if (ct.has_temp_modifier()) { + ret += EnumStrReplaceUnderscores(TempModifier_Name(ct.temp_modifier())) + .erase(0, std::string("TM_").length()); + ret += " "; + } + ret += "TRIGGER "; + if (ct.if_not_exists()) + ret += "IF NOT EXISTS "; + + if (ct.has_schema()) { + ret += SchemaToString(ct.schema()); + ret += " "; + } + + ret += TriggerToString(ct.trigger()); + ret += " "; + if (ct.has_trigger_type()) { + ret += EnumStrReplaceUnderscores( + CreateTrigger_TriggerType_Name(ct.trigger_type())); + ret += " "; + } + ret += CreateTrigger_TriggerInstr_Name(ct.trigger_instr()); + ret += " "; + if (ct.trigger_instr() == CreateTrigger::UPDATE) { + ret += "OF "; + ret += ColumnListToString(ct.col_list()); + ret += " "; + } + ret += "ON "; + ret += TableToString(ct.table()); + ret += " "; + if (ct.for_each_row()) + ret += "FOR EACH ROW "; + + if (ct.has_when()) { + ret += "WHEN "; + ret += ExprComparisonHighProbabilityToString(ct.when()); + ret += " "; + } + + ret += "BEGIN "; + ret += TypicalQueryToString(ct.tq()); + ret += "; "; + for (int i = 0; i < ct.extra_tqs_size(); i++) { + ret += TypicalQueryToString(ct.extra_tqs(i)); + ret += "; "; + } + ret += "END"; + return ret; +} + +// ~~~~REINDEX~~~~ +CONV_FN(ReIndex, ri) { +// Chrome doesn't use REINDEX +#if !defined(SQLITE_OMIT_REINDEX) + if (ri.empty()) + return "REINDEX"; + std::string ret("REINDEX "); + if (ri.has_collate_type()) { + ret += CollateTypeToString(ri.collate_type()); + return ret; + } + if (ri.has_schema()) { + ret += SchemaToString(ri.schema()); + ret += "."; + } + if (ri.has_table()) + ret += TableToString(ri.table()); + else + ret += IndexToString(ri.index()); + + return ret; +#else + return ""; +#endif +} + +CONV_FN(Drop, d) { + std::string ret("DROP "); + std::string if_exists(""); + std::string schema(""); + if (d.if_exists()) + if_exists = "IF EXISTS "; + if (d.has_schema()) { + schema = SchemaToString(d.schema()); + schema += " "; + } + // oneof + if (d.has_index()) { + ret += "INDEX "; + ret += if_exists; + ret += schema; + ret += IndexToString(d.index()); + } else if (d.has_index()) { + ret += "TABLE "; + ret += if_exists; + ret += schema; + ret += TableToString(d.table()); + } else if (d.has_index()) { + ret += "TRIGGER "; + ret += if_exists; + ret += schema; + ret += TriggerToString(d.trigger()); + } else { + ret += "VIEW "; + ret += if_exists; + ret += schema; + ret += ViewToString(d.view_fallback()); + } + return ret; +} + +// ~~~~ALTER TABLE~~~~ +CONV_FN(AlterTable, at) { + std::string ret("ALTER TABLE "); + ret += ExprSchemaTableToString(at.schema_table()); + if (at.has_col()) { + ret += "RENAME "; + if (at.column()) + ret += "COLUMN "; + ret += ColumnToString(at.col()); + ret += " TO "; + ret += ColumnToString(at.col_to()); + } else if (at.has_col_def()) { + ret += "ADD "; + if (at.column()) + ret += "COLUMN "; + ret += ColumnDefToString(at.col_def()); + } else { + ret += "RENAME TO "; + ret += TableToString(at.table_fallback()); + } + return ret; +} + +// ~~~~ATTACH DATABASE~~~~ +CONV_FN(AttachDatabase, ad) { + std::string ret("ATTACH DATABASE \'"); + if (ad.in_memory()) { + if (ad.file_uri()) { + ret += "file:"; + std::string add; + if (ad.has_db_name()) { + ret += SchemaToString(ad.db_name()); + ret += "?mode=memory"; + add = "&"; + } else { + ret += ":memory:"; + add = "?"; + } + + if (ad.shared_cache()) { + ret += add; + ret += "cache=shared"; + } + } + } + ret += "\' AS "; + ret += SchemaToString(ad.schema()); + return ret; +} + +// ~~~~DETACH DATABASE~~~~ +CONV_FN(DetachDatabase, dd) { + std::string ret("DETACH DATABASE "); + ret += SchemaToString(dd.schema()); + return ret; +} + +// ~~~~Time and date fns~~~~ +CONV_FN(HoursStuff, hs) { + std::string ret; + if (hs.has_hh()) { + ret += std::to_string(hs.hh() % 100); + if (hs.has_mm()) { + ret += ":"; + ret += std::to_string(hs.mm() % 100); + if (hs.has_ss()) { + ret += ":"; + ret += std::to_string(hs.ss() % 100); + if (hs.has_sss()) { + ret += "."; + ret += std::to_string(hs.sss() % 1000); + } + } + } + } + return ret; +} + +CONV_FN(TimeString, ts) { + std::string ret; + if (ts.has_yyyy()) { + // FIXME in the future add zeroes for integers < 1000. + ret += std::to_string(ts.yyyy() % 10000); + ret += "-"; + ret += std::to_string(ts.mm() % 100); + ret += "-"; + ret += std::to_string(ts.dd() % 100); + if (ts.extra_t()) + ret += "T"; + if (ts.has_hs()) + ret += HoursStuffToString(ts.hs()); + } else if (ts.has_hs()) { + ret += HoursStuffToString(ts.hs()); + } else if (ts.has_dddddddddd()) { + ret += std::to_string(ts.dddddddddd() % 10000000000); + } else if (ts.now()) { + ret += "now"; + } else { + ret += ConvertToSqlString(ts.random_bytes()); + } + + if (ts.has_tz_plus()) { + if (ts.z()) { + ret += "Z"; + } else { + if (ts.plus()) + ret += "+"; + else + ret += "-"; + ret += std::to_string(ts.tz_hh() % 100); + ret += std::to_string(ts.tz_mm() % 100); + } + } + return ret; +} + +CONV_FN(TimeModifier, tm) { + std::string ret; + if (tm.has_nm()) { + ret += std::to_string(tm.num()); + ret += " "; + if (tm.has_dot_num()) { + ret += "."; + ret += std::to_string(tm.dot_num()); + } + ret += StrToLower(TimeModifier_NumberedModifiers_Name(tm.nm())); + } else { + ret += StrToLower( + EnumStrReplaceUnderscores(TimeModifier_OtherModifiers_Name(tm.om()))); + } + if (tm.om() == TimeModifier::WEEKDAY) { + ret += " "; + ret += std::to_string(tm.num()); + } + return ret; +} + +CONV_FN(SimpleDateAndTimeFn, sfn) { + std::string ret; + ret += StrToLower(SimpleDateAndTimeFn_FnName_Name(sfn.fn_name())); + ret += "(\'"; + ret += TimeStringToString(sfn.time_string()); + ret += "\'"; + for (int i = 0; i < sfn.modifiers_size(); i++) { + ret += ", \'"; + ret += TimeModifierToString(sfn.modifiers(i)); + ret += "\'"; + } + ret += ") "; + return ret; +} + +CONV_FN(StrftimeFormat, sf) { + std::string ret; + if (sf.has_subs()) { + std::string subs = StrftimeFormat_Substitution_Name(sf.subs()); + if (sf.lowercase()) + subs = StrToLower(subs); + ret += "%" + subs; + } else { + ret += "%%"; + } + + ret += ConvertToSqlString(sf.bytes()); + return ret; +} + +CONV_FN(StrftimeFn, sfn) { + std::string ret("strftime(\'"); + for (int i = 0; i < sfn.fmts_size(); i++) { + ret += StrftimeFormatToString(sfn.fmts(i)); + } + ret += "\', \'"; + ret += TimeStringToString(sfn.time_string()); + ret += "\'"; + for (int i = 0; i < sfn.modifiers_size(); i++) { + ret += ", \'"; + ret += TimeModifierToString(sfn.modifiers(i)); + ret += "\'"; + } + ret += ") "; + return ret; +} + +CONV_FN(DateAndTimeFn, dat) { + if (dat.has_simple()) + return SimpleDateAndTimeFnToString(dat.simple()); + else + return StrftimeFnToString(dat.strftime()); +} + +// ~~~~QUERY~~~~ +CONV_FN(SQLQuery, query) { + using QueryType = SQLQuery::QueryOneofCase; + switch (query.query_oneof_case()) { + case QueryType::kSelect: + return SelectToString(query.select()); + case QueryType::kCreateTable: + return CreateTableToString(query.create_table()); + case QueryType::kInsert: + return InsertToString(query.insert()); + case QueryType::kDelete: + return DeleteToString(query.delete_()); + case QueryType::kFts3Table: + return CreateFTS3TableToString(query.fts3_table()); + case QueryType::kFtsQuery: + return FTS3SpecificQueryToString(query.fts_query()); + case QueryType::kBeginTxn: + return BeginTransactionToString(query.begin_txn()); + case QueryType::kCommitTxn: + return CommitTransactionToString(query.commit_txn()); + case QueryType::kRollbackStmt: + return RollbackStatementToString(query.rollback_stmt()); +#if !defined(FUZZ_OMIT_SAVEPOINT) + case QueryType::kCreateSavePoint: + return CreateSavePointToString(query.create_save_point()); + case QueryType::kReleaseSavePoint: + return ReleaseSavePointToString(query.release_save_point()); +#endif + case QueryType::kAnalyze: + return AnalyzeToString(query.analyze()); + case QueryType::kVacuum: + return VacuumToString(query.vacuum()); + case QueryType::kPragma: + return PragmaToString(query.pragma()); + case QueryType::kUpdate: + return UpdateToString(query.update()); + case QueryType::kCreateIndex: + return CreateIndexToString(query.create_index()); + case QueryType::kCreateView: + return CreateViewToString(query.create_view()); + case QueryType::kCreateTrigger: + return CreateTriggerToString(query.create_trigger()); + case QueryType::kReindex: + return ReIndexToString(query.reindex()); + case QueryType::kDrop: + return DropToString(query.drop()); + case QueryType::kAlterTable: + return AlterTableToString(query.alter_table()); + case QueryType::kAttachDb: + return AttachDatabaseToString(query.attach_db()); + case QueryType::kDetachDb: + return DetachDatabaseToString(query.detach_db()); +#if defined(FUZZ_FTS3) + case QueryType::kFts3Insert: + return FTS3HiddenTableInsertToString(query.fts3_insert()); + case QueryType::kFts3Update: + return FTS3HiddenTableUpdateToString(query.fts3_update()); + case QueryType::kFts3Delete: + return FTS3HiddenTableDeleteToString(query.fts3_delete()); +#endif + default: + return ""; + } +} + +std::vector<std::string> SQLQueriesToVec(const SQLQueries& sql_queries) { + std::vector<std::string> queries; + queries.reserve(sql_queries.extra_queries_size() + 1); + queries.push_back(CreateTableToString(sql_queries.create_table()) + ";"); + for (int i = 0; i < sql_queries.extra_queries_size(); i++) { + std::string query = SQLQueryToString(sql_queries.extra_queries(i)); + if (query == "") + continue; + query += ";"; + queries.push_back(query); + } + return queries; +} + +CONV_FN(SQLQueries, sql_queries) { + std::string queries; + + for (std::string& query : SQLQueriesToVec(sql_queries)) { + queries += query; + queries += "\n"; + } + + return queries; +} + +} // namespace sql_fuzzer
diff --git a/third_party/sqlite/fuzz/sql_query_proto_to_string.h b/third_party/sqlite/fuzz/sql_query_proto_to_string.h new file mode 100644 index 0000000..237f628 --- /dev/null +++ b/third_party/sqlite/fuzz/sql_query_proto_to_string.h
@@ -0,0 +1,26 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef THIRD_PARTY_SQLITE_FUZZ_SQL_QUERY_PROTO_TO_STRING_H_ +#define THIRD_PARTY_SQLITE_FUZZ_SQL_QUERY_PROTO_TO_STRING_H_ + +#include <string> +#include <vector> + +#include "third_party/sqlite/fuzz/sql_queries.pb.h" + +namespace sql_fuzzer { + +std::string SQLQueriesToString( + const sql_query_grammar::SQLQueries& sql_queries); +std::vector<std::string> SQLQueriesToVec( + const sql_query_grammar::SQLQueries& sql_queries); + +std::string PrintfToString(const sql_query_grammar::Printf&); +std::string StrftimeFnToString(const sql_query_grammar::StrftimeFn&); +std::string ExprToString(const sql_query_grammar::Expr&); + +} // namespace sql_fuzzer + +#endif // THIRD_PARTY_SQLITE_FUZZ_SQL_QUERY_PROTO_TO_STRING_H_
diff --git a/third_party/sqlite/fuzz/sql_run_queries.cc b/third_party/sqlite/fuzz/sql_run_queries.cc new file mode 100644 index 0000000..6485c694 --- /dev/null +++ b/third_party/sqlite/fuzz/sql_run_queries.cc
@@ -0,0 +1,135 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Adapted from sqlite's ossfuzz.c + +#include <iostream> // TODO(mpdenton) remove +#include <string> +#include <vector> + +#include "third_party/sqlite/sqlite3.h" + +namespace sql_fuzzer { + +namespace { +int progress_handler(void*) { + return 1; +} +} // namespace + +void RunSqlQueriesOnSameDB() { + // TODO(mpdenton) unimplemented +} + +sqlite3* InitConnectionForFuzzing() { + int rc; // Return code from various interfaces. + sqlite3* db; // Sqlite db. + + rc = sqlite3_initialize(); + if (rc) { + std::cerr << "Failed initialization. " << std::endl; + return nullptr; + } + + // Open the database connection. Only use an in-memory database. + rc = sqlite3_open_v2( + "fuzz.db", &db, + SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE | SQLITE_OPEN_MEMORY, 0); + if (rc) { + std::cerr << "Failed to open DB. " << std::endl; + return nullptr; + } + +#ifndef SQLITE_OMIT_PROGRESS_CALLBACK + // Invoke the progress handler frequently to check to see if we + // are taking too long. The progress handler will return true + // (which will block further processing) if more than 10 seconds have + // elapsed since the start of the test. + sqlite3_progress_handler(db, 23, progress_handler, nullptr); +#endif + + // Enables foreign key constraints + sqlite3_db_config(db, SQLITE_DBCONFIG_ENABLE_FKEY, 1, &rc); + + // sqlite3_db_config(db, SQLITE_DBCONFIG_DEFENSIVE, 0, &rc); // TODO(pwnall) + + return db; +} + +void CloseConnection(sqlite3* db) { + // Cleanup and return. + sqlite3_exec(db, "PRAGMA temp_store_directory=''", 0, 0, 0); + sqlite3_close(db); +} + +void RunSqlQueriesOnConnection(sqlite3* db, std::vector<std::string> queries) { + int rc; + for (size_t i = 0; i < queries.size(); i++) { + // Run each query one by one. + // First, compile the query. + sqlite3_stmt* stmt; + const char* pzTail; + rc = sqlite3_prepare_v2(db, queries[i].c_str(), -1, &stmt, &pzTail); + if (rc != SQLITE_OK) { + if (getenv("PRINT_SQLITE_ERRORS")) { + std::cerr << "Could not compile: " << queries[i] << std::endl; + std::cerr << "Error message from db: " << sqlite3_errmsg(db) + << std::endl; + std::cerr << "-----------------------------" << std::endl; + } + continue; + } + + // No sqlite3_bind. + + // Now run the compiled query. + int col_cnt = sqlite3_column_count(stmt); + rc = SQLITE_ROW; + while (rc == SQLITE_ROW) { + rc = sqlite3_step(stmt); + if (rc != SQLITE_DONE && rc != SQLITE_ROW) { + if (getenv("PRINT_SQLITE_ERRORS")) { + std::cerr << "Step problem: " << queries[i] << std::endl; + std::cerr << "Error message from db: " << sqlite3_errmsg(db) + << std::endl; + std::cerr << "-----------------------------" << std::endl; + } + goto free_stmt; + } + // Loop through the columns to catch a little bit more coverage. + for (int i = 0; i < col_cnt; i++) { + switch (sqlite3_column_type(stmt, i)) { + case SQLITE_INTEGER: + sqlite3_column_int(stmt, i); + break; + case SQLITE_FLOAT: + sqlite3_column_double(stmt, i); + break; + case SQLITE_TEXT: + sqlite3_column_text(stmt, i); + break; + case SQLITE_BLOB: + sqlite3_column_blob(stmt, i); + break; + default: + break; + } + } + } + + // Finalize the query + free_stmt: + sqlite3_finalize(stmt); + } +} + +void RunSqlQueries(std::vector<std::string> queries) { + sqlite3* db = InitConnectionForFuzzing(); + + RunSqlQueriesOnConnection(db, queries); + + CloseConnection(db); +} + +} // namespace sql_fuzzer
diff --git a/third_party/sqlite/fuzz/sql_run_queries.h b/third_party/sqlite/fuzz/sql_run_queries.h new file mode 100644 index 0000000..ea5d481 --- /dev/null +++ b/third_party/sqlite/fuzz/sql_run_queries.h
@@ -0,0 +1,17 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include <string> +#include <vector> + +#include "third_party/sqlite/sqlite3.h" + +namespace sql_fuzzer { +/* Standalone function that wraps the three functions below. */ +void RunSqlQueries(std::vector<std::string> queries); + +sqlite3* InitConnectionForFuzzing(); +void RunSqlQueriesOnConnection(sqlite3* db, std::vector<std::string> queries); +void CloseConnection(sqlite3* db); +} // namespace sql_fuzzer
diff --git a/third_party/sqlite/fuzz/sql_strftime_fuzzer.cc b/third_party/sqlite/fuzz/sql_strftime_fuzzer.cc new file mode 100644 index 0000000..54ac6035 --- /dev/null +++ b/third_party/sqlite/fuzz/sql_strftime_fuzzer.cc
@@ -0,0 +1,30 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include <iostream> +#include <string> +#include <vector> + +#include "testing/libfuzzer/proto/lpm_interface.h" +#include "third_party/sqlite/fuzz/sql_query_grammar.pb.h" +#include "third_party/sqlite/fuzz/sql_query_proto_to_string.h" +#include "third_party/sqlite/fuzz/sql_run_queries.h" + +using namespace sql_query_grammar; + +DEFINE_BINARY_PROTO_FUZZER(const StrftimeFn& sql_strftime) { + std::string strftime_str = sql_fuzzer::StrftimeFnToString(sql_strftime); + // Convert printf command into runnable SQL query. + strftime_str = "SELECT " + strftime_str + ";"; + + if (getenv("LPM_DUMP_NATIVE_INPUT")) { + std::cout << "_________________________" << std::endl; + std::cout << strftime_str << std::endl; + std::cout << "------------------------" << std::endl; + } + + std::vector<std::string> queries; + queries.push_back(strftime_str); + sql_fuzzer::RunSqlQueries(queries); +}
diff --git a/third_party/unrar/README.chromium b/third_party/unrar/README.chromium index fa3b59a..a611355 100644 --- a/third_party/unrar/README.chromium +++ b/third_party/unrar/README.chromium
@@ -28,3 +28,5 @@ inside the unrar library code. This is done because the unrar library code operates inside a sandbox, so it doesn't have the permissions to open files. - Remove some static initializers. +- Pass a file handle to a temporary file with write permission, so the archive + can be extracted inside the sandbox for analysis.
diff --git a/third_party/unrar/patches/5.6.8.patch b/third_party/unrar/patches/5.6.8.patch index e1cc15e..ef9f127 100644 --- a/third_party/unrar/patches/5.6.8.patch +++ b/third_party/unrar/patches/5.6.8.patch
@@ -18,7 +18,7 @@ if (Format!=RARFMT14 && (CommHead.UnpVer < 15 || CommHead.UnpVer > VER_UNPACK || CommHead.Method > 0x35)) return false; diff --git a/third_party/unrar/src/archive.cpp b/third_party/unrar/src/archive.cpp -index f07ed05c1666..5630ad063aac 100644 +index f07ed05c1666..bb71254d5ff3 100644 --- a/third_party/unrar/src/archive.cpp +++ b/third_party/unrar/src/archive.cpp @@ -100,6 +100,7 @@ RARFORMAT Archive::IsSignature(const byte *D,size_t Size) @@ -46,6 +46,49 @@ if (StartFound) break; } +@@ -335,3 +337,12 @@ int64 Archive::Tell() + } + #endif + ++#if defined(CHROMIUM_UNRAR) ++void Archive::SetTempFileHandle(FileHandle hF) { ++ hTempFile = hF; ++} ++ ++FileHandle Archive::GetTempFileHandle() { ++ return hTempFile; ++} ++#endif +diff --git a/third_party/unrar/src/archive.hpp b/third_party/unrar/src/archive.hpp +index fd33ac359adb..a1f5e66569db 100644 +--- a/third_party/unrar/src/archive.hpp ++++ b/third_party/unrar/src/archive.hpp +@@ -58,6 +58,14 @@ class Archive:public File + QuickOpen QOpen; + bool ProhibitQOpen; + #endif ++#ifdef USE_ARCMEM ++ ArcMemory ArcMem; ++#endif ++ ++#if defined(CHROMIUM_UNRAR) ++ FileHandle hTempFile; ++#endif ++ + public: + Archive(RAROptions *InitCmd=NULL); + ~Archive(); +@@ -99,6 +107,10 @@ class Archive:public File + void QOpenUnload() {QOpen.Unload();} + void SetProhibitQOpen(bool Mode) {ProhibitQOpen=Mode;} + #endif ++#if defined(CHROMIUM_UNRAR) ++ void SetTempFileHandle(FileHandle hF); ++ FileHandle GetTempFileHandle(); ++#endif + + BaseBlock ShortBlock; + MarkHeader MarkHead; diff --git a/third_party/unrar/src/arcread.cpp b/third_party/unrar/src/arcread.cpp index c8cb1ee53aba..7eec01d7eb0f 100644 --- a/third_party/unrar/src/arcread.cpp @@ -510,7 +553,7 @@ diff --git a/third_party/unrar/src/extract.cpp b/third_party/unrar/src/extract.cpp -index 4540bd398452..f4835067514c 100644 +index 4540bd398452..3f4a2d442a7d 100644 --- a/third_party/unrar/src/extract.cpp +++ b/third_party/unrar/src/extract.cpp @@ -67,6 +67,7 @@ void CmdExtract::DoExtract() @@ -577,7 +620,17 @@ Arc.SeekToNext(); return true; } -@@ -573,6 +581,7 @@ bool CmdExtract::ExtractCurrentFile(Archive &Arc,size_t HeaderSize,bool &Repeat) +@@ -510,6 +518,9 @@ bool CmdExtract::ExtractCurrentFile(Archive &Arc,size_t HeaderSize,bool &Repeat) + #endif + + File CurFile; ++#if defined(CHROMIUM_UNRAR) ++ CurFile.SetFileHandle(Arc.GetTempFileHandle()); ++#endif + + bool LinkEntry=Arc.FileHead.RedirType!=FSREDIR_NONE; + if (LinkEntry && Arc.FileHead.RedirType!=FSREDIR_FILECOPY) +@@ -573,6 +584,7 @@ bool CmdExtract::ExtractCurrentFile(Archive &Arc,size_t HeaderSize,bool &Repeat) } FileCount++; if (Command!='I') @@ -585,7 +638,7 @@ if (SkipSolid) mprintf(St(MExtrSkipFile),ArcFileName); else -@@ -591,6 +600,7 @@ bool CmdExtract::ExtractCurrentFile(Archive &Arc,size_t HeaderSize,bool &Repeat) +@@ -591,6 +603,7 @@ bool CmdExtract::ExtractCurrentFile(Archive &Arc,size_t HeaderSize,bool &Repeat) mprintf(St(MExtrFile),DestFileName); break; } @@ -593,7 +646,7 @@ if (!Cmd->DisablePercentage) mprintf(L" "); -@@ -634,10 +644,12 @@ bool CmdExtract::ExtractCurrentFile(Archive &Arc,size_t HeaderSize,bool &Repeat) +@@ -634,10 +647,12 @@ bool CmdExtract::ExtractCurrentFile(Archive &Arc,size_t HeaderSize,bool &Repeat) wchar NameExisting[NM]; ExtrPrepareName(Arc,Arc.FileHead.RedirName,NameExisting,ASIZE(NameExisting)); if (FileCreateMode && *NameExisting!=0) // *NameExisting can be 0 in case of excessive -ap switch. @@ -606,7 +659,7 @@ } else if (Type==FSREDIR_UNIXSYMLINK || Type==FSREDIR_WINSYMLINK || Type==FSREDIR_JUNCTION) -@@ -651,7 +663,7 @@ bool CmdExtract::ExtractCurrentFile(Archive &Arc,size_t HeaderSize,bool &Repeat) +@@ -651,7 +666,7 @@ bool CmdExtract::ExtractCurrentFile(Archive &Arc,size_t HeaderSize,bool &Repeat) LinkSuccess=false; } @@ -615,7 +668,7 @@ { // RAR 5.x links have a valid data checksum even in case of // failure, because they do not store any data. -@@ -664,6 +676,7 @@ bool CmdExtract::ExtractCurrentFile(Archive &Arc,size_t HeaderSize,bool &Repeat) +@@ -664,6 +679,7 @@ bool CmdExtract::ExtractCurrentFile(Archive &Arc,size_t HeaderSize,bool &Repeat) } else if (!Arc.FileHead.SplitBefore) @@ -623,7 +676,7 @@ if (Arc.FileHead.Method==0) UnstoreFile(DataIO,Arc.FileHead.UnpSize); else -@@ -677,6 +690,7 @@ bool CmdExtract::ExtractCurrentFile(Archive &Arc,size_t HeaderSize,bool &Repeat) +@@ -677,6 +693,7 @@ bool CmdExtract::ExtractCurrentFile(Archive &Arc,size_t HeaderSize,bool &Repeat) #endif Unp->DoUnpack(Arc.FileHead.UnpVer,Arc.FileHead.Solid); } @@ -631,7 +684,7 @@ Arc.SeekToNext(); -@@ -731,7 +745,7 @@ bool CmdExtract::ExtractCurrentFile(Archive &Arc,size_t HeaderSize,bool &Repeat) +@@ -731,7 +748,7 @@ bool CmdExtract::ExtractCurrentFile(Archive &Arc,size_t HeaderSize,bool &Repeat) mprintf(L"\b\b\b\b\b "); if (!TestMode && (Command=='X' || Command=='E') && @@ -640,7 +693,7 @@ (!BrokenFile || Cmd->KeepBroken)) { // We could preallocate more space that really written to broken file. -@@ -774,11 +788,13 @@ bool CmdExtract::ExtractCurrentFile(Archive &Arc,size_t HeaderSize,bool &Repeat) +@@ -774,11 +791,13 @@ bool CmdExtract::ExtractCurrentFile(Archive &Arc,size_t HeaderSize,bool &Repeat) if (DataIO.NextVolumeMissing) return false; if (!ExtrFile) @@ -655,7 +708,7 @@ } diff --git a/third_party/unrar/src/file.cpp b/third_party/unrar/src/file.cpp -index e2bb42a616ad..5188dbff715c 100644 +index e2bb42a616ad..b69a3122427b 100644 --- a/third_party/unrar/src/file.cpp +++ b/third_party/unrar/src/file.cpp @@ -23,10 +23,12 @@ File::File() @@ -709,7 +762,27 @@ #ifdef LOCK_EX #ifdef _OSF_SOURCE -@@ -228,6 +244,8 @@ bool File::Close() +@@ -157,6 +173,11 @@ bool File::WOpen(const wchar *Name) + + bool File::Create(const wchar *Name,uint Mode) + { ++#if defined(CHROMIUM_UNRAR) ++ // Since the Chromium sandbox does not allow the creation of files, use the ++ // provided file. ++ hFile = hOpenFile; ++#else + // OpenIndiana based NAS and CIFS shares fail to set the file time if file + // was created in read+write mode and some data was written and not flushed + // before SetFileTime call. So we should use the write only mode if we plan +@@ -193,6 +214,7 @@ bool File::Create(const wchar *Name,uint Mode) + #else + hFile=fopen(NameA,WriteMode ? WRITEBINARY:CREATEBINARY); + #endif ++#endif + #endif + NewFile=true; + HandleType=FILE_HANDLENORMAL; +@@ -228,6 +250,8 @@ bool File::Close() { if (!SkipClose) { @@ -718,7 +791,7 @@ #ifdef _WIN_ALL // We use the standard system handle for stdout in Windows // and it must not be closed here. -@@ -240,6 +258,7 @@ bool File::Close() +@@ -240,6 +264,7 @@ bool File::Close() Success=fclose(hFile)!=EOF; #endif #endif @@ -726,7 +799,7 @@ } hFile=FILE_BAD_HANDLE; } -@@ -367,6 +386,7 @@ int File::Read(void *Data,size_t Size) +@@ -367,6 +392,7 @@ int File::Read(void *Data,size_t Size) { ErrorType=FILE_READERROR; if (AllowExceptions) @@ -734,7 +807,7 @@ if (IgnoreReadErrors) { ReadSize=0; -@@ -384,6 +404,7 @@ int File::Read(void *Data,size_t Size) +@@ -384,6 +410,7 @@ int File::Read(void *Data,size_t Size) continue; ErrHandler.ReadError(FileName); } @@ -742,7 +815,7 @@ } break; } -@@ -499,18 +520,22 @@ bool File::RawSeek(int64 Offset,int Method) +@@ -499,18 +526,22 @@ bool File::RawSeek(int64 Offset,int Method) int64 File::Tell() { if (hFile==FILE_BAD_HANDLE) @@ -765,7 +838,7 @@ return INT32TO64(HighDist,LowDist); #else #ifdef FILE_USE_OPEN -@@ -727,3 +752,9 @@ int64 File::Copy(File &Dest,int64 Length) +@@ -727,3 +758,9 @@ int64 File::Copy(File &Dest,int64 Length) return CopySize; } #endif @@ -1848,10 +1921,10 @@ break; diff --git a/third_party/unrar/src/unrar_wrapper.h b/third_party/unrar/src/unrar_wrapper.h new file mode 100644 -index 000000000000..b19759da6f6e +index 000000000000..0b92964fa08e --- /dev/null +++ b/third_party/unrar/src/unrar_wrapper.h -@@ -0,0 +1,15 @@ +@@ -0,0 +1,20 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. @@ -1862,8 +1935,13 @@ +#include "rar.hpp" + +namespace third_party_unrar { ++ +using ::Archive; -+static const int kUnrarEndarcHead = ::HEAD_ENDARC; ++using ::CmdExtract; ++using ::CommandData; ++ ++static const int kUnrarEndarcHead = HEAD_ENDARC; ++static const int kUnrarFileHead = HEAD_FILE; +} // namespace third_party_unrar + +#endif // THIRD_PARTY_UNRAR_SRC_UNRAR_WRAPPER_H_
diff --git a/third_party/unrar/src/archive.cpp b/third_party/unrar/src/archive.cpp index 5630ad06..bb71254d 100644 --- a/third_party/unrar/src/archive.cpp +++ b/third_party/unrar/src/archive.cpp
@@ -337,3 +337,12 @@ } #endif +#if defined(CHROMIUM_UNRAR) +void Archive::SetTempFileHandle(FileHandle hF) { + hTempFile = hF; +} + +FileHandle Archive::GetTempFileHandle() { + return hTempFile; +} +#endif
diff --git a/third_party/unrar/src/archive.hpp b/third_party/unrar/src/archive.hpp index fd33ac3..2084122f 100644 --- a/third_party/unrar/src/archive.hpp +++ b/third_party/unrar/src/archive.hpp
@@ -58,6 +58,13 @@ QuickOpen QOpen; bool ProhibitQOpen; #endif + +#if defined(CHROMIUM_UNRAR) + // A handle for a temporary file that should be used when extracting the + // archive. This is used to extract the contents while in a sandbox. + FileHandle hTempFile; +#endif + public: Archive(RAROptions *InitCmd=NULL); ~Archive(); @@ -99,6 +106,10 @@ void QOpenUnload() {QOpen.Unload();} void SetProhibitQOpen(bool Mode) {ProhibitQOpen=Mode;} #endif +#if defined(CHROMIUM_UNRAR) + void SetTempFileHandle(FileHandle hF); + FileHandle GetTempFileHandle(); +#endif BaseBlock ShortBlock; MarkHeader MarkHead;
diff --git a/third_party/unrar/src/extract.cpp b/third_party/unrar/src/extract.cpp index f4835067..6e13c18 100644 --- a/third_party/unrar/src/extract.cpp +++ b/third_party/unrar/src/extract.cpp
@@ -518,6 +518,11 @@ #endif File CurFile; +#if defined(CHROMIUM_UNRAR) + // Since extraction is done in a sandbox, this must extract to the temp file + // handle instead of the default. + CurFile.SetFileHandle(Arc.GetTempFileHandle()); +#endif bool LinkEntry=Arc.FileHead.RedirType!=FSREDIR_NONE; if (LinkEntry && Arc.FileHead.RedirType!=FSREDIR_FILECOPY)
diff --git a/third_party/unrar/src/file.cpp b/third_party/unrar/src/file.cpp index 5188dbf..d4b7b4a 100644 --- a/third_party/unrar/src/file.cpp +++ b/third_party/unrar/src/file.cpp
@@ -173,6 +173,11 @@ bool File::Create(const wchar *Name,uint Mode) { +#if defined(CHROMIUM_UNRAR) + // Since the Chromium sandbox does not allow the creation of files, use the + // provided file. + hFile = hOpenFile; +#else // OpenIndiana based NAS and CIFS shares fail to set the file time if file // was created in read+write mode and some data was written and not flushed // before SetFileTime call. So we should use the write only mode if we plan @@ -210,6 +215,7 @@ hFile=fopen(NameA,WriteMode ? WRITEBINARY:CREATEBINARY); #endif #endif +#endif // defined(CHROMIUM_UNRAR) NewFile=true; HandleType=FILE_HANDLENORMAL; SkipClose=false;
diff --git a/third_party/unrar/src/unrar_wrapper.h b/third_party/unrar/src/unrar_wrapper.h index b19759da..0b92964f 100644 --- a/third_party/unrar/src/unrar_wrapper.h +++ b/third_party/unrar/src/unrar_wrapper.h
@@ -8,8 +8,13 @@ #include "rar.hpp" namespace third_party_unrar { + using ::Archive; -static const int kUnrarEndarcHead = ::HEAD_ENDARC; +using ::CmdExtract; +using ::CommandData; + +static const int kUnrarEndarcHead = HEAD_ENDARC; +static const int kUnrarFileHead = HEAD_FILE; } // namespace third_party_unrar #endif // THIRD_PARTY_UNRAR_SRC_UNRAR_WRAPPER_H_
diff --git a/tools/android/roll/android_deps/build.gradle b/tools/android/roll/android_deps/build.gradle index 544ac68..24c14bd 100644 --- a/tools/android/roll/android_deps/build.gradle +++ b/tools/android/roll/android_deps/build.gradle
@@ -74,6 +74,10 @@ compile "com.squareup:javapoet:1.11.0" compile "com.google.protobuf:protobuf-lite:3.0.1" + + // ARCore - needed for WebXR implementation on Android + compile "com.google.ar:core:1.5.0" + } task setUpRepository(type: BuildConfigGenerator) {
diff --git a/tools/android/roll/android_deps/buildSrc/src/main/groovy/BuildConfigGenerator.groovy b/tools/android/roll/android_deps/buildSrc/src/main/groovy/BuildConfigGenerator.groovy index e5a2f12..41892a1 100644 --- a/tools/android/roll/android_deps/buildSrc/src/main/groovy/BuildConfigGenerator.groovy +++ b/tools/android/roll/android_deps/buildSrc/src/main/groovy/BuildConfigGenerator.groovy
@@ -166,6 +166,11 @@ // Deprecated deps jar but still needed by play services basement. sb.append(' input_jars_paths=["\\$android_sdk/optional/org.apache.http.legacy.jar"]\n') break + case 'com_google_ar_core': + // Target .aar file contains .so libraries that need to be extracted, + // and android_aar_prebuilt template will fail if it's not set explictly. + sb.append(' extract_native_libraries = true\n') + break } }
diff --git a/tools/android/roll/android_deps/buildSrc/src/main/groovy/ChromiumDepGraph.groovy b/tools/android/roll/android_deps/buildSrc/src/main/groovy/ChromiumDepGraph.groovy index 7b588211..bb33364d 100644 --- a/tools/android/roll/android_deps/buildSrc/src/main/groovy/ChromiumDepGraph.groovy +++ b/tools/android/roll/android_deps/buildSrc/src/main/groovy/ChromiumDepGraph.groovy
@@ -48,6 +48,10 @@ url: "https://github.com/protocolbuffers/protobuf/blob/master/java/lite.md", licenseUrl: "https://raw.githubusercontent.com/protocolbuffers/protobuf/master/LICENSE", licenseName: "BSD"), + 'com_google_ar_core' :new DependencyDescription( + url: "https://github.com/google-ar/arcore-android-sdk", + licenseUrl: "https://raw.githubusercontent.com/google-ar/arcore-android-sdk/master/LICENSE", + licenseName: "Apache 2.0"), ] Project project
diff --git a/tools/luci-go/.gitignore b/tools/luci-go/.gitignore index 38af367..2934681 100644 --- a/tools/luci-go/.gitignore +++ b/tools/luci-go/.gitignore
@@ -1,7 +1,10 @@ -/.versions /isolate /isolate.exe /isolated /isolated.exe +/linux64/isolate +/mac64/isolate /swarming /swarming.exe +/win64/isolate.exe +.versions
diff --git a/tools/luci-go/linux64/isolate.sha1 b/tools/luci-go/linux64/isolate.sha1 new file mode 100644 index 0000000..1610657 --- /dev/null +++ b/tools/luci-go/linux64/isolate.sha1
@@ -0,0 +1 @@ +9734e966a14f9e26f86e38a020fcd7584248d285
diff --git a/tools/luci-go/mac64/isolate.sha1 b/tools/luci-go/mac64/isolate.sha1 new file mode 100644 index 0000000..a61e43ab --- /dev/null +++ b/tools/luci-go/mac64/isolate.sha1
@@ -0,0 +1 @@ +18561de57e944d096521838b4e6cb49e0cc1df23
diff --git a/tools/luci-go/win64/isolate.exe.sha1 b/tools/luci-go/win64/isolate.exe.sha1 new file mode 100644 index 0000000..5ac52a0 --- /dev/null +++ b/tools/luci-go/win64/isolate.exe.sha1
@@ -0,0 +1 @@ +af227603890ea1d8c082b5caf15e46a6bf060a2e
diff --git a/tools/mb/mb_config.pyl b/tools/mb/mb_config.pyl index 02ed9ef..6ea737f 100644 --- a/tools/mb/mb_config.pyl +++ b/tools/mb/mb_config.pyl
@@ -772,7 +772,7 @@ # bots all using the 'release_bot' config). 'configs': { 'afl_asan_release_bot': [ - 'afl', 'asan', 'shared_release_bot', 'chromeos_codecs', 'pdf_xfa', 'disable_nacl', 'optimize_for_fuzzing', + 'afl', 'asan', 'release_bot', 'chromeos_codecs', 'pdf_xfa', 'disable_nacl', 'optimize_for_fuzzing', ], 'android_binary_size': [
diff --git a/tools/metrics/histograms/OWNERS b/tools/metrics/histograms/OWNERS index 8fa4cae..288af0a 100644 --- a/tools/metrics/histograms/OWNERS +++ b/tools/metrics/histograms/OWNERS
@@ -1,5 +1,15 @@ -# Metrics changes should always be reviewed by owners. +# Core Metrics Owners per-file histograms.xml=file://base/metrics/OWNERS + +# Use the following owners only if: +# - You work in the same area as them. +# - They are already a good reviewer for the non-metrics part of the CL. + +per-file histograms.xml=alexilin@chromium.org +per-file histograms.xml=csharrison@chromium.org +per-file histograms.xml=cthomp@chromium.org +per-file histograms.xml=schenney@chromium.org + per-file histograms.xml=set noparent # Extending enums by adding new buckets is allowed without OWNERS review, but
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml index 4c98708..365fbba 100644 --- a/tools/metrics/histograms/enums.xml +++ b/tools/metrics/histograms/enums.xml
@@ -2553,6 +2553,13 @@ <int value="1" label="Suggestion Selected"/> </enum> +<enum name="AutofillCardholderNameFixFlowPromptEvent"> + <int value="0" label="Shown"/> + <int value="1" label="Accepted"/> + <int value="2" label="Dismissed"/> + <int value="3" label="Closed without user interaction"/> +</enum> + <enum name="AutofillCardUploadDecision"> <obsolete> Deprecated as of 2/2016, replaced by AutofillCardUploadDecisionExpanded. @@ -3187,6 +3194,13 @@ <int value="3" label="Expiration date did not match, masked server card"/> </enum> +<enum name="AutofillSyncState"> + <int value="0" label="Signed Out"/> + <int value="1" label="Signed In"/> + <int value="2" label="Signed In and Wallet Sync Transport Enabled"/> + <int value="3" label="Signed In and Sync Feature Enabled"/> +</enum> + <enum name="AutofillTypeQuality"> <int value="0" label="Unknown"/> <int value="1" label="Match"/> @@ -17454,6 +17468,7 @@ <int value="1297" label="FILEMANAGERPRIVATEINTERNAL_UNSHAREPATHWITHCROSTINI"/> <int value="1298" label="PASSWORDSPRIVATE_RECORDPASSWORDSPAGEACCESSINSETTINGS"/> + <int value="1299" label="AUTOFILLPRIVATE_SERVERCARDLINKCLICKED"/> </enum> <enum name="ExtensionIconState">
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml index 1ba89d3..9c98f0f 100644 --- a/tools/metrics/histograms/histograms.xml +++ b/tools/metrics/histograms/histograms.xml
@@ -7097,6 +7097,18 @@ </summary> </histogram> +<histogram name="Autofill.CardholderNameFixFlowPrompt.Events" + enum="AutofillCardholderNameFixFlowPromptEvent" expires_after="2019-12-01"> + <owner>dlkumar@google.com</owner> + <owner>jsaul@google.com</owner> + <owner>chrome-autofill@google.com</owner> + <summary> + Events tracking the usage of the cardholder name fix flow prompt. This + prompt is triggered whenever cardholder name must be explicitly requested + from the user in order to upload the card to Google Payments. + </summary> +</histogram> + <histogram name="Autofill.CardUploadDecision" enum="AutofillCardUploadDecision"> <obsolete> Deprecated as of 2/2016, replaced by Autofill.CardUploadDecisionMetric. @@ -8040,6 +8052,16 @@ <summary>Usage of the "Scan card" control item.</summary> </histogram> +<histogram name="Autofill.ServerCardLinkClicked" enum="AutofillSyncState" + expires_after="M75"> + <owner>sebsg@chromium.org</owner> + <owner>ftirelo@chromium.org</owner> + <summary> + Logged when the user clicks on the server credit card link in the settings + page. + </summary> +</histogram> + <histogram name="Autofill.ServerExperimentId" enum="AutofillExperimentId"> <obsolete> Deprecated as of 6/2011, replaced by Autofill.ServerExperimentId.Query. @@ -75323,18 +75345,19 @@ <histogram name="PageLoad.Experimental.Bytes.Cache" units="KB"> <owner>jkarlin@chromium.org</owner> <summary> - The number of prefiltered (e.g., compressed) KiloBytes loaded from the cache - via the browser process for a page load. Recorded when the page load is - terminated. + The number of prefiltered (e.g., compressed) response body KiloBytes loaded + from the cache via the browser process for a page load. Recorded when the + page load is terminated. Only recorded for complete resources. </summary> </histogram> <histogram name="PageLoad.Experimental.Bytes.Network" units="KB"> <owner>jkarlin@chromium.org</owner> <summary> - The number of prefiltered (e.g., compressed) KiloBytes loaded over the - network via the browser process for a page load. Recorded when the page load - is terminated. + The number of prefiltered (e.g., compressed) response body KiloBytes loaded + over the network via the browser process for a page load. Does not include + any header or overhead bytes. Recorded when the page load is terminated. + Only recorded for complete resources. </summary> </histogram> @@ -75352,8 +75375,10 @@ <histogram name="PageLoad.Experimental.Bytes.Total" units="KB"> <owner>jkarlin@chromium.org</owner> <summary> - The number of prefiltered (e.g., compressed) KiloBytes loaded via the - browser process for a page load. Recorded when the page load is terminated. + The number of prefiltered (e.g., compressed) response body KiloBytes loaded + via the browser process for a page load. Does not include any header or + overhead bytes. Recorded when the page load is terminated. Only recorded for + complete resources. </summary> </histogram> @@ -105473,7 +105498,7 @@ </histogram> <histogram name="SiteIsolatedCodeCache.JS.Behaviour" - enum="SiteIsolatedCodeCacheJSBehaviour" expires_after="2018-12-31"> + enum="SiteIsolatedCodeCacheJSBehaviour" expires_after="2019-06-30"> <owner>mythria@chromium.org</owner> <summary> The behaviour of site isolated javascript code cache recorded for each cache @@ -105483,7 +105508,7 @@ </histogram> <histogram name="SiteIsolatedCodeCache.WASM.Behaviour" - enum="SiteIsolatedCodeCacheWASMBehaviour" expires_after="2018-12-31"> + enum="SiteIsolatedCodeCacheWASMBehaviour" expires_after="2019-06-30"> <owner>bbudge@chromium.org</owner> <summary> The behaviour of site isolated web assembly code cache recorded for each @@ -105737,7 +105762,7 @@ </histogram> <histogram name="SiteIsolation.XSD.Browser.Allowed.ContentScript" - enum="ContentResourceType2" expires_after="2018-12-11"> + enum="ContentResourceType2" expires_after="2019-06-01"> <owner>creis@chromium.org</owner> <summary> The total count of responses that were would be blocked by the cross-site @@ -131085,6 +131110,7 @@ </histogram_suffixes> <histogram_suffixes name="FileBrowserCrostiniSharedPathsDepth" separator="."> + <suffix name="AndroidFiles" label="Shared path in Android volume."/> <suffix name="Downloads" label="Shared path in Downloads volume."/> <suffix name="DriveComputers" label="Shared path in Drive Computers volume."/> <suffix name="MyDrive" label="Shared path in My Drive volume."/> @@ -135867,7 +135893,13 @@ the NoScript Preview intervention."/> <affected-histogram name="PageLoad.DocumentTiming.NavigationToLoadEventFired"/> - <affected-histogram name="PageLoad.Experimental.Bytes.Network"/> + <affected-histogram name="PageLoad.Experimental.Bytes.Network"> + <obsolete> + Deprecated 12/2018. + </obsolete> + </affected-histogram> + <affected-histogram + name="PageLoad.Experimental.Bytes.NetworkIncludingHeaders"/> <affected-histogram name="PageLoad.Experimental.CompletedResources.Network"/> <affected-histogram name="PageLoad.Experimental.PaintTiming.NavigationToFirstMeaningfulPaint"/> @@ -135962,7 +135994,13 @@ ResourceLoadingHints to show a Preview version of the page."/> <affected-histogram name="PageLoad.DocumentTiming.NavigationToLoadEventFired"/> - <affected-histogram name="PageLoad.Experimental.Bytes.Network"/> + <affected-histogram name="PageLoad.Experimental.Bytes.Network"> + <obsolete> + Deprecated 12/2018. + </obsolete> + </affected-histogram> + <affected-histogram + name="PageLoad.Experimental.Bytes.NetworkIncludingHeaders"/> <affected-histogram name="PageLoad.Experimental.CompletedResources.Network"/> <affected-histogram name="PageLoad.Experimental.PaintTiming.NavigationToFirstMeaningfulPaint"/> @@ -138817,6 +138855,15 @@ <affected-histogram name="Event.Latency.TouchToScrollUpdateSwapBegin"/> </histogram_suffixes> +<histogram_suffixes name="ServiceWorker.ResponseSource" separator="."> + <suffix name="CacheStorage" label="The response came from CacheStorage."/> + <suffix name="HttpCache" label="The response came from HttpCache."/> + <suffix name="Network" label="The response directly came from network."/> + <suffix name="Unspecified" label="The source of a response was unspecified."/> + <affected-histogram + name="ServiceWorker.LoadTiming.Subresource.ResponseReceivedToCompleted2"/> +</histogram_suffixes> + <histogram_suffixes name="ServiceWorker.ShutdownStatus" separator="_"> <suffix name="InShutdown" label="Browser shutdown started."/> <suffix name="NotInShutdown" label="Browser shutdown has not started."/>
diff --git a/ui/base/clipboard/clipboard_aura.cc b/ui/base/clipboard/clipboard_aura.cc index a70dcb97..202a196 100644 --- a/ui/base/clipboard/clipboard_aura.cc +++ b/ui/base/clipboard/clipboard_aura.cc
@@ -17,6 +17,7 @@ #include "base/memory/ptr_util.h" #include "base/no_destructor.h" #include "base/strings/utf_string_conversions.h" +#include "skia/ext/skia_utils_base.h" #include "third_party/skia/include/core/SkBitmap.h" #include "ui/base/clipboard/clipboard_monitor.h" #include "ui/base/clipboard/custom_data_helper.h" @@ -92,9 +93,9 @@ const SkBitmap& bitmap() const { return bitmap_; } void SetBitmapData(const SkBitmap& bitmap) { - if (bitmap_.tryAllocPixels(bitmap.info())) { - bitmap.readPixels(bitmap_.info(), bitmap_.getPixels(), bitmap_.rowBytes(), - 0, 0); + if (!skia::SkBitmapToN32OpaqueOrPremul(bitmap, &bitmap_)) { + NOTREACHED() << "Unable to convert bitmap for clipboard"; + return; } format_ |= BITMAP; }
diff --git a/ui/base/clipboard/clipboard_mac.mm b/ui/base/clipboard/clipboard_mac.mm index 8d8aeb1c..2677438 100644 --- a/ui/base/clipboard/clipboard_mac.mm +++ b/ui/base/clipboard/clipboard_mac.mm
@@ -18,6 +18,7 @@ #include "base/stl_util.h" #include "base/strings/sys_string_conversions.h" #include "base/strings/utf_string_conversions.h" +#include "skia/ext/skia_utils_base.h" #include "skia/ext/skia_utils_mac.h" #import "third_party/mozilla/NSPasteboard+Utils.h" #include "third_party/skia/include/core/SkBitmap.h" @@ -451,8 +452,18 @@ } void ClipboardMac::WriteBitmap(const SkBitmap& bitmap) { + SkBitmap out_bitmap; + if (!skia::SkBitmapToN32OpaqueOrPremul(bitmap, &out_bitmap)) { + NOTREACHED() << "Unable to convert bitmap for clipboard"; + return; + } + NSImage* image = skia::SkBitmapToNSImageWithColorSpace( - bitmap, base::mac::GetSystemColorSpace()); + out_bitmap, base::mac::GetSystemColorSpace()); + if (!image) { + NOTREACHED() << "SkBitmapToNSImageWithColorSpace failed"; + return; + } // An API to ask the NSImage to write itself to the clipboard comes in 10.6 :( // For now, spit out the image as a TIFF. NSPasteboard* pb = GetPasteboard();
diff --git a/ui/base/clipboard/clipboard_test_template.h b/ui/base/clipboard/clipboard_test_template.h index 6527047..fd0dcc6 100644 --- a/ui/base/clipboard/clipboard_test_template.h +++ b/ui/base/clipboard/clipboard_test_template.h
@@ -12,6 +12,9 @@ // TODO(dcheng): This is really horrible. In general, all tests should run on // all platforms, to avoid this mess. +#ifndef UI_BASE_CLIPBOARD_CLIPBOARD_TEST_TEMPLATE_H_ +#define UI_BASE_CLIPBOARD_CLIPBOARD_TEST_TEMPLATE_H_ + #include <stdint.h> #include <memory> @@ -34,6 +37,7 @@ #include "ui/base/clipboard/scoped_clipboard_writer.h" #include "ui/base/test/test_clipboard.h" #include "ui/gfx/geometry/size.h" +#include "ui/gfx/half_float.h" #if defined(OS_WIN) #include "ui/base/clipboard/clipboard_util_win.h" @@ -376,14 +380,20 @@ #endif } +namespace { + +using U8x4 = std::array<uint8_t, 4>; +using F16x4 = std::array<gfx::HalfFloat, 4>; + +template <typename T> static void TestBitmapWrite(Clipboard* clipboard, - const gfx::Size& size, - const uint32_t* bitmap_data) { + const SkImageInfo& info, + const T* bitmap_data, + const U8x4* expect_data) { { ScopedClipboardWriter scw(CLIPBOARD_TYPE_COPY_PASTE); SkBitmap bitmap; - ASSERT_TRUE(bitmap.setInfo( - SkImageInfo::MakeN32Premul(size.width(), size.height()))); + ASSERT_TRUE(bitmap.setInfo(info)); bitmap.setPixels( const_cast<void*>(reinterpret_cast<const void*>(bitmap_data))); scw.WriteImage(bitmap); @@ -392,42 +402,119 @@ EXPECT_TRUE(clipboard->IsFormatAvailable(Clipboard::GetBitmapFormatType(), CLIPBOARD_TYPE_COPY_PASTE)); const SkBitmap& image = clipboard->ReadImage(CLIPBOARD_TYPE_COPY_PASTE); - EXPECT_EQ(size, gfx::Size(image.width(), image.height())); - for (int j = 0; j < image.height(); ++j) { - const uint32_t* row_address = image.getAddr32(0, j); - for (int i = 0; i < image.width(); ++i) { - int offset = i + j * image.width(); - EXPECT_EQ(bitmap_data[offset], row_address[i]) << "i = " << i - << ", j = " << j; + ASSERT_EQ(image.info().colorType(), kN32_SkColorType); + ASSERT_NE(image.info().alphaType(), kUnpremul_SkAlphaType); + EXPECT_EQ(gfx::Size(info.width(), info.height()), + gfx::Size(image.width(), image.height())); + for (int y = 0; y < image.height(); ++y) { + const U8x4* actual_row = + reinterpret_cast<const U8x4*>(image.getAddr32(0, y)); + const U8x4* expect_row = &expect_data[y * info.width()]; + for (int x = 0; x < image.width(); ++x) { + EXPECT_EQ(expect_row[x], actual_row[x]) << "x = " << x << ", y = " << y; } } } -TYPED_TEST(ClipboardTest, SharedBitmapTest) { - const uint32_t fake_bitmap_1[] = { - 0x46061626, 0xf69f5988, 0x793f2937, 0xfa55b986, - 0x78772152, 0x87692a30, 0x36322a25, 0x4320401b, - 0x91848c21, 0xc3177b3c, 0x6946155c, 0x64171952, - }; - { - SCOPED_TRACE("first bitmap"); - TestBitmapWrite(&this->clipboard(), gfx::Size(4, 3), fake_bitmap_1); - } +constexpr U8x4 kRGBAUnpremul = {0x8a, 0x50, 0x15, 0x46}; +constexpr U8x4 kRGBAPremul = {0x26, 0x16, 0x06, 0x46}; +constexpr U8x4 kRGBAOpaque = {0x26, 0x16, 0x06, 0xff}; +constexpr U8x4 kBGRAUnpremul = {0x15, 0x50, 0x8a, 0x46}; +constexpr U8x4 kBGRAPremul = {0x06, 0x16, 0x26, 0x46}; +constexpr U8x4 kBGRAOpaque = {0x06, 0x16, 0x26, 0xff}; +constexpr F16x4 kRGBAF16Unpremul = {0x3854, 0x3505, 0x2d45, 0x3464}; +constexpr F16x4 kRGBAF16Premul = {0x30c5, 0x2d86, 0x2606, 0x3464}; +constexpr F16x4 kRGBAF16Opaque = {0x30c5, 0x2d86, 0x2606, 0x3c00}; - const uint32_t fake_bitmap_2[] = { - 0x46061626, 0xf69f5988, - 0x793f2937, 0xfa55b986, - 0x78772152, 0x87692a30, - 0x36322a25, 0x4320401b, - 0x91848c21, 0xc3177b3c, - 0x6946155c, 0x64171952, - 0xa6910313, 0x8302323e, - }; - { - SCOPED_TRACE("second bitmap"); - TestBitmapWrite(&this->clipboard(), gfx::Size(2, 7), fake_bitmap_2); - } +constexpr U8x4 kN32 = + (kN32_SkColorType == kRGBA_8888_SkColorType) ? kRGBAPremul : kBGRAPremul; +constexpr U8x4 kN32Opaque = + (kN32_SkColorType == kRGBA_8888_SkColorType) ? kRGBAOpaque : kBGRAOpaque; + +// Either RGBA_8888 or BGRA_8888 will be equivalent to N32, but the other +// won't be. +TYPED_TEST(ClipboardTest, Bitmap_RGBA_Premul) { + TestBitmapWrite( + &this->clipboard(), + SkImageInfo::Make(1, 1, kRGBA_8888_SkColorType, kPremul_SkAlphaType), + &kRGBAPremul, &kN32); } +TYPED_TEST(ClipboardTest, Bitmap_RGBA_Unpremul) { + TestBitmapWrite( + &this->clipboard(), + SkImageInfo::Make(1, 1, kRGBA_8888_SkColorType, kUnpremul_SkAlphaType), + &kRGBAUnpremul, &kN32); +} +TYPED_TEST(ClipboardTest, Bitmap_RGBA_Opaque) { + TestBitmapWrite( + &this->clipboard(), + SkImageInfo::Make(1, 1, kRGBA_8888_SkColorType, kOpaque_SkAlphaType), + &kRGBAOpaque, &kN32Opaque); +} +TYPED_TEST(ClipboardTest, Bitmap_BGRA_Premul) { + TestBitmapWrite( + &this->clipboard(), + SkImageInfo::Make(1, 1, kBGRA_8888_SkColorType, kPremul_SkAlphaType), + &kBGRAPremul, &kN32); +} +TYPED_TEST(ClipboardTest, Bitmap_BGRA_Unpremul) { + TestBitmapWrite( + &this->clipboard(), + SkImageInfo::Make(1, 1, kBGRA_8888_SkColorType, kUnpremul_SkAlphaType), + &kBGRAUnpremul, &kN32); +} +TYPED_TEST(ClipboardTest, Bitmap_BGRA_Opaque) { + TestBitmapWrite( + &this->clipboard(), + SkImageInfo::Make(1, 1, kBGRA_8888_SkColorType, kOpaque_SkAlphaType), + &kBGRAOpaque, &kN32Opaque); +} + +// Used by HTMLCanvasElement. +TYPED_TEST(ClipboardTest, Bitmap_F16_Premul) { + TestBitmapWrite( + &this->clipboard(), + SkImageInfo::Make(1, 1, kRGBA_F16_SkColorType, kPremul_SkAlphaType), + &kRGBAF16Premul, &kN32); +} +TYPED_TEST(ClipboardTest, Bitmap_F16_Unpremul) { + TestBitmapWrite( + &this->clipboard(), + SkImageInfo::Make(1, 1, kRGBA_F16_SkColorType, kUnpremul_SkAlphaType), + &kRGBAF16Unpremul, &kN32); +} +TYPED_TEST(ClipboardTest, Bitmap_F16_Opaque) { + TestBitmapWrite( + &this->clipboard(), + SkImageInfo::Make(1, 1, kRGBA_F16_SkColorType, kOpaque_SkAlphaType), + &kRGBAF16Opaque, &kN32Opaque); +} + +TYPED_TEST(ClipboardTest, Bitmap_N32_Premul) { + constexpr U8x4 b[4 * 3] = { + {0x26, 0x16, 0x06, 0x46}, {0x88, 0x59, 0x9f, 0xf6}, + {0x37, 0x29, 0x3f, 0x79}, {0x86, 0xb9, 0x55, 0xfa}, + {0x52, 0x21, 0x77, 0x78}, {0x30, 0x2a, 0x69, 0x87}, + {0x25, 0x2a, 0x32, 0x36}, {0x1b, 0x40, 0x20, 0x43}, + {0x21, 0x8c, 0x84, 0x91}, {0x3c, 0x7b, 0x17, 0xc3}, + {0x5c, 0x15, 0x46, 0x69}, {0x52, 0x19, 0x17, 0x64}, + }; + TestBitmapWrite(&this->clipboard(), SkImageInfo::MakeN32Premul(4, 3), b, b); +} +TYPED_TEST(ClipboardTest, Bitmap_N32_Premul_2x7) { + constexpr U8x4 b[2 * 7] = { + {0x26, 0x16, 0x06, 0x46}, {0x88, 0x59, 0x9f, 0xf6}, + {0x37, 0x29, 0x3f, 0x79}, {0x86, 0xb9, 0x55, 0xfa}, + {0x52, 0x21, 0x77, 0x78}, {0x30, 0x2a, 0x69, 0x87}, + {0x25, 0x2a, 0x32, 0x36}, {0x1b, 0x40, 0x20, 0x43}, + {0x21, 0x8c, 0x84, 0x91}, {0x3c, 0x7b, 0x17, 0xc3}, + {0x5c, 0x15, 0x46, 0x69}, {0x52, 0x19, 0x17, 0x64}, + {0x13, 0x03, 0x91, 0xa6}, {0x3e, 0x32, 0x02, 0x83}, + }; + TestBitmapWrite(&this->clipboard(), SkImageInfo::MakeN32Premul(2, 7), b, b); +} + +} // namespace TYPED_TEST(ClipboardTest, DataTest) { const ui::Clipboard::FormatType kFormat = @@ -674,3 +761,5 @@ } } // namespace ui + +#endif // UI_BASE_CLIPBOARD_CLIPBOARD_TEST_TEMPLATE_H_ \ No newline at end of file
diff --git a/ui/base/clipboard/clipboard_win.cc b/ui/base/clipboard/clipboard_win.cc index f5d2e406..1857bfa0 100644 --- a/ui/base/clipboard/clipboard_win.cc +++ b/ui/base/clipboard/clipboard_win.cc
@@ -25,6 +25,7 @@ #include "base/win/message_window.h" #include "base/win/scoped_gdi_object.h" #include "base/win/scoped_hdc.h" +#include "skia/ext/skia_utils_base.h" #include "skia/ext/skia_utils_win.h" #include "third_party/skia/include/core/SkBitmap.h" #include "ui/base/clipboard/clipboard_util_win.h" @@ -805,9 +806,16 @@ NULL); } -void ClipboardWin::WriteBitmap(const SkBitmap& bitmap) { +void ClipboardWin::WriteBitmap(const SkBitmap& in_bitmap) { HDC dc = ::GetDC(NULL); + SkBitmap bitmap; + // Either points bitmap at in_bitmap, or allocates and converts pixels. + if (!skia::SkBitmapToN32OpaqueOrPremul(in_bitmap, &bitmap)) { + NOTREACHED() << "Unable to convert bitmap for clipboard"; + return; + } + // This doesn't actually cost us a memcpy when the bitmap comes from the // renderer as we load it into the bitmap using setPixels which just sets a // pointer. Someone has to memcpy it into GDI, it might as well be us here.
diff --git a/ui/base/mojo/clipboard_client.cc b/ui/base/mojo/clipboard_client.cc index ddc6898..0424a79 100644 --- a/ui/base/mojo/clipboard_client.cc +++ b/ui/base/mojo/clipboard_client.cc
@@ -10,6 +10,7 @@ #include "base/strings/utf_string_conversions.h" #include "mojo/public/cpp/bindings/sync_call_restrictions.h" +#include "skia/ext/skia_utils_base.h" #include "third_party/skia/include/core/SkBitmap.h" #include "ui/base/clipboard/custom_data_helper.h" @@ -148,7 +149,12 @@ void ClipboardClient::WriteBitmap(const SkBitmap& bitmap) { mojo::SyncCallRestrictions::ScopedAllowSyncCall allow_sync_call; - clipboard_->WriteBitmap(bitmap); + SkBitmap out_bitmap; + if (!skia::SkBitmapToN32OpaqueOrPremul(bitmap, &out_bitmap)) { + NOTREACHED() << "Unable to convert bitmap for clipboard"; + return; + } + clipboard_->WriteBitmap(out_bitmap); } void ClipboardClient::WriteData(const FormatType& format,
diff --git a/ui/base/test/test_clipboard.cc b/ui/base/test/test_clipboard.cc index 66a8fc2..eaf9d066 100644 --- a/ui/base/test/test_clipboard.cc +++ b/ui/base/test/test_clipboard.cc
@@ -8,6 +8,7 @@ #include "base/memory/ptr_util.h" #include "base/numerics/safe_conversions.h" #include "base/strings/utf_string_conversions.h" +#include "skia/ext/skia_utils_base.h" #include "ui/base/clipboard/clipboard_monitor.h" namespace ui { @@ -187,9 +188,12 @@ void TestClipboard::WriteBitmap(const SkBitmap& bitmap) { // Create a dummy entry. GetDefaultStore().data[GetBitmapFormatType()]; + SkBitmap& dst = GetDefaultStore().image; - if (dst.tryAllocPixels(bitmap.info())) { - bitmap.readPixels(dst.info(), dst.getPixels(), dst.rowBytes(), 0, 0); + // Either points bitmap at in_bitmap, or allocates and converts pixels. + if (!skia::SkBitmapToN32OpaqueOrPremul(bitmap, &dst)) { + NOTREACHED() << "Unable to convert bitmap for clipboard"; + return; } }
diff --git a/ui/base/x/selection_owner.cc b/ui/base/x/selection_owner.cc index 1804eaed..4efee2d 100644 --- a/ui/base/x/selection_owner.cc +++ b/ui/base/x/selection_owner.cc
@@ -54,7 +54,7 @@ XAtom type = x11::None; int format = 0; // size in bits of each item in 'property' unsigned long num_items = 0; - unsigned char* properties = NULL; + unsigned char* properties = nullptr; unsigned long remaining_bytes = 0; int result = XGetWindowProperty(gfx::GetXDisplay(), window, property, @@ -100,9 +100,8 @@ } void SelectionOwner::RetrieveTargets(std::vector<XAtom>* targets) { - for (auto it = format_map_.begin(); it != format_map_.end(); ++it) { - targets->push_back(it->first); - } + for (const auto& format_target : format_map_) + targets->push_back(format_target.first); } void SelectionOwner::TakeOwnershipOfSelection( @@ -145,13 +144,12 @@ requested_property, &conversions)) { std::vector<XAtom> conversion_results; - for (size_t i = 0; i < conversions.size(); ++i) { - bool conversion_successful = ProcessTarget(conversions[i].first, - requestor, - conversions[i].second); - conversion_results.push_back(conversions[i].first); - conversion_results.push_back( - conversion_successful ? conversions[i].second : x11::None); + for (const std::pair<XAtom, XAtom>& conversion : conversions) { + bool conversion_successful = + ProcessTarget(conversion.first, requestor, conversion.second); + conversion_results.push_back(conversion.first); + conversion_results.push_back(conversion_successful ? conversion.second + : x11::None); } // Set the property to indicate which conversions succeeded. This matches @@ -216,11 +214,8 @@ if (target == targets_atom) { // We have been asked for TARGETS. Send an atom array back with the data // types we support. - std::vector<XAtom> targets; - targets.push_back(timestamp_atom); - targets.push_back(targets_atom); - targets.push_back(save_targets_atom); - targets.push_back(multiple_atom); + std::vector<XAtom> targets = {timestamp_atom, targets_atom, + save_targets_atom, multiple_atom}; RetrieveTargets(&targets); XChangeProperty(x_display_, requestor, property, XA_ATOM, 32, @@ -302,7 +297,7 @@ // transfer->data once the zero-sized chunk is sent to indicate that state // related to this data transfer can be cleared. if (chunk_length == 0) - transfer->data = NULL; + transfer->data = nullptr; } void SelectionOwner::AbortStaleIncrementalTransfers() {
diff --git a/ui/base/x/selection_requestor.cc b/ui/base/x/selection_requestor.cc index 8fb3bda..48a4080 100644 --- a/ui/base/x/selection_requestor.cc +++ b/ui/base/x/selection_requestor.cc
@@ -38,16 +38,15 @@ if (data.size() == 1u) return data[0]; - size_t length = 0; - for (size_t i = 0; i < data.size(); ++i) - length += data[i]->size(); + size_t combined_length = 0; + for (const auto& datum : data) + combined_length += datum->size(); std::vector<unsigned char> combined_data; - combined_data.reserve(length); + combined_data.reserve(combined_length); - for (size_t i = 0; i < data.size(); ++i) { - combined_data.insert(combined_data.end(), - data[i]->front(), - data[i]->front() + data[i]->size()); + for (const auto& datum : data) { + combined_data.insert(combined_data.end(), datum->front(), + datum->front() + datum->size()); } return base::RefCountedBytes::TakeVector(&combined_data); } @@ -109,21 +108,17 @@ XAtom target, const std::vector<XAtom>& parameter) { SetAtomArrayProperty(x_window_, kChromeSelection, "ATOM", parameter); - PerformBlockingConvertSelection(selection, target, NULL, NULL, NULL); + PerformBlockingConvertSelection(selection, target, nullptr, nullptr, nullptr); } SelectionData SelectionRequestor::RequestAndWaitForTypes( XAtom selection, const std::vector<XAtom>& types) { - for (auto it = types.begin(); it != types.end(); ++it) { + for (const XAtom& item : types) { scoped_refptr<base::RefCountedMemory> data; XAtom type = x11::None; - if (PerformBlockingConvertSelection(selection, - *it, - &data, - NULL, - &type) && - type == *it) { + if (PerformBlockingConvertSelection(selection, item, &data, nullptr, + &type) && type == item) { return SelectionData(type, data); } } @@ -283,8 +278,9 @@ } SelectionRequestor::Request* SelectionRequestor::GetCurrentRequest() { - return current_request_index_ == requests_.size() ? - NULL : requests_[current_request_index_]; + return current_request_index_ == requests_.size() + ? nullptr + : requests_[current_request_index_]; } SelectionRequestor::Request::Request(XAtom selection,
diff --git a/ui/base/x/selection_requestor_unittest.cc b/ui/base/x/selection_requestor_unittest.cc index 7cf997e..3b8efd2 100644 --- a/ui/base/x/selection_requestor_unittest.cc +++ b/ui/base/x/selection_requestor_unittest.cc
@@ -66,11 +66,11 @@ InputOnly, CopyFromParent, // visual 0, - NULL); + nullptr); event_source_ = PlatformEventSource::CreateDefault(); CHECK(PlatformEventSource::GetInstance()); - requestor_.reset(new SelectionRequestor(x_display_, x_window_, NULL)); + requestor_.reset(new SelectionRequestor(x_display_, x_window_, nullptr)); } void TearDown() override {
diff --git a/ui/base/x/selection_utils.cc b/ui/base/x/selection_utils.cc index c0947ea..1ff0c81 100644 --- a/ui/base/x/selection_utils.cc +++ b/ui/base/x/selection_utils.cc
@@ -51,9 +51,9 @@ void GetAtomIntersection(const std::vector< ::Atom>& desired, const std::vector< ::Atom>& offered, std::vector< ::Atom>* output) { - for (auto it = desired.begin(); it != desired.end(); ++it) { - if (base::ContainsValue(offered, *it)) - output->push_back(*it); + for (const auto& desired_atom : desired) { + if (base::ContainsValue(offered, desired_atom)) + output->push_back(desired_atom); } } @@ -120,8 +120,8 @@ ui::SelectionData SelectionFormatMap::GetFirstOf( const std::vector< ::Atom>& requested_types) const { - for (auto it = requested_types.begin(); it != requested_types.end(); ++it) { - auto data_it = data_.find(*it); + for (const auto& requested_type : requested_types) { + auto data_it = data_.find(requested_type); if (data_it != data_.end()) { return SelectionData(data_it->first, data_it->second); } @@ -132,8 +132,8 @@ std::vector< ::Atom> SelectionFormatMap::GetTypes() const { std::vector< ::Atom> atoms; - for (auto it = data_.begin(); it != data_.end(); ++it) - atoms.push_back(it->first); + for (const auto& datum : data_) + atoms.push_back(datum.first); return atoms; } @@ -169,7 +169,7 @@ } const unsigned char* SelectionData::GetData() const { - return memory_.get() ? memory_->front() : NULL; + return memory_.get() ? memory_->front() : nullptr; } size_t SelectionData::GetSize() const {
diff --git a/ui/base/x/x11_util.cc b/ui/base/x/x11_util.cc index 9d79f93..9dfd9e0 100644 --- a/ui/base/x/x11_util.cc +++ b/ui/base/x/x11_util.cc
@@ -664,7 +664,7 @@ XAtom type = x11::None; int format = 0; // size in bits of each item in 'property' unsigned long num_items = 0; - unsigned char* property = NULL; + unsigned char* property = nullptr; int result = GetProperty(window, property_name, 1, &type, &format, &num_items, &property); @@ -685,7 +685,7 @@ unsigned long nbytes = 0; XAtom prop_type = x11::None; int prop_format = 0; - unsigned char* property_data = NULL; + unsigned char* property_data = nullptr; if (XGetWindowProperty(gfx::GetXDisplay(), window, property, 0, kLongLength, x11::False, AnyPropertyType, &prop_type, &prop_format, &nitems, &nbytes, &property_data) != x11::Success) { @@ -698,7 +698,7 @@ size_t bytes = 0; // So even though we should theoretically have nbytes (and we can't - // pass NULL there), we need to manually calculate the byte length here + // pass nullptr there), we need to manually calculate the byte length here // because nbytes always returns zero. switch (prop_format) { case 8: @@ -731,7 +731,7 @@ XAtom type = x11::None; int format = 0; // size in bits of each item in 'property' unsigned long num_items = 0; - unsigned char* property = NULL; + unsigned char* property = nullptr; int result = GetProperty(window, property_name, 1, &type, &format, &num_items, &property); @@ -750,7 +750,7 @@ XAtom type = x11::None; int format = 0; // size in bits of each item in 'property' unsigned long num_items = 0; - unsigned char* property = NULL; + unsigned char* property = nullptr; int result = GetProperty(window, property_name, 1, &type, &format, &num_items, &property); @@ -771,7 +771,7 @@ XAtom type = x11::None; int format = 0; // size in bits of each item in 'property' unsigned long num_items = 0; - unsigned char* properties = NULL; + unsigned char* properties = nullptr; int result = GetProperty(window, property_name, (~0L), // (all of them) @@ -797,7 +797,7 @@ XAtom type = x11::None; int format = 0; // size in bits of each item in 'property' unsigned long num_items = 0; - unsigned char* properties = NULL; + unsigned char* properties = nullptr; int result = GetProperty(window, property_name, (~0L), // (all of them) @@ -820,7 +820,7 @@ XAtom type = x11::None; int format = 0; // size in bits of each item in 'property' unsigned long num_items = 0; - unsigned char* property = NULL; + unsigned char* property = nullptr; int result = GetProperty(window, property_name, 1024, &type, &format, &num_items, &property); @@ -1097,7 +1097,7 @@ Atom type; int format; unsigned long count; - unsigned char *data = NULL; + unsigned char* data = nullptr; if (GetProperty(window, "_NET_CLIENT_LIST_STACKING", ~0L, &type, &format, &count, &data) != x11::Success) { return false; @@ -1227,7 +1227,7 @@ } void SetDefaultX11ErrorHandlers() { - SetX11ErrorHandlers(NULL, NULL); + SetX11ErrorHandlers(nullptr, nullptr); } bool IsX11WindowFullScreen(XID window) { @@ -1348,7 +1348,7 @@ // These functions are declared in x11_util_internal.h because they require // XLib.h to be included, and it conflicts with many other headers. XRenderPictFormat* GetRenderARGB32Format(XDisplay* dpy) { - static XRenderPictFormat* pictformat = NULL; + static XRenderPictFormat* pictformat = nullptr; if (pictformat) return pictformat;
diff --git a/ui/file_manager/file_manager/background/js/crostini.js b/ui/file_manager/file_manager/background/js/crostini.js index 4aa1675..216cb998 100644 --- a/ui/file_manager/file_manager/background/js/crostini.js +++ b/ui/file_manager/file_manager/background/js/crostini.js
@@ -33,6 +33,7 @@ CrostiniImpl.VALID_ROOT_TYPES_FOR_SHARE = new Map([ [VolumeManagerCommon.RootType.DOWNLOADS, 'Downloads'], [VolumeManagerCommon.RootType.REMOVABLE, 'Removable'], + [VolumeManagerCommon.RootType.ANDROID_FILES, 'AndroidFiles'], ]); /**
diff --git a/ui/file_manager/file_manager/foreground/js/metadata/BUILD.gn b/ui/file_manager/file_manager/foreground/js/metadata/BUILD.gn index fa2e8ae..6f95c18 100644 --- a/ui/file_manager/file_manager/foreground/js/metadata/BUILD.gn +++ b/ui/file_manager/file_manager/foreground/js/metadata/BUILD.gn
@@ -8,6 +8,14 @@ # TODO(tapted): This entire folder should move to //ui/file_manager/base. visibility = [ "//ui/file_manager/*" ] +group("closure_compile") { + testonly = true + deps = [ + ":closure_compile_module", + ":unit_tests_type_check", + ] +} + js_type_check("closure_compile_module") { deps = [ ":byte_reader", @@ -84,6 +92,15 @@ js_library("external_metadata_provider") { deps = [ ":metadata_provider", + "//ui/file_manager/externs:file_manager_private", + ] +} + +js_unittest("external_metadata_provider_unittest") { + deps = [ + ":external_metadata_provider", + "//ui/file_manager/base/js:mock_chrome", + "//ui/file_manager/base/js:test_error_reporting", ] } @@ -264,6 +281,7 @@ deps = [ ":content_metadata_provider_unittest", ":exif_parser_unittest", + ":external_metadata_provider_unittest", ":file_system_metadata_provider_unittest", ":image_orientation_unittest", ":metadata_cache_item_unittest", @@ -273,11 +291,3 @@ ":thumbnail_model_unittest", ] } - -group("closure_compile") { - testonly = true - deps = [ - ":closure_compile_module", - ":unit_tests_type_check", - ] -}
diff --git a/ui/file_manager/file_manager/foreground/js/metadata/external_metadata_provider_unittest.html b/ui/file_manager/file_manager/foreground/js/metadata/external_metadata_provider_unittest.html deleted file mode 100644 index e2edc1af1..0000000 --- a/ui/file_manager/file_manager/foreground/js/metadata/external_metadata_provider_unittest.html +++ /dev/null
@@ -1,21 +0,0 @@ -<!DOCTYPE html> -<!-- Copyright 2015 The Chromium Authors. All rights reserved. - -- Use of this source code is governed by a BSD-style license that can be - -- found in the LICENSE file. - --> -<!-- Base classes --> -<script src="../../../../../webui/resources/js/cr.js"></script> -<script src="../../../../../webui/resources/js/cr/event_target.js"></script> -<script src="metadata_cache_set.js"></script> -<script src="metadata_provider.js"></script> -<script src="metadata_request.js"></script> - -<!-- Others --> -<script src="../../../../../webui/resources/js/assert.js"></script> -<script src="../../../common/js/lru_cache.js"></script> -<script src="../../../../base/js/test_error_reporting.js"></script> -<script src="external_metadata_provider.js"></script> -<script src="metadata_cache_item.js"></script> -<script src="metadata_item.js"></script> - -<script src="external_metadata_provider_unittest.js"></script>
diff --git a/ui/file_manager/file_manager/foreground/js/metadata/external_metadata_provider_unittest.js b/ui/file_manager/file_manager/foreground/js/metadata/external_metadata_provider_unittest.js index dbca1520..21cef7f 100644 --- a/ui/file_manager/file_manager/foreground/js/metadata/external_metadata_provider_unittest.js +++ b/ui/file_manager/file_manager/foreground/js/metadata/external_metadata_provider_unittest.js
@@ -2,19 +2,31 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -var entryA = { - toURL: function() { return "filesystem://A"; }, - isFile: true -}; +/** @const {!Entry} */ +const entryA = /** @type {!Entry} */ ({ + toURL: function() { + return 'filesystem://A'; + }, + isFile: true, +}); -var entryB = { - toURL: function() { return "filesystem://B"; }, - isFile: true -}; +/** @const {!Entry} */ +const entryB = /** @type {!Entry} */ ({ + toURL: function() { + return 'filesystem://B'; + }, + isFile: true, +}); + +/** + * Mock chrome APIs. + * @type {!Object} + */ +let mockChrome; function testExternalMetadataProviderBasic(callback) { - // Mocking chrome API. - window.chrome = { + // Setup mock chrome APIs. + mockChrome = { fileManagerPrivate: { getEntryProperties: function(entries, names, callback) { assertEquals(2, entries.length); @@ -41,8 +53,13 @@ ]); } }, - runtime: {lastError: null} + runtime: { + lastError: null, + }, }; + + installMockChrome(mockChrome); + var provider = new ExternalMetadataProvider(); reportPromise(provider.get([ new MetadataRequest(entryA, ['modificationTime', 'size']),
diff --git a/ui/gfx/color_palette.h b/ui/gfx/color_palette.h index d17425b..186c6c0 100644 --- a/ui/gfx/color_palette.h +++ b/ui/gfx/color_palette.h
@@ -17,6 +17,7 @@ // palette ranges from 050-900. constexpr SkColor kGoogleBlue100 = SkColorSetRGB(0xD2, 0xE3, 0xFC); constexpr SkColor kGoogleBlue300 = SkColorSetRGB(0x8A, 0xB4, 0xF8); +constexpr SkColor kGoogleBlue400 = SkColorSetRGB(0x66, 0x9D, 0xF6); constexpr SkColor kGoogleBlue500 = SkColorSetRGB(0x42, 0x85, 0xF4); constexpr SkColor kGoogleBlue600 = SkColorSetRGB(0x1A, 0x73, 0xE8); constexpr SkColor kGoogleBlue700 = SkColorSetRGB(0x19, 0x67, 0xD2);
diff --git a/ui/login/display_manager.js b/ui/login/display_manager.js index a665d34..66aba49 100644 --- a/ui/login/display_manager.js +++ b/ui/login/display_manager.js
@@ -269,6 +269,12 @@ userCount_: 0, /** + * Number of reloadContent() calls since start for testing. + * @type {number} + */ + reloadContentNumEvents_: 0, + + /** * Stored OOBE configuration for newly registered screens. * @type {!OobeTypes.OobeConfiguration} */ @@ -869,6 +875,7 @@ var currentScreenId = this.screens_[this.currentStep_]; var currentScreen = $(currentScreenId); this.updateScreenSize(currentScreen); + ++this.reloadContentNumEvents_; }, /**
diff --git a/ui/native_theme/common_theme.cc b/ui/native_theme/common_theme.cc index be4c33f6..2986477 100644 --- a/ui/native_theme/common_theme.cc +++ b/ui/native_theme/common_theme.cc
@@ -106,6 +106,8 @@ case NativeTheme::kColorId_ButtonEnabledColor: case NativeTheme::kColorId_ButtonHoverColor: return kButtonEnabledColor; + case NativeTheme::kColorId_ProminentButtonFocusedColor: + return gfx::kGoogleBlue400; case NativeTheme::kColorId_ProminentButtonColor: return gfx::kGoogleBlue500; case NativeTheme::kColorId_TextOnProminentButtonColor: @@ -126,7 +128,7 @@ case NativeTheme::kColorId_MenuBorderColor: return SkColorSetRGB(0xBA, 0xBA, 0xBA); case NativeTheme::kColorId_MenuSeparatorColor: - return SkColorSetRGB(0xE9, 0xE9, 0xE9); + return gfx::kGoogleGrey200; case NativeTheme::kColorId_MenuBackgroundColor: return SK_ColorWHITE; case NativeTheme::kColorId_FocusedMenuItemBackgroundColor:
diff --git a/ui/native_theme/native_theme.h b/ui/native_theme/native_theme.h index 2796e42..0e2ad024 100644 --- a/ui/native_theme/native_theme.h +++ b/ui/native_theme/native_theme.h
@@ -304,6 +304,7 @@ kColorId_ButtonHoverColor, kColorId_ButtonPressedShade, kColorId_ProminentButtonColor, + kColorId_ProminentButtonFocusedColor, kColorId_TextOnProminentButtonColor, // MenuItem kColorId_TouchableMenuItemLabelColor,
diff --git a/ui/native_theme/native_theme_dark_aura.cc b/ui/native_theme/native_theme_dark_aura.cc index 712fc0d..320c5ef 100644 --- a/ui/native_theme/native_theme_dark_aura.cc +++ b/ui/native_theme/native_theme_dark_aura.cc
@@ -27,6 +27,8 @@ // Button case kColorId_ButtonEnabledColor: return SK_ColorWHITE; + case kColorId_ProminentButtonFocusedColor: + return gfx::kGoogleBlue500; case kColorId_ProminentButtonColor: return gfx::kGoogleBlue600;
diff --git a/ui/views/controls/button/md_text_button.cc b/ui/views/controls/button/md_text_button.cc index c47cf87..fb8fb15d 100644 --- a/ui/views/controls/button/md_text_button.cc +++ b/ui/views/controls/button/md_text_button.cc
@@ -111,6 +111,16 @@ UpdateColors(); } +void MdTextButton::OnFocus() { + LabelButton::OnFocus(); + UpdateColors(); +} + +void MdTextButton::OnBlur() { + LabelButton::OnBlur(); + UpdateColors(); +} + std::unique_ptr<views::InkDropHighlight> MdTextButton::CreateInkDropHighlight() const { // The prominent button hover effect is a shadow. @@ -248,7 +258,8 @@ bg_color = *bg_color_override_; } else if (is_prominent_) { bg_color = theme->GetSystemColor( - ui::NativeTheme::kColorId_ProminentButtonColor); + HasFocus() ? ui::NativeTheme::kColorId_ProminentButtonFocusedColor + : ui::NativeTheme::kColorId_ProminentButtonColor); if (is_disabled) { bg_color = color_utils::BlendTowardOppositeLuma( bg_color, gfx::kDisabledControlAlpha);
diff --git a/ui/views/controls/button/md_text_button.h b/ui/views/controls/button/md_text_button.h index eafa8a8..76ad4b8 100644 --- a/ui/views/controls/button/md_text_button.h +++ b/ui/views/controls/button/md_text_button.h
@@ -39,9 +39,6 @@ // background and ink drop effects. void set_corner_radius(float radius); - // View: - void OnPaintBackground(gfx::Canvas* canvas) override; - // LabelButton: void OnNativeThemeChanged(const ui::NativeTheme* theme) override; std::unique_ptr<InkDrop> CreateInkDrop() override; @@ -55,6 +52,11 @@ void StateChanged(ButtonState old_state) override; protected: + // View: + void OnPaintBackground(gfx::Canvas* canvas) override; + void OnFocus() override; + void OnBlur() override; + MdTextButton(ButtonListener* listener, int button_context); private:
diff --git a/ui/webui/resources/cr_components/BUILD.gn b/ui/webui/resources/cr_components/BUILD.gn index b39708e..3773a9e 100644 --- a/ui/webui/resources/cr_components/BUILD.gn +++ b/ui/webui/resources/cr_components/BUILD.gn
@@ -7,6 +7,7 @@ group("closure_compile") { deps = [ "certificate_manager:closure_compile", + "managed_footnote:closure_compile", ] if (is_chromeos) {
diff --git a/ui/webui/resources/cr_components/cr_components_resources.grdp b/ui/webui/resources/cr_components/cr_components_resources.grdp index 2c978f4..5723b56 100644 --- a/ui/webui/resources/cr_components/cr_components_resources.grdp +++ b/ui/webui/resources/cr_components/cr_components_resources.grdp
@@ -383,4 +383,12 @@ type="chrome_html" compress="gzip" /> </if> + <structure name="IDR_WEBUI_MANAGED_FOOTNOTE_HTML" + file="cr_components/managed_footnote/managed_footnote.html" + type="chrome_html" + compress="gzip" /> + <structure name="IDR_WEBUI_MANAGED_FOOTNOTE_JS" + file="cr_components/managed_footnote/managed_footnote.js" + type="chrome_html" + compress="gzip" /> </grit-part>
diff --git a/ui/webui/resources/cr_components/managed_footnote/BUILD.gn b/ui/webui/resources/cr_components/managed_footnote/BUILD.gn new file mode 100644 index 0000000..a5b2c62 --- /dev/null +++ b/ui/webui/resources/cr_components/managed_footnote/BUILD.gn
@@ -0,0 +1,19 @@ +# Copyright 2018 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +import("//third_party/closure_compiler/compile_js.gni") + +js_type_check("closure_compile") { + deps = [ + ":managed_footnote", + ] +} + +js_library("managed_footnote") { + deps = [ + "//ui/webui/resources/js:cr", + "//ui/webui/resources/js:i18n_behavior", + "//ui/webui/resources/js:load_time_data", + ] +}
diff --git a/ui/webui/resources/cr_components/managed_footnote/managed_footnote.html b/ui/webui/resources/cr_components/managed_footnote/managed_footnote.html new file mode 100644 index 0000000..95602ef --- /dev/null +++ b/ui/webui/resources/cr_components/managed_footnote/managed_footnote.html
@@ -0,0 +1,52 @@ +<link rel="import" href="../../html/polymer.html"> + +<link rel="import" href="../../cr_elements/icons.html"> +<link rel="import" href="../../html/i18n_behavior.html"> +<link rel="import" href="../../html/load_time_data.html"> +<link rel="import" href="../../polymer/v1_0/iron-icon/iron-icon.html"> +<link rel="import" href="../../polymer/v1_0/paper-styles/color.html"> + +<dom-module id="managed-footnote"> + <template> + <style> + :host { + --iron-icon-fill-color: var(--google-grey-refresh-700); + + align-items: center; + border-top: 1px solid var(--google-grey-300); + color: var(--google-grey-refresh-700); + display: none; + /* Should be 13px when <html> font-size is 16px */ + font-size: 0.8125rem; + justify-content: center; + padding: 0 24px; + } + + :host([is-managed_]) { + display: flex; + } + + :host([noborder]) { + border-top: none; + } + + a[href] { + color: var(--google-blue-500); + text-decoration: none; + } + + iron-icon { + flex-shrink: 0; + height: 20px; + padding-inline-end: 8px; + width: 20px; + } + </style> + + <template is="dom-if" if="[[isManaged_]]"> + <iron-icon icon="cr:domain"></iron-icon> + <div id="content" inner-h-t-m-l="[[message_]]"></div> + </template> + </template> + <script src="managed_footnote.js"></script> +</dom-module>
diff --git a/ui/webui/resources/cr_components/managed_footnote/managed_footnote.js b/ui/webui/resources/cr_components/managed_footnote/managed_footnote.js new file mode 100644 index 0000000..96fc102 --- /dev/null +++ b/ui/webui/resources/cr_components/managed_footnote/managed_footnote.js
@@ -0,0 +1,61 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +/** + * @fileoverview Polymer element for indicating that this user is managed by + * their organization. This component uses the |isManaged| boolean in + * loadTimeData, and the |managedByOrg| i18n string. + * + * If |isManaged| is false, this component is hidden. If |isManaged| is true, it + * becomes visible. + */ + +(function() { +/** + * URL of the help article for the clickable link. + * @type {string} + */ +// TODO(nicolaso): Use a p-link instead, once it's available. b/117655761 +const HELP_ARTICLE_URL = 'https://support.google.com/chromebook/answer/1331549'; + +Polymer({ + is: 'managed-footnote', + + behaviors: [I18nBehavior], + + properties: { + /** + * Whether the browser is managed by their organization through enterprise + * policies. + * @private + */ + isManaged_: { + reflectToAttribute: true, + type: Boolean, + value: function() { + return loadTimeData.getBoolean('isManaged'); + }, + }, + + /** + * Localized message to display in the footnote. May contain an <a> + * element. + * @private + */ + message_: String, + }, + + /** @override */ + ready: function() { + this.message_ = this.i18nAdvanced('managedByOrg', { + substitutions: [HELP_ARTICLE_URL], + tags: ['a'], + attrs: { + target: (node, v) => v === '_blank', + href: (node, v) => v === HELP_ARTICLE_URL, + }, + }); + }, +}); +})();
diff --git a/ui/webui/resources/cr_elements/icons.html b/ui/webui/resources/cr_elements/icons.html index 437eb4e..fda872d 100644 --- a/ui/webui/resources/cr_elements/icons.html +++ b/ui/webui/resources/cr_elements/icons.html
@@ -42,6 +42,7 @@ <g id="clear"><path d="M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z"></path></g> <g id="close"><path d="M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z"></path></g> <g id="delete"><path d="M6 19c0 1.1.9 2 2 2h8c1.1 0 2-.9 2-2V7H6v12zM19 4h-3.5l-1-1h-5l-1 1H5v2h14V4z"></path></g> + <g id="domain"><path d="M12 7V3H2v18h20V7H12zM6 19H4v-2h2v2zm0-4H4v-2h2v2zm0-4H4V9h2v2zm0-4H4V5h2v2zm4 12H8v-2h2v2zm0-4H8v-2h2v2zm0-4H8V9h2v2zm0-4H8V5h2v2zm10 12h-8v-2h2v-2h-2v-2h2v-2h-2V9h8v10zm-2-8h-2v2h2v-2zm0 4h-2v2h2v-2z"></path></g> <g id="error"><path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm1 15h-2v-2h2v2zm0-4h-2V7h2v6z"></path></g> <g id="error-outline"><path d="M11 15h2v2h-2zm0-8h2v6h-2zm.99-5C6.47 2 2 6.48 2 12s4.47 10 9.99 10C17.52 22 22 17.52 22 12S17.52 2 11.99 2zM12 20c-4.42 0-8-3.58-8-8s3.58-8 8-8 8 3.58 8 8-3.58 8-8 8z"></path></g> <g id="expand-less"><path d="M12 8l-6 6 1.41 1.41L12 10.83l4.59 4.58L18 14z"></path></g>
diff --git a/webrunner/BUILD.gn b/webrunner/BUILD.gn index 4b2851e..b997a62 100644 --- a/webrunner/BUILD.gn +++ b/webrunner/BUILD.gn
@@ -57,7 +57,9 @@ ] } -test("castrunner_unittests") { +# TODO(crbug.com/901955): This target is to be used for both unit tests and +# integration tests. +test("castrunner_tests") { sources = [ "app/cast/cast_runner_unittest.cc", ] @@ -69,6 +71,10 @@ "//testing/gmock", "//testing/gtest", ] + package_deps = [ [ + ":service_pkg", + "chromium", + ] ] } fuchsia_package("webrunner_pkg") {