diff --git a/DEPS b/DEPS index ff9e8d8..f965bf8 100644 --- a/DEPS +++ b/DEPS
@@ -610,7 +610,7 @@ # For Linux and Chromium OS. 'src/third_party/cros_system_api': { - 'url': Var('chromium_git') + '/chromiumos/platform2/system_api.git' + '@' + '7d4f284ecdc0f1acf8f217edea667be2ad28fcb1', + 'url': Var('chromium_git') + '/chromiumos/platform2/system_api.git' + '@' + '2e1f8c671bd4a63619f207c3e771ac8cd8fe2f09', 'condition': 'checkout_linux', }, @@ -954,7 +954,7 @@ }, 'src/third_party/perfetto': - Var('android_git') + '/platform/external/perfetto.git' + '@' + '333dfc148ff370ab58096afcab4ba84367920515', + Var('android_git') + '/platform/external/perfetto.git' + '@' + '7a4d068d23a61a4ad7ec0fe333e2597ef686157c', 'src/third_party/perl': { 'url': Var('chromium_git') + '/chromium/deps/perl.git' + '@' + 'ac0d98b5cee6c024b0cffeb4f8f45b6fc5ccdb78', @@ -1106,7 +1106,7 @@ Var('chromium_git') + '/external/khronosgroup/webgl.git' + '@' + '6d2f3f4cb8bac1f7c4a945c73d07a33df74f22f9', 'src/third_party/webrtc': - Var('webrtc_git') + '/src.git' + '@' + '7f6417f480e79511ab186354bf7cd8b43765f415', + Var('webrtc_git') + '/src.git' + '@' + 'c0f26d458d3deb57142f4203f627eaf7577a7a22', 'src/third_party/xdg-utils': { 'url': Var('chromium_git') + '/chromium/deps/xdg-utils.git' + '@' + 'd80274d5869b17b8c9067a1022e4416ee7ed5e0d', @@ -1137,7 +1137,7 @@ Var('chromium_git') + '/v8/v8.git' + '@' + Var('v8_revision'), 'src-internal': { - 'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@3fbdcc7add70666e504fd5f3905741bbd374ad72', + 'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@dcf4ffb80c0134cd1f1164b84c0aea26264c2536', 'condition': 'checkout_src_internal', },
diff --git a/WATCHLISTS b/WATCHLISTS index ed829fd..682010e 100644 --- a/WATCHLISTS +++ b/WATCHLISTS
@@ -2157,8 +2157,7 @@ 'gamepad': ['mattreynolds+watch@chromium.org'], 'gcm': ['peter@chromium.org', 'zea+watch@chromium.org'], - 'generic_sensor': ['alexander.shalamov@intel.com', - 'juncai+watch@chromium.org', + 'generic_sensor': ['juncai+watch@chromium.org', 'mattreynolds+watch@chromium.org', 'timvolodine@chromium.org', 'wanming.lin@intel.com'],
diff --git a/android_webview/browser/aw_browser_main_parts.cc b/android_webview/browser/aw_browser_main_parts.cc index a18719a..1eff17a 100644 --- a/android_webview/browser/aw_browser_main_parts.cc +++ b/android_webview/browser/aw_browser_main_parts.cc
@@ -149,11 +149,6 @@ AwBrowserMainParts::~AwBrowserMainParts() { } -bool AwBrowserMainParts::ShouldContentCreateFeatureList() { - // FeatureList will be created in AwFieldTrialCreator. - return false; -} - int AwBrowserMainParts::PreEarlyInitialization() { // Network change notifier factory must be singleton, only set factory // instance while it is not been created.
diff --git a/android_webview/browser/aw_browser_main_parts.h b/android_webview/browser/aw_browser_main_parts.h index 0cb7f4b3..e5eca00 100644 --- a/android_webview/browser/aw_browser_main_parts.h +++ b/android_webview/browser/aw_browser_main_parts.h
@@ -30,7 +30,6 @@ ~AwBrowserMainParts() override; // Overriding methods from content::BrowserMainParts. - bool ShouldContentCreateFeatureList() override; int PreEarlyInitialization() override; int PreCreateThreads() override; void PreMainMessageLoopRun() override;
diff --git a/android_webview/browser/aw_variations_service_client.cc b/android_webview/browser/aw_variations_service_client.cc index 7781ad84..f7e34e9 100644 --- a/android_webview/browser/aw_variations_service_client.cc +++ b/android_webview/browser/aw_variations_service_client.cc
@@ -28,10 +28,6 @@ AwVariationsServiceClient::~AwVariationsServiceClient() {} -std::string AwVariationsServiceClient::GetApplicationLocale() { - return std::string(); -} - base::Callback<base::Version(void)> AwVariationsServiceClient::GetVersionForSimulationCallback() { return base::BindRepeating(&GetVersionForSimulation);
diff --git a/android_webview/browser/aw_variations_service_client.h b/android_webview/browser/aw_variations_service_client.h index 0caf0fd..c313038 100644 --- a/android_webview/browser/aw_variations_service_client.h +++ b/android_webview/browser/aw_variations_service_client.h
@@ -25,7 +25,6 @@ ~AwVariationsServiceClient() override; private: - std::string GetApplicationLocale() override; base::Callback<base::Version(void)> GetVersionForSimulationCallback() override; scoped_refptr<network::SharedURLLoaderFactory> GetURLLoaderFactory() override;
diff --git a/android_webview/lib/aw_main_delegate.cc b/android_webview/lib/aw_main_delegate.cc index 738b904..c01baf6 100644 --- a/android_webview/lib/aw_main_delegate.cc +++ b/android_webview/lib/aw_main_delegate.cc
@@ -304,6 +304,13 @@ logging::CloseLogFile(); } +bool AwMainDelegate::ShouldCreateFeatureList() { + // TODO(https://crbug.com/887468): Move the creation of FeatureList from + // AwBrowserMainParts::PreCreateThreads() to + // AwMainDelegate::PostEarlyInitialization(). + return false; +} + content::ContentBrowserClient* AwMainDelegate::CreateContentBrowserClient() { content_browser_client_.reset(new AwContentBrowserClient()); return content_browser_client_.get();
diff --git a/android_webview/lib/aw_main_delegate.h b/android_webview/lib/aw_main_delegate.h index 4648702..abed40c 100644 --- a/android_webview/lib/aw_main_delegate.h +++ b/android_webview/lib/aw_main_delegate.h
@@ -44,6 +44,7 @@ const std::string& process_type, const content::MainFunctionParams& main_function_params) override; void ProcessExiting(const std::string& process_type) override; + bool ShouldCreateFeatureList() override; content::ContentBrowserClient* CreateContentBrowserClient() override; content::ContentGpuClient* CreateContentGpuClient() override; content::ContentRendererClient* CreateContentRendererClient() override;
diff --git a/base/android/java/src/org/chromium/base/ApplicationStatus.java b/base/android/java/src/org/chromium/base/ApplicationStatus.java index 9496da8..7c8c3584 100644 --- a/base/android/java/src/org/chromium/base/ApplicationStatus.java +++ b/base/android/java/src/org/chromium/base/ApplicationStatus.java
@@ -67,15 +67,6 @@ } } - static { - // Chrome initializes this only for the main process. This assert aims to try and catch - // usages from GPU / renderers, while still allowing tests. - assert ContextUtils.isMainProcess() - || ContextUtils.getProcessName().contains(":test") - : "Cannot use ApplicationState from process: " - + ContextUtils.getProcessName(); - } - private static final Object sCurrentApplicationStateLock = new Object(); @SuppressLint("SupportAnnotationUsage")
diff --git a/base/android/java/src/org/chromium/base/ContextUtils.java b/base/android/java/src/org/chromium/base/ContextUtils.java index 8284cd1..a592ac8 100644 --- a/base/android/java/src/org/chromium/base/ContextUtils.java +++ b/base/android/java/src/org/chromium/base/ContextUtils.java
@@ -168,8 +168,4 @@ throw new RuntimeException(e); } } - - public static boolean isMainProcess() { - return !getProcessName().contains(":"); - } }
diff --git a/base/task/sequence_manager/sequence_manager_impl.cc b/base/task/sequence_manager/sequence_manager_impl.cc index c190c9a..8d9b092 100644 --- a/base/task/sequence_manager/sequence_manager_impl.cc +++ b/base/task/sequence_manager/sequence_manager_impl.cc
@@ -726,6 +726,17 @@ return weak_factory_.GetWeakPtr(); } +bool SequenceManagerImpl::SetCrashKeysAndCheckIsTaskCancelled( + const PendingTask& task) const { +#if !defined(OS_NACL) + debug::SetCrashKeyString(main_thread_only().file_name_crash_key, + task.posted_from.file_name()); + debug::SetCrashKeyString(main_thread_only().function_name_crash_key, + task.posted_from.function_name()); +#endif // OS_NACL + return task.task.IsCancelled(); +} + void SequenceManagerImpl::SetDefaultTaskRunner( scoped_refptr<SingleThreadTaskRunner> task_runner) { controller_->SetDefaultTaskRunner(task_runner);
diff --git a/base/task/sequence_manager/sequence_manager_impl.h b/base/task/sequence_manager/sequence_manager_impl.h index 81b43fe..76d06372 100644 --- a/base/task/sequence_manager/sequence_manager_impl.h +++ b/base/task/sequence_manager/sequence_manager_impl.h
@@ -159,6 +159,9 @@ WeakPtr<SequenceManagerImpl> GetWeakPtr(); + // TODO(alexclarke): Remove when possible. + bool SetCrashKeysAndCheckIsTaskCancelled(const PendingTask& task) const; + protected: // Create a task queue manager where |controller| controls the thread // on which the tasks are eventually run.
diff --git a/base/task/sequence_manager/task_queue_impl.cc b/base/task/sequence_manager/task_queue_impl.cc index 922af436..b1164a7 100644 --- a/base/task/sequence_manager/task_queue_impl.cc +++ b/base/task/sequence_manager/task_queue_impl.cc
@@ -403,10 +403,15 @@ void TaskQueueImpl::WakeUpForDelayedWork(LazyNow* lazy_now) { // Enqueue all delayed tasks that should be running now, skipping any that // have been canceled. + const SequenceManagerImpl* sequence_manager = + main_thread_only().sequence_manager; while (!main_thread_only().delayed_incoming_queue.empty()) { Task& task = const_cast<Task&>(main_thread_only().delayed_incoming_queue.top()); - if (!task.task || task.task.IsCancelled()) { + // TODO(alexclarke): Use IsCancelled once we've understood the bug. + // See http://crbug.com/798554 + if (!task.task || + sequence_manager->SetCrashKeysAndCheckIsTaskCancelled(task)) { main_thread_only().delayed_incoming_queue.pop(); continue; } @@ -855,8 +860,13 @@ // Remove canceled tasks. std::priority_queue<Task> remaining_tasks; + const SequenceManagerImpl* sequence_manager = + main_thread_only().sequence_manager; while (!main_thread_only().delayed_incoming_queue.empty()) { - if (!main_thread_only().delayed_incoming_queue.top().task.IsCancelled()) { + // TODO(alexclarke): Use IsCancelled once we've understood the bug. + // See http://crbug.com/798554 + if (!sequence_manager->SetCrashKeysAndCheckIsTaskCancelled( + main_thread_only().delayed_incoming_queue.top())) { remaining_tasks.push(std::move( const_cast<Task&>(main_thread_only().delayed_incoming_queue.top()))); } @@ -1000,6 +1010,12 @@ main_thread_only().delayed_fence = nullopt; } +void TaskQueueImpl::ClearSequenceManagerForTesting() { + AutoLock lock(any_thread_lock_); + any_thread().sequence_manager = nullptr; + main_thread_only().sequence_manager = nullptr; +} + } // namespace internal } // namespace sequence_manager } // namespace base
diff --git a/base/task/sequence_manager/task_queue_impl.h b/base/task/sequence_manager/task_queue_impl.h index 9036c28..8fcd036 100644 --- a/base/task/sequence_manager/task_queue_impl.h +++ b/base/task/sequence_manager/task_queue_impl.h
@@ -235,6 +235,9 @@ // constructed due to not having TaskQueue. void SetQueueEnabledForTest(bool enabled); + // TODO(alexclarke): Remove when possible. + void ClearSequenceManagerForTesting(); + protected: void SetDelayedWakeUpForTesting(Optional<DelayedWakeUp> wake_up);
diff --git a/base/task/sequence_manager/work_queue.cc b/base/task/sequence_manager/work_queue.cc index 43b5bea..e040bf5 100644 --- a/base/task/sequence_manager/work_queue.cc +++ b/base/task/sequence_manager/work_queue.cc
@@ -4,6 +4,7 @@ #include "base/task/sequence_manager/work_queue.h" +#include "base/task/sequence_manager/sequence_manager_impl.h" #include "base/task/sequence_manager/work_queue_sets.h" namespace base { @@ -155,8 +156,13 @@ bool WorkQueue::RemoveAllCanceledTasksFromFront() { DCHECK(work_queue_sets_); bool task_removed = false; - while (!tasks_.empty() && - (!tasks_.front().task || tasks_.front().task.IsCancelled())) { + const SequenceManagerImpl* sequence_manager = task_queue_->sequence_manager(); + // TODO(alexclarke): Use IsCancelled once we've understood the bug. + // See http://crbug.com/798554 + while ( + !tasks_.empty() && + (!tasks_.front().task || + sequence_manager->SetCrashKeysAndCheckIsTaskCancelled(tasks_.front()))) { tasks_.pop_front(); task_removed = true; }
diff --git a/base/task/sequence_manager/work_queue_unittest.cc b/base/task/sequence_manager/work_queue_unittest.cc index 56bd291..4ada0fa4 100644 --- a/base/task/sequence_manager/work_queue_unittest.cc +++ b/base/task/sequence_manager/work_queue_unittest.cc
@@ -9,6 +9,7 @@ #include "base/bind.h" #include "base/task/sequence_manager/real_time_domain.h" +#include "base/task/sequence_manager/sequence_manager_impl.h" #include "base/task/sequence_manager/task_queue_impl.h" #include "base/task/sequence_manager/work_queue_sets.h" #include "testing/gmock/include/gmock/gmock.h" @@ -34,8 +35,10 @@ class WorkQueueTest : public testing::Test { public: void SetUp() override { + dummy_sequence_manager_ = SequenceManagerImpl::CreateUnbound(nullptr); time_domain_.reset(new RealTimeDomain()); - task_queue_ = std::make_unique<TaskQueueImpl>(nullptr, time_domain_.get(), + task_queue_ = std::make_unique<TaskQueueImpl>(dummy_sequence_manager_.get(), + time_domain_.get(), TaskQueue::Spec("test")); work_queue_.reset(new WorkQueue(task_queue_.get(), "test", @@ -44,7 +47,11 @@ work_queue_sets_->AddQueue(work_queue_.get(), 0); } - void TearDown() override { work_queue_sets_->RemoveQueue(work_queue_.get()); } + void TearDown() override { + work_queue_sets_->RemoveQueue(work_queue_.get()); + + task_queue_->ClearSequenceManagerForTesting(); + } protected: Task FakeCancelableTaskWithEnqueueOrder(int enqueue_order, @@ -71,6 +78,7 @@ return fake_task; } + std::unique_ptr<SequenceManagerImpl> dummy_sequence_manager_; std::unique_ptr<RealTimeDomain> time_domain_; std::unique_ptr<TaskQueueImpl> task_queue_; std::unique_ptr<WorkQueue> work_queue_;
diff --git a/build/config/android/internal_rules.gni b/build/config/android/internal_rules.gni index 7e885e0..3226846 100644 --- a/build/config/android/internal_rules.gni +++ b/build/config/android/internal_rules.gni
@@ -48,17 +48,10 @@ _dexlayout_path = "//third_party/android_build_tools/art/dexlayout" _profman_path = "//third_party/android_build_tools/art/profman" _art_lib_file_names = [ - "libartbased.so", "libartbase.so", "libart-compiler.so", - "libartd-compiler.so", - "libartd-dexlayout.so", - "libartd-disassembler.so", "libart-dexlayout.so", "libart-disassembler.so", - "libartd-simulator-container.so", - "libartd-simulator.so", - "libartd.so", "libart-gtest.so", "libart.so", "libbacktrace.so", @@ -66,7 +59,6 @@ "libcrypto-host.so", "libc++.so", "libcutils.so", - "libdexfiled.so", "libdexfile.so", "libexpat-host.so", "libicui18n-host.so", @@ -79,13 +71,9 @@ "libnativebridge.so", "libnativehelper.so", "libnativeloader.so", - "libopenjdkd.so", - "libopenjdkjvmd.so", "libopenjdkjvm.so", - "libopenjdkjvmtid.so", "libopenjdkjvmti.so", "libopenjdk.so", - "libprofiled.so", "libprofile.so", "libsigchain.so", "libssl-host.so", @@ -1179,11 +1167,11 @@ if (defined(invoker.dexlayout_profile)) { args += [ - "--dexlayout_profile", + "--dexlayout-profile", rebase_path(invoker.dexlayout_profile, root_build_dir), - "--dexlayout_path", + "--dexlayout-path", rebase_path(_dexlayout_path, root_build_dir), - "--profman_path", + "--profman-path", rebase_path(_profman_path, root_build_dir), ] inputs += [
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ChromeApplication.java b/chrome/android/java/src/org/chromium/chrome/browser/ChromeApplication.java index 5d22916..2c9d49527 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/ChromeApplication.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/ChromeApplication.java
@@ -60,12 +60,12 @@ // Quirk: context.getApplicationContext() returns null during this method. @Override protected void attachBaseContext(Context context) { - boolean browserProcess = ContextUtils.isMainProcess(); - if (browserProcess) UmaUtils.recordMainEntryPointTime(); + boolean isBrowserProcess = !ContextUtils.getProcessName().contains(":"); + if (isBrowserProcess) UmaUtils.recordMainEntryPointTime(); super.attachBaseContext(context); ContextUtils.initApplicationContext(this); - if (browserProcess) { + if (isBrowserProcess) { if (BuildConfig.IS_MULTIDEX_ENABLED) { ChromiumMultiDexInstaller.install(this); }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/language/LanguageAskPrompt.java b/chrome/android/java/src/org/chromium/chrome/browser/language/LanguageAskPrompt.java index 25a5dfe..68561730 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/language/LanguageAskPrompt.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/language/LanguageAskPrompt.java
@@ -23,6 +23,7 @@ import org.chromium.chrome.browser.modaldialog.ModalDialogView; import org.chromium.chrome.browser.preferences.PrefServiceBridge; import org.chromium.chrome.browser.preferences.languages.LanguageItem; +import org.chromium.components.language.AndroidLanguageMetricsBridge; import org.chromium.components.language.GeoLanguageProviderBridge; import java.util.ArrayList; @@ -219,6 +220,7 @@ for (String language : languagesToAdd) { PrefServiceBridge.getInstance().updateUserAcceptLanguages(language, true); + AndroidLanguageMetricsBridge.reportExplicitLanguageAskStateChanged(language, true); } HashSet<String> languagesToRemove = new HashSet<String>(mInitialLanguages); @@ -226,6 +228,7 @@ for (String language : languagesToRemove) { PrefServiceBridge.getInstance().updateUserAcceptLanguages(language, false); + AndroidLanguageMetricsBridge.reportExplicitLanguageAskStateChanged(language, false); } }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/widget/bottomsheet/BottomSheet.java b/chrome/android/java/src/org/chromium/chrome/browser/widget/bottomsheet/BottomSheet.java index dab6166..22859bbf 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/widget/bottomsheet/BottomSheet.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/widget/bottomsheet/BottomSheet.java
@@ -12,7 +12,6 @@ import android.content.Context; import android.graphics.Color; import android.graphics.Rect; -import android.graphics.Region; import android.os.Build; import android.support.annotation.IntDef; import android.support.annotation.Nullable; @@ -167,6 +166,9 @@ /** The {@link BottomSheetMetrics} used to record user actions and histograms. */ private final BottomSheetMetrics mMetrics; + /** The view that contains the sheet. */ + private ViewGroup mSheetContainer; + /** For detecting scroll and fling events on the bottom sheet. */ private BottomSheetSwipeDetector mGestureDetector; @@ -511,14 +513,6 @@ return true; } - @Override - public boolean gatherTransparentRegion(Region region) { - // TODO(mdjones): Figure out what this should actually be set to since the view animates - // without necessarily calling this method again. - region.setEmpty(); - return true; - } - /** * @return Whether or not the toolbar Android View is hidden due to being scrolled off-screen. */ @@ -686,6 +680,9 @@ @Override public void onBottomControlsHeightChanged(int bottomControlsHeight) {} }); + + mSheetContainer = (ViewGroup) this.getParent(); + mSheetContainer.removeView(this); } @Override @@ -1099,6 +1096,13 @@ setTranslationY(translationY); + float hiddenHeight = getHiddenRatio() * mContainerHeight; + if (mCurrentOffsetPx <= hiddenHeight && this.getParent() != null) { + mSheetContainer.removeView(this); + } else if (mCurrentOffsetPx > hiddenHeight && this.getParent() == null) { + mSheetContainer.addView(this); + } + float peekHeight = getSheetHeightForState(SheetState.PEEK); boolean isAtPeekingHeight = MathUtils.areFloatsEqual(getCurrentOffsetPx(), peekHeight); if (isSheetOpen() && (getCurrentOffsetPx() < peekHeight || isAtPeekingHeight)) { @@ -1341,8 +1345,6 @@ if (getFocusedChild() == null) requestFocus(); } - setVisibility(mCurrentState == SheetState.HIDDEN ? GONE : VISIBLE); - for (BottomSheetObserver o : mObservers) { o.onSheetStateChanged(mCurrentState); }
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/fullscreen/FullscreenManagerTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/fullscreen/FullscreenManagerTest.java index c5949dd6..2ddafabe 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/fullscreen/FullscreenManagerTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/fullscreen/FullscreenManagerTest.java
@@ -346,14 +346,10 @@ "Failed to reset scrolling state", gestureListenerManager.isScrollInProgress()); } - /** - * TODO(https://crbug.com/876097): Remove the DisableFeatures block turning off contextual - * suggestions. - */ @Test @LargeTest @Feature({"Fullscreen"}) - @Features.DisableFeatures({ChromeFeatureList.CONTEXTUAL_SUGGESTIONS_BUTTON}) + @Features.DisableFeatures({ChromeFeatureList.OFFLINE_INDICATOR}) public void testHidingBrowserControlsRemovesSurfaceFlingerOverlay() throws InterruptedException { FullscreenManagerTestUtils.disableBrowserOverrides();
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/infobar/InfoBarContainerTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/infobar/InfoBarContainerTest.java index 55932af7..6780a30 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/infobar/InfoBarContainerTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/infobar/InfoBarContainerTest.java
@@ -26,14 +26,12 @@ import org.chromium.base.test.util.RetryOnFailure; import org.chromium.chrome.R; import org.chromium.chrome.browser.ChromeActivity; -import org.chromium.chrome.browser.ChromeFeatureList; import org.chromium.chrome.browser.ChromeSwitches; import org.chromium.chrome.browser.preferences.PrefServiceBridge; import org.chromium.chrome.test.ChromeActivityTestRule; import org.chromium.chrome.test.ChromeJUnit4ClassRunner; import org.chromium.chrome.test.util.InfoBarTestAnimationListener; import org.chromium.chrome.test.util.InfoBarUtil; -import org.chromium.chrome.test.util.browser.Features; import org.chromium.content_public.browser.test.util.Criteria; import org.chromium.content_public.browser.test.util.CriteriaHelper; import org.chromium.net.test.EmbeddedTestServer; @@ -288,13 +286,10 @@ /** * Tests that adding and removing correctly manages the transparent region, which allows for * optimizations in SurfaceFlinger (less overlays). - * TODO(https://crbug.com/876097): Remove the DisableFeatures block turning off contextual - * suggestions. */ @Test @MediumTest @Feature({"Browser"}) - @Features.DisableFeatures({ChromeFeatureList.CONTEXTUAL_SUGGESTIONS_BUTTON}) public void testAddAndDismissSurfaceFlingerOverlays() throws Exception { final ViewGroup decorView = (ViewGroup) mActivityTestRule.getActivity().getWindow().getDecorView();
diff --git a/chrome/app/chrome_main_delegate.cc b/chrome/app/chrome_main_delegate.cc index b644568..ba1e3e1 100644 --- a/chrome/app/chrome_main_delegate.cc +++ b/chrome/app/chrome_main_delegate.cc
@@ -512,6 +512,11 @@ chrome_feature_list_creator_->CreateFeatureList(); tracing_sampler_profiler_->OnMessageLoopStarted(); } + +bool ChromeMainDelegate::ShouldCreateFeatureList() { + // Chrome creates the FeatureList, so content should not. + return false; +} #endif bool ChromeMainDelegate::BasicStartupComplete(int* exit_code) { @@ -1163,5 +1168,15 @@ // Initialize NSApplication using the custom subclass. chrome_browser_application_mac::RegisterBrowserCrApp(); + + if (l10n_util::GetLocaleOverride().empty()) { + // The browser process only wants to support the language Cocoa will use, + // so force the app locale to be overridden with that value. This must + // happen before the ResourceBundle is loaded, which happens in + // ChromeBrowserMainParts::PreEarlyInitialization(). + // Don't do this if the locale is already set, which is done by integration + // tests to ensure tests always run with the same locale. + l10n_util::OverrideLocaleWithCocoaLocale(); + } #endif }
diff --git a/chrome/app/chrome_main_delegate.h b/chrome/app/chrome_main_delegate.h index 3508a62..34df18d 100644 --- a/chrome/app/chrome_main_delegate.h +++ b/chrome/app/chrome_main_delegate.h
@@ -16,7 +16,7 @@ #include "ui/base/resource/data_pack.h" #if !defined(CHROME_MULTIPLE_DLL_CHILD) -#include "chrome/browser/chrome_feature_list_creator.h" +#include "chrome/browser/metrics/chrome_feature_list_creator.h" #endif namespace base { @@ -67,6 +67,7 @@ void PreCreateMainMessageLoop() override; #if !defined(CHROME_MULTIPLE_DLL_CHILD) void PostEarlyInitialization() override; + bool ShouldCreateFeatureList() override; #endif content::ContentBrowserClient* CreateContentBrowserClient() override;
diff --git a/chrome/app/chromeos_strings.grdp b/chrome/app/chromeos_strings.grdp index d3c12a2..a70e7b7 100644 --- a/chrome/app/chromeos_strings.grdp +++ b/chrome/app/chromeos_strings.grdp
@@ -3008,9 +3008,6 @@ <message name="IDS_AD_DEVICE_NAME_INPUT_LABEL" desc="Admin-facing. Label for device name input field on the Active Directory domain join screen. User should tell us the name of their device."> Chromebook device name </message> - <message name="IDS_AD_DEVICE_NAME_REGEX_INPUT_LABEL" desc="Admin-facing. Label for device name input field on the Active Directory domain join screen. User should tell us the name of their device."> - Chromebook device name (<ph name="REGEX">$1<ex>^DEVICE_\d+$</ex></ph>) - </message> <message name="IDS_AD_DOMAIN_JOIN_WELCOME_MESSAGE" desc="Admin-facing. Welcome message on the Active Directory domain join screen."> Join device to domain </message>
diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn index 02f71b8..08c23c6 100644 --- a/chrome/browser/BUILD.gn +++ b/chrome/browser/BUILD.gn
@@ -262,8 +262,6 @@ "chrome_content_browser_client_parts.h", "chrome_device_client.cc", "chrome_device_client.h", - "chrome_feature_list_creator.cc", - "chrome_feature_list_creator.h", "chrome_notification_types.h", "chrome_quota_permission_context.cc", "chrome_quota_permission_context.h", @@ -740,6 +738,8 @@ "metrics/chrome_browser_main_extra_parts_metrics.cc", "metrics/chrome_browser_main_extra_parts_metrics.h", "metrics/chrome_browser_main_extra_parts_metrics_mac.mm", + "metrics/chrome_feature_list_creator.cc", + "metrics/chrome_feature_list_creator.h", "metrics/chrome_metrics_service_accessor.cc", "metrics/chrome_metrics_service_accessor.h", "metrics/chrome_metrics_service_client.cc", @@ -1611,6 +1611,8 @@ "usb/usb_chooser_context_factory.h", "usb/usb_chooser_controller.cc", "usb/usb_chooser_controller.h", + "usb/usb_policy_allowed_devices.cc", + "usb/usb_policy_allowed_devices.h", "usb/usb_tab_helper.cc", "usb/usb_tab_helper.h", "usb/web_usb_chooser.cc",
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc index 0dfc9c5..1c1d632 100644 --- a/chrome/browser/about_flags.cc +++ b/chrome/browser/about_flags.cc
@@ -1493,6 +1493,10 @@ flag_descriptions::kDisablePushStateThrottleName, flag_descriptions::kDisablePushStateThrottleDescription, kOsAll, SINGLE_VALUE_TYPE(switches::kDisablePushStateThrottle)}, + {"disable-ipc-flooding-protection", + flag_descriptions::kDisableIpcFloodingProtectionName, + flag_descriptions::kDisableIpcFloodingProtectionDescription, kOsAll, + SINGLE_VALUE_TYPE(switches::kDisableIpcFloodingProtection)}, {"disable-hyperlink-auditing", flag_descriptions::kHyperlinkAuditingName, flag_descriptions::kHyperlinkAuditingDescription, kOsAll, SINGLE_DISABLE_VALUE_TYPE(switches::kNoPings)},
diff --git a/chrome/browser/android/download/available_offline_content_provider_unittest.cc b/chrome/browser/android/download/available_offline_content_provider_unittest.cc index c0f28095..7c9cc063 100644 --- a/chrome/browser/android/download/available_offline_content_provider_unittest.cc +++ b/chrome/browser/android/download/available_offline_content_provider_unittest.cc
@@ -4,6 +4,7 @@ #include "chrome/browser/android/download/available_offline_content_provider.h" +#include "base/bind.h" #include "base/strings/string_util.h" #include "base/test/bind_test_util.h" #include "base/test/scoped_feature_list.h" @@ -97,7 +98,7 @@ // single MockOfflineContentProvider. aggregator_ = static_cast<OfflineContentAggregator*>( OfflineContentAggregatorFactory::GetInstance()->SetTestingFactoryAndUse( - &profile_, &BuildOfflineContentAggregator)); + &profile_, base::BindRepeating(&BuildOfflineContentAggregator))); aggregator_->RegisterProvider(kProviderNamespace, &content_provider_); content_provider_.SetVisuals({}); }
diff --git a/chrome/browser/apps/guest_view/web_view_browsertest.cc b/chrome/browser/apps/guest_view/web_view_browsertest.cc index d08979e..b745568 100644 --- a/chrome/browser/apps/guest_view/web_view_browsertest.cc +++ b/chrome/browser/apps/guest_view/web_view_browsertest.cc
@@ -3293,7 +3293,14 @@ TestHelper("testFindAPI_findupdate", "web_view/shim", NO_TEST_SERVER); } -IN_PROC_BROWSER_TEST_F(WebViewTest, Shim_testFindInMultipleWebViews) { +// TODO(crbug.com/892085): Disabled on Windows due to flakiness. Re-enable. +#if defined(OS_WIN) +#define MAYBE_Shim_testFindInMultipleWebViews \ + DISABLED_Shim_testFindInMultipleWebViews +#else +#define MAYBE_Shim_testFindInMultipleWebViews Shim_testFindInMultipleWebViews +#endif +IN_PROC_BROWSER_TEST_F(WebViewTest, MAYBE_Shim_testFindInMultipleWebViews) { TestHelper("testFindInMultipleWebViews", "web_view/shim", NO_TEST_SERVER); }
diff --git a/chrome/browser/autocomplete/search_provider_unittest.cc b/chrome/browser/autocomplete/search_provider_unittest.cc index dcb987d9..f4c77be 100644 --- a/chrome/browser/autocomplete/search_provider_unittest.cc +++ b/chrome/browser/autocomplete/search_provider_unittest.cc
@@ -8,6 +8,7 @@ #include <string> +#include "base/bind.h" #include "base/command_line.h" #include "base/macros.h" #include "base/metrics/field_trial.h" @@ -294,7 +295,8 @@ // We need both the history service and template url model loaded. ASSERT_TRUE(profile_.CreateHistoryService(true, false)); TemplateURLServiceFactory::GetInstance()->SetTestingFactoryAndUse( - &profile_, &TemplateURLServiceFactory::BuildInstanceFor); + &profile_, + base::BindRepeating(&TemplateURLServiceFactory::BuildInstanceFor)); TemplateURLService* turl_model = TemplateURLServiceFactory::GetForProfile(&profile_); @@ -331,7 +333,8 @@ profile_.BlockUntilHistoryProcessesPendingRequests(); AutocompleteClassifierFactory::GetInstance()->SetTestingFactoryAndUse( - &profile_, &AutocompleteClassifierFactory::BuildInstanceFor); + &profile_, + base::BindRepeating(&AutocompleteClassifierFactory::BuildInstanceFor)); client_.reset( new TestAutocompleteProviderClient(&profile_, &test_url_loader_factory_));
diff --git a/chrome/browser/autocomplete/shortcuts_provider_extension_unittest.cc b/chrome/browser/autocomplete/shortcuts_provider_extension_unittest.cc index 467e680..2594236 100644 --- a/chrome/browser/autocomplete/shortcuts_provider_extension_unittest.cc +++ b/chrome/browser/autocomplete/shortcuts_provider_extension_unittest.cc
@@ -8,6 +8,7 @@ #include <string> #include <vector> +#include "base/bind.h" #include "base/macros.h" #include "base/memory/ref_counted.h" #include "base/run_loop.h" @@ -67,7 +68,9 @@ void ShortcutsProviderExtensionTest::SetUp() { ShortcutsBackendFactory::GetInstance()->SetTestingFactoryAndUse( - &profile_, &ShortcutsBackendFactory::BuildProfileNoDatabaseForTesting); + &profile_, + base::BindRepeating( + &ShortcutsBackendFactory::BuildProfileNoDatabaseForTesting)); backend_ = ShortcutsBackendFactory::GetForProfile(&profile_); ASSERT_TRUE(backend_.get()); ASSERT_TRUE(profile_.CreateHistoryService(true, false));
diff --git a/chrome/browser/browser_process_impl.cc b/chrome/browser/browser_process_impl.cc index 25b184cd..827c58d2 100644 --- a/chrome/browser/browser_process_impl.cc +++ b/chrome/browser/browser_process_impl.cc
@@ -38,7 +38,6 @@ #include "chrome/browser/chrome_child_process_watcher.h" #include "chrome/browser/chrome_content_browser_client.h" #include "chrome/browser/chrome_device_client.h" -#include "chrome/browser/chrome_feature_list_creator.h" #include "chrome/browser/chrome_notification_types.h" #include "chrome/browser/component_updater/chrome_component_updater_configurator.h" #include "chrome/browser/component_updater/supervised_user_whitelist_installer.h" @@ -56,6 +55,7 @@ #include "chrome/browser/loader/chrome_resource_dispatcher_host_delegate.h" #include "chrome/browser/media/webrtc/webrtc_event_log_manager.h" #include "chrome/browser/media/webrtc/webrtc_log_uploader.h" +#include "chrome/browser/metrics/chrome_feature_list_creator.h" #include "chrome/browser/metrics/chrome_metrics_service_accessor.h" #include "chrome/browser/metrics/chrome_metrics_services_manager_client.h" #include "chrome/browser/metrics/thread_watcher.h" @@ -96,6 +96,7 @@ #include "components/metrics/metrics_pref_names.h" #include "components/metrics/metrics_service.h" #include "components/metrics_services_manager/metrics_services_manager.h" +#include "components/metrics_services_manager/metrics_services_manager_client.h" #include "components/net_log/chrome_net_log.h" #include "components/network_time/network_time_tracker.h" #include "components/optimization_guide/optimization_guide_service.h" @@ -219,10 +220,16 @@ BrowserProcessImpl::BrowserProcessImpl( ChromeFeatureListCreator* chrome_feature_list_creator) - : chrome_feature_list_creator_(chrome_feature_list_creator), - pref_service_factory_( - std::make_unique<prefs::InProcessPrefServiceFactory>()) { + : chrome_feature_list_creator_(chrome_feature_list_creator) { g_browser_process = this; + + DCHECK(chrome_feature_list_creator_); + browser_policy_connector_ = + chrome_feature_list_creator_->TakeChromeBrowserPolicyConnector(); + created_browser_policy_connector_ = true; + pref_service_factory_ = + chrome_feature_list_creator_->TakePrefServiceFactory(); + platform_part_ = std::make_unique<BrowserProcessPlatformPart>(); // Most work should be done in Init(). } @@ -461,6 +468,14 @@ } #endif // !defined(OS_ANDROID) +void BrowserProcessImpl::SetMetricsServices( + std::unique_ptr<metrics_services_manager::MetricsServicesManager> manager, + metrics_services_manager::MetricsServicesManagerClient* client) { + metrics_services_manager_ = std::move(manager); + metrics_services_manager_client_ = + static_cast<ChromeMetricsServicesManagerClient*>(client); +} + namespace { // Used at the end of session to block the UI thread for completion of sentinel @@ -1117,33 +1132,8 @@ void BrowserProcessImpl::CreateLocalState() { DCHECK(!local_state_); - base::FilePath local_state_path; - CHECK(base::PathService::Get(chrome::FILE_LOCAL_STATE, &local_state_path)); - - auto pref_registry = base::MakeRefCounted<PrefRegistrySimple>(); - if (chrome_feature_list_creator_) - local_state_ = chrome_feature_list_creator_->TakePrefService(); - PrefRegistrySimple* pref_pregistry_simple = - local_state_ ? static_cast<PrefRegistrySimple*>( - local_state_->DeprecatedGetPrefRegistry()) - : pref_registry.get(); - - // Register local state preferences. - RegisterLocalState(pref_pregistry_simple); - - auto delegate = pref_service_factory_->CreateDelegate(); - delegate->InitPrefRegistry(pref_pregistry_simple); - if (local_state_) { - chrome_prefs::InstallPoliciesOnLocalState( - local_state_.get(), policy_service(), std::move(delegate)); - } else { - local_state_ = chrome_prefs::CreateLocalState( - local_state_path, policy_service(), std::move(pref_registry), false, - std::move(delegate)); - DCHECK(local_state_); - } - - sessions::SessionIdGenerator::GetInstance()->Init(local_state_.get()); + local_state_ = chrome_feature_list_creator_->TakePrefService(); + DCHECK(local_state_); } void BrowserProcessImpl::PreCreateThreads(
diff --git a/chrome/browser/browser_process_impl.h b/chrome/browser/browser_process_impl.h index 9d7174d1..8799ad3 100644 --- a/chrome/browser/browser_process_impl.h +++ b/chrome/browser/browser_process_impl.h
@@ -24,6 +24,7 @@ #include "chrome/browser/browser_process.h" #include "chrome/common/buildflags.h" #include "components/keep_alive_registry/keep_alive_state_observer.h" +#include "components/metrics_services_manager/metrics_services_manager.h" #include "components/nacl/common/buildflags.h" #include "components/prefs/persistent_pref_store.h" #include "components/prefs/pref_change_registrar.h" @@ -80,9 +81,9 @@ class BrowserProcessImpl : public BrowserProcess, public KeepAliveStateObserver { public: - // |user_pref_store|: if non-null, will be used as the source (and - // destination) of user prefs for Local State instead of loading the JSON file - // from disk. + // |chrome_feature_list_creator| should not be null. The BrowserProcessImpl + // will take the PrefService owned by the creator as the Local State instead + // of loading the JSON file from disk. explicit BrowserProcessImpl( ChromeFeatureListCreator* chrome_feature_list_creator); ~BrowserProcessImpl() override; @@ -124,6 +125,12 @@ void PostDestroyThreads(); #endif + // Sets |metrics_services_manager_| and |metrics_services_manager_client_| + // which is owned by it. + void SetMetricsServices( + std::unique_ptr<metrics_services_manager::MetricsServicesManager> manager, + metrics_services_manager::MetricsServicesManagerClient* client); + // BrowserProcess implementation. void ResourceDispatcherHostCreated() override; void EndSession() override;
diff --git a/chrome/browser/chrome_browser_main.cc b/chrome/browser/chrome_browser_main.cc index 2fcd8a2..00b7b81b 100644 --- a/chrome/browser/chrome_browser_main.cc +++ b/chrome/browser/chrome_browser_main.cc
@@ -54,7 +54,6 @@ #include "chrome/browser/browser_process_platform_part.h" #include "chrome/browser/chrome_browser_field_trials.h" #include "chrome/browser/chrome_browser_main_extra_parts.h" -#include "chrome/browser/chrome_feature_list_creator.h" #include "chrome/browser/component_updater/crl_set_component_installer.h" #include "chrome/browser/component_updater/file_type_policies_component_installer.h" #include "chrome/browser/component_updater/mei_preload_component_installer.h" @@ -72,6 +71,7 @@ #include "chrome/browser/lifetime/browser_shutdown.h" #include "chrome/browser/media/webrtc/media_capture_devices_dispatcher.h" #include "chrome/browser/media/webrtc/webrtc_log_util.h" +#include "chrome/browser/metrics/chrome_feature_list_creator.h" #include "chrome/browser/metrics/chrome_metrics_service_accessor.h" #include "chrome/browser/metrics/expired_histograms_array.h" #include "chrome/browser/metrics/field_trial_synchronizer.h" @@ -409,9 +409,10 @@ registry->RegisterStringPref(language::prefs::kApplicationLocale, std::string()); const std::unique_ptr<PrefService> parent_local_state = - chrome_prefs::CreateLocalState(parent_profile, - g_browser_process->policy_service(), - std::move(registry), false, nullptr); + chrome_prefs::CreateLocalState( + parent_profile, g_browser_process->policy_service(), + std::move(registry), false, nullptr, + g_browser_process->browser_policy_connector()); // Right now, we only inherit the locale setting from the parent profile. local_state->SetString( language::prefs::kApplicationLocale, @@ -434,24 +435,6 @@ #endif // defined(OS_CHROMEOS) } -void ConvertFlagsToSwitches() { -#if !defined(OS_CHROMEOS) - // Convert active flags into switches. This needs to be done before - // ui::ResourceBundle::InitSharedInstanceWithLocale as some loaded resources - // are affected by experiment flags (--touch-optimized-ui in particular). On - // ChromeOS system level flags are applied from the device settings from the - // session manager. - DCHECK(!ui::ResourceBundle::HasSharedInstance()); - TRACE_EVENT0("startup", - "ChromeBrowserMainParts::PreCreateThreadsImpl:ConvertFlags"); - flags_ui::PrefServiceFlagsStorage flags_storage( - g_browser_process->local_state()); - about_flags::ConvertFlagsToSwitches(&flags_storage, - base::CommandLine::ForCurrentProcess(), - flags_ui::kAddSentinels); -#endif // !defined(OS_CHROMEOS) -} - // Initializes the primary profile, possibly doing some user prompting to pick // a fallback profile. Returns the newly created profile, or NULL if startup // should not continue. @@ -830,44 +813,6 @@ chrome_extra_parts_.clear(); } -void ChromeBrowserMainParts::SetupFieldTrials() { - // Initialize FieldTrialList to support FieldTrials. This is intentionally - // leaked since it needs to live for the duration of the browser process and - // there's no benefit in cleaning it up at exit. - base::FieldTrialList* leaked_field_trial_list = new base::FieldTrialList( - browser_process_->GetMetricsServicesManager()->CreateEntropyProvider()); - ANNOTATE_LEAKING_OBJECT_PTR(leaked_field_trial_list); - ignore_result(leaked_field_trial_list); - - auto feature_list = std::make_unique<base::FeatureList>(); - - // Associate parameters chosen in about:flags and create trial/group for them. - flags_ui::PrefServiceFlagsStorage flags_storage( - g_browser_process->local_state()); - std::vector<std::string> variation_ids = - about_flags::RegisterAllFeatureVariationParameters( - &flags_storage, feature_list.get()); - - std::set<std::string> unforceable_field_trials; -#if defined(OFFICIAL_BUILD) - unforceable_field_trials.insert("SettingsEnforcement"); -#endif // defined(OFFICIAL_BUILD) - - variations::VariationsService* variations_service = - browser_process_->variations_service(); - variations_service->SetupFieldTrials( - cc::switches::kEnableGpuBenchmarking, switches::kEnableFeatures, - switches::kDisableFeatures, unforceable_field_trials, variation_ids, - std::move(feature_list), &browser_field_trials_); - variations::InitCrashKeys(); - - // Initialize FieldTrialSynchronizer system. This is a singleton and is used - // for posting tasks via base::Bind. Its deleted when it goes out of scope. - // Even though base::Bind does AddRef and Release, the object will not be - // deleted after the Task is executed. - field_trial_synchronizer_ = new FieldTrialSynchronizer(); -} - void ChromeBrowserMainParts::SetupMetrics() { TRACE_EVENT0("startup", "ChromeBrowserMainParts::SetupMetrics"); metrics::MetricsService* metrics = browser_process_->metrics_service(); @@ -996,11 +941,6 @@ // content::BrowserMainParts implementation ------------------------------------ -bool ChromeBrowserMainParts::ShouldContentCreateFeatureList() { - // Chrome creates the FeatureList, so no need for content to do the same. - return false; -} - int ChromeBrowserMainParts::PreEarlyInitialization() { TRACE_EVENT0("startup", "ChromeBrowserMainParts::PreEarlyInitialization"); for (size_t i = 0; i < chrome_extra_parts_.size(); ++i) @@ -1014,6 +954,13 @@ bool failed_to_load_resource_bundle = false; const int load_local_state_result = LoadLocalState(&failed_to_load_resource_bundle); + + // Reuses the MetricsServicesManager and GetMetricsServicesManagerClient + // instances created in the FeatureListCreator so they won't be created again. + browser_process_->SetMetricsServices( + chrome_feature_list_creator_->TakeMetricsServicesManager(), + chrome_feature_list_creator_->GetMetricsServicesManagerClient()); + if (load_local_state_result == chrome::RESULT_CODE_MISSING_DATA && failed_to_load_resource_bundle) { if (base::CommandLine::ForCurrentProcess()->HasSwitch( @@ -1097,8 +1044,6 @@ InitializeLocalState(); - ConvertFlagsToSwitches(); - browser_process_->local_state()->UpdateCommandLinePrefStore( new ChromeCommandLinePrefStore(base::CommandLine::ForCurrentProcess())); @@ -1124,14 +1069,6 @@ SetupOriginTrialsCommandLine(browser_process_->local_state()); - // Initialize field trials now that the Local State file has been read. This - // is done as soon as possible (here), so that code using the base::Feature - // API can be used from this point on. Field trials are also needed by - // IOThread's initialization in BrowserProcess:PreCreateThreads. Metrics - // initialization is handled in PreMainMessageLoopRunImpl since it posts - // tasks. - SetupFieldTrials(); - metrics::EnableExpiryChecker(chrome_metrics::kExpiredHistogramsHashes, chrome_metrics::kNumExpiredHistograms);
diff --git a/chrome/browser/chrome_browser_main.h b/chrome/browser/chrome_browser_main.h index ea6c75d..52239138 100644 --- a/chrome/browser/chrome_browser_main.h +++ b/chrome/browser/chrome_browser_main.h
@@ -21,7 +21,6 @@ class BrowserProcessImpl; class ChromeBrowserMainExtraParts; class ChromeFeatureListCreator; -class FieldTrialSynchronizer; class HeapProfilerController; class PrefService; class Profile; @@ -62,7 +61,6 @@ ChromeFeatureListCreator* chrome_feature_list_creator); // content::BrowserMainParts overrides. - bool ShouldContentCreateFeatureList() override; // These are called in-order by content::BrowserMainLoop. // Each stage calls the same stages in any ChromeBrowserMainExtraParts added // with AddParts() from ChromeContentBrowserClient::CreateBrowserMainParts. @@ -106,10 +104,6 @@ private: friend class ChromeBrowserMainPartsTestApi; - // Sets up the field trials and related initialization. Call only after - // about:flags have been converted to switches. - void SetupFieldTrials(); - // Constructs the metrics service and initializes metrics recording. void SetupMetrics(); @@ -204,9 +198,6 @@ Profile* profile_; bool run_message_loop_; - // Initialized in |SetupFieldTrials()|. - scoped_refptr<FieldTrialSynchronizer> field_trial_synchronizer_; - base::FilePath user_data_dir_; // This is used to store the ui data pack. The data pack is moved when
diff --git a/chrome/browser/chrome_browser_main_mac.mm b/chrome/browser/chrome_browser_main_mac.mm index 450966a..1835aa3 100644 --- a/chrome/browser/chrome_browser_main_mac.mm +++ b/chrome/browser/chrome_browser_main_mac.mm
@@ -35,7 +35,6 @@ #include "components/os_crypt/os_crypt.h" #include "content/public/common/main_function_params.h" #include "content/public/common/result_codes.h" -#include "ui/base/l10n/l10n_util_mac.h" #include "ui/base/resource/resource_bundle.h" #include "ui/base/resource/resource_handle.h" @@ -89,15 +88,6 @@ singleton_command_line->AppendSwitch(switches::kNoStartupWindow); } - // If ui_task is not NULL, the app is actually a browser_test. - if (!parameters().ui_task) { - // The browser process only wants to support the language Cocoa will use, - // so force the app locale to be overriden with that value. This must - // happen before the ResourceBundle is loaded, which happens in - // ChromeBrowserMainParts::PreEarlyInitialization(). - l10n_util::OverrideLocaleWithCocoaLocale(); - } - return ChromeBrowserMainPartsPosix::PreEarlyInitialization(); }
diff --git a/chrome/browser/chrome_content_browser_client.cc b/chrome/browser/chrome_content_browser_client.cc index c79f73f8..a71e301 100644 --- a/chrome/browser/chrome_content_browser_client.cc +++ b/chrome/browser/chrome_content_browser_client.cc
@@ -4601,9 +4601,9 @@ return; if (!SystemNetworkContextManager::GetInstance()) { DCHECK(!g_browser_process); - DCHECK(chrome_feature_list_creator_->simple_local_state()); + DCHECK(chrome_feature_list_creator_->local_state()); SystemNetworkContextManager::CreateInstance( - chrome_feature_list_creator_->simple_local_state()); + chrome_feature_list_creator_->local_state()); } // Need to set up global NetworkService state before anything else uses it. SystemNetworkContextManager::GetInstance()->OnNetworkServiceCreated(
diff --git a/chrome/browser/chrome_content_browser_client.h b/chrome/browser/chrome_content_browser_client.h index 30a59ea..7e41e4c 100644 --- a/chrome/browser/chrome_content_browser_client.h +++ b/chrome/browser/chrome_content_browser_client.h
@@ -18,8 +18,8 @@ #include "base/memory/ref_counted.h" #include "base/memory/weak_ptr.h" #include "build/build_config.h" -#include "chrome/browser/chrome_feature_list_creator.h" #include "chrome/browser/chrome_service.h" +#include "chrome/browser/metrics/chrome_feature_list_creator.h" #include "content/public/browser/content_browser_client.h" #include "content/public/common/resource_type.h" #include "extensions/buildflags/buildflags.h"
diff --git a/chrome/browser/chrome_feature_list_creator.cc b/chrome/browser/chrome_feature_list_creator.cc deleted file mode 100644 index 486de8f..0000000 --- a/chrome/browser/chrome_feature_list_creator.cc +++ /dev/null
@@ -1,57 +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/chrome_feature_list_creator.h" - -#include "base/files/file_path.h" -#include "base/files/file_util.h" -#include "base/path_service.h" -#include "chrome/browser/prefs/chrome_command_line_pref_store.h" -#include "chrome/browser/prefs/chrome_pref_service_factory.h" -#include "chrome/common/chrome_paths.h" -#include "components/prefs/json_pref_store.h" -#include "components/prefs/pref_registry.h" -#include "components/prefs/pref_registry_simple.h" -#include "components/prefs/pref_service_factory.h" -#include "components/variations/pref_names.h" - -ChromeFeatureListCreator::ChromeFeatureListCreator() = default; -ChromeFeatureListCreator::~ChromeFeatureListCreator() = default; - -void ChromeFeatureListCreator::CreatePrefService() { - base::FilePath local_state_file; - bool result = - base::PathService::Get(chrome::FILE_LOCAL_STATE, &local_state_file); - DCHECK(result); - - pref_store_ = base::MakeRefCounted<JsonPrefStore>(local_state_file); - pref_store_->ReadPrefs(); - - PrefServiceFactory factory; - factory.set_user_prefs(pref_store_); - factory.set_command_line_prefs( - base::MakeRefCounted<ChromeCommandLinePrefStore>( - base::CommandLine::ForCurrentProcess())); - factory.set_read_error_callback(base::BindRepeating( - &chrome_prefs::HandlePersistentPrefStoreReadError, local_state_file)); - scoped_refptr<PrefRegistry> registry = new PrefRegistrySimple(); - simple_local_state_ = factory.Create(registry); -} - -scoped_refptr<PersistentPrefStore> ChromeFeatureListCreator::GetPrefStore() { - return pref_store_; -} - -std::unique_ptr<PrefService> ChromeFeatureListCreator::TakePrefService() { - return std::move(simple_local_state_); -} - -void ChromeFeatureListCreator::CreateFeatureList() { - CreatePrefService(); - // TODO(hanxi): Add implementation to create feature list. -} - -void ChromeFeatureListCreator::CreatePrefServiceForTesting() { - CreatePrefService(); -}
diff --git a/chrome/browser/chrome_feature_list_creator.h b/chrome/browser/chrome_feature_list_creator.h deleted file mode 100644 index f39e211..0000000 --- a/chrome/browser/chrome_feature_list_creator.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_CHROME_FEATURE_LIST_CREATOR_H_ -#define CHROME_BROWSER_CHROME_FEATURE_LIST_CREATOR_H_ - -#include "base/macros.h" -#include "components/prefs/pref_service.h" - -// Responsible for creating feature list and all its necessary parameters. -// This class is currently WIP and doesn't do what it's meant to do. -// TODO(hanxi): Finish implementation, https://crbug.com/848615. -class ChromeFeatureListCreator { - public: - ChromeFeatureListCreator(); - ~ChromeFeatureListCreator(); - - // Gets the pref store that is used to create feature list. - scoped_refptr<PersistentPrefStore> GetPrefStore(); - - // Passing ownership of the |simple_local_state_| to the caller. - std::unique_ptr<PrefService> TakePrefService(); - - // Initializes all necessary parameters to create the feature list and calls - // base::FeatureList::SetInstance() to set the global instance. - void CreateFeatureList(); - - void CreatePrefServiceForTesting(); - - PrefService* simple_local_state() { return simple_local_state_.get(); } - - private: - void CreatePrefService(); - - scoped_refptr<PersistentPrefStore> pref_store_; - - // If TakePrefService() is called, the caller will take the ownership - // of this variable. Stop using this variable afterwards. - std::unique_ptr<PrefService> simple_local_state_; - - DISALLOW_COPY_AND_ASSIGN(ChromeFeatureListCreator); -}; - -#endif // CHROME_BROWSER_CHROME_FEATURE_LIST_CREATOR_H_
diff --git a/chrome/browser/chromeos/BUILD.gn b/chrome/browser/chromeos/BUILD.gn index 3577fa4..232a328 100644 --- a/chrome/browser/chromeos/BUILD.gn +++ b/chrome/browser/chromeos/BUILD.gn
@@ -619,6 +619,8 @@ "dbus/chrome_features_service_provider.h", "dbus/component_updater_service_provider.cc", "dbus/component_updater_service_provider.h", + "dbus/dbus_helper.cc", + "dbus/dbus_helper.h", "dbus/drive_file_stream_service_provider.cc", "dbus/drive_file_stream_service_provider.h", "dbus/kiosk_info_service_provider.cc",
diff --git a/chrome/browser/chromeos/arc/arc_play_store_enabled_preference_handler_unittest.cc b/chrome/browser/chromeos/arc/arc_play_store_enabled_preference_handler_unittest.cc index 5f5cec4..88055d3 100644 --- a/chrome/browser/chromeos/arc/arc_play_store_enabled_preference_handler_unittest.cc +++ b/chrome/browser/chromeos/arc/arc_play_store_enabled_preference_handler_unittest.cc
@@ -6,6 +6,7 @@ #include <memory> +#include "base/bind.h" #include "base/command_line.h" #include "base/files/scoped_temp_dir.h" #include "base/run_loop.h" @@ -64,8 +65,9 @@ TestingProfile::Builder profile_builder; profile_builder.SetProfileName(kTestProfileName); profile_builder.SetPath(temp_dir_.GetPath().AppendASCII("TestArcProfile")); - profile_builder.AddTestingFactory(ConsentAuditorFactory::GetInstance(), - BuildFakeConsentAuditor); + profile_builder.AddTestingFactory( + ConsentAuditorFactory::GetInstance(), + base::BindRepeating(&BuildFakeConsentAuditor)); profile_ = profile_builder.Build(); arc_session_manager_ = std::make_unique<ArcSessionManager>(
diff --git a/chrome/browser/chromeos/arc/arc_session_manager_browsertest.cc b/chrome/browser/chromeos/arc/arc_session_manager_browsertest.cc index 20a131ad..5dab0be2 100644 --- a/chrome/browser/chromeos/arc/arc_session_manager_browsertest.cc +++ b/chrome/browser/chromeos/arc/arc_session_manager_browsertest.cc
@@ -6,6 +6,7 @@ #include <string> #include "base/auto_reset.h" +#include "base/bind.h" #include "base/command_line.h" #include "base/files/file_path.h" #include "base/files/scoped_temp_dir.h" @@ -144,7 +145,7 @@ profile_builder.SetProfileName(kFakeUserName); profile_builder.AddTestingFactory( ProfileOAuth2TokenServiceFactory::GetInstance(), - BuildFakeProfileOAuth2TokenService); + base::BindRepeating(&BuildFakeProfileOAuth2TokenService)); profile_ = profile_builder.Build(); token_service_ = static_cast<FakeProfileOAuth2TokenService*>( ProfileOAuth2TokenServiceFactory::GetForProfile(profile()));
diff --git a/chrome/browser/chromeos/arc/auth/arc_auth_service_browsertest.cc b/chrome/browser/chromeos/arc/auth/arc_auth_service_browsertest.cc index b9c3917..86a8234 100644 --- a/chrome/browser/chromeos/arc/auth/arc_auth_service_browsertest.cc +++ b/chrome/browser/chromeos/arc/auth/arc_auth_service_browsertest.cc
@@ -194,9 +194,10 @@ profile_builder.AddTestingFactory( ProfileOAuth2TokenServiceFactory::GetInstance(), - BuildFakeProfileOAuth2TokenService); - profile_builder.AddTestingFactory(SigninManagerFactory::GetInstance(), - BuildFakeSigninManagerBase); + base::BindRepeating(&BuildFakeProfileOAuth2TokenService)); + profile_builder.AddTestingFactory( + SigninManagerFactory::GetInstance(), + base::BindRepeating(&BuildFakeSigninManagerBase)); if (user_type == user_manager::USER_TYPE_CHILD) profile_builder.SetSupervisedUserId(supervised_users::kChildAccountSUID);
diff --git a/chrome/browser/chromeos/chrome_browser_main_chromeos.cc b/chrome/browser/chromeos/chrome_browser_main_chromeos.cc index d99c269..0727e77 100644 --- a/chrome/browser/chromeos/chrome_browser_main_chromeos.cc +++ b/chrome/browser/chromeos/chrome_browser_main_chromeos.cc
@@ -47,6 +47,7 @@ #include "chrome/browser/chromeos/boot_times_recorder.h" #include "chrome/browser/chromeos/dbus/chrome_features_service_provider.h" #include "chrome/browser/chromeos/dbus/component_updater_service_provider.h" +#include "chrome/browser/chromeos/dbus/dbus_helper.h" #include "chrome/browser/chromeos/dbus/drive_file_stream_service_provider.h" #include "chrome/browser/chromeos/dbus/kiosk_info_service_provider.h" #include "chrome/browser/chromeos/dbus/metrics_event_service_provider.h" @@ -286,33 +287,6 @@ namespace internal { -// Contains state created in PreEarlyInitialization(). This is just the state -// needed for field trials. -class DBusPreEarlyInit { - public: - DBusPreEarlyInit() { - SystemSaltGetter::Initialize(); - - // Initialize DBusThreadManager for the browser. - DBusThreadManager::Initialize(DBusThreadManager::kAll); - - // Initialize the device settings service so that we'll take actions per - // signals sent from the session manager. This needs to happen before - // g_browser_process initializes BrowserPolicyConnector. - DeviceSettingsService::Initialize(); - InstallAttributes::Initialize(); - } - - ~DBusPreEarlyInit() { - // NOTE: This must only be called if Initialize() was called. - DBusThreadManager::Shutdown(); - SystemSaltGetter::Shutdown(); - } - - private: - DISALLOW_COPY_AND_ASSIGN(DBusPreEarlyInit); -}; - // Wrapper class for initializing D-Bus services and shutting them down. class DBusServices { public: @@ -549,7 +523,8 @@ ChromeFeatureListCreator* chrome_feature_list_creator) : ChromeBrowserMainPartsLinux(parameters, std::move(data_pack), - chrome_feature_list_creator) {} + chrome_feature_list_creator), + is_dbus_initialized_(chrome_feature_list_creator != nullptr) {} ChromeBrowserMainPartsChromeos::~ChromeBrowserMainPartsChromeos() { // To be precise, logout (browser shutdown) is not yet done, but the @@ -600,7 +575,8 @@ chrome::SetChannel(channel); #endif - dbus_pre_early_init_ = std::make_unique<internal::DBusPreEarlyInit>(); + if (!is_dbus_initialized_) + PreEarlyInitDBus(); if (!base::SysInfo::IsRunningOnChromeOS() && parsed_command_line().HasSwitch( @@ -1213,7 +1189,7 @@ // (ComponentUpdaterServiceProvider). g_browser_process->platform_part()->ShutdownCrosComponentManager(); - dbus_pre_early_init_.reset(); + ShutdownDBus(); // Reset SystemTokenCertDBInitializer after DBus services because it should // outlive CertLoader.
diff --git a/chrome/browser/chromeos/chrome_browser_main_chromeos.h b/chrome/browser/chromeos/chrome_browser_main_chromeos.h index 365d5b4..5940c06 100644 --- a/chrome/browser/chromeos/chrome_browser_main_chromeos.h +++ b/chrome/browser/chromeos/chrome_browser_main_chromeos.h
@@ -51,7 +51,6 @@ namespace internal { -class DBusPreEarlyInit; class DBusServices; class SystemTokenCertDBInitializer; } @@ -99,7 +98,9 @@ std::unique_ptr<WakeOnWifiManager> wake_on_wifi_manager_; std::unique_ptr<NetworkThrottlingObserver> network_throttling_observer_; - std::unique_ptr<internal::DBusPreEarlyInit> dbus_pre_early_init_; + // Indicates whether the DBus has been initialized before. It is possible that + // the DBus has been initialized in ChromeFeatureListCreator. + bool is_dbus_initialized_ = false; std::unique_ptr<internal::DBusServices> dbus_services_; std::unique_ptr<internal::SystemTokenCertDBInitializer>
diff --git a/chrome/browser/chromeos/dbus/dbus_helper.cc b/chrome/browser/chromeos/dbus/dbus_helper.cc new file mode 100644 index 0000000..e83fd6e --- /dev/null +++ b/chrome/browser/chromeos/dbus/dbus_helper.cc
@@ -0,0 +1,33 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/chromeos/dbus/dbus_helper.h" + +#include "chrome/browser/chromeos/settings/device_settings_service.h" +#include "chrome/browser/chromeos/settings/install_attributes.h" +#include "chromeos/cryptohome/system_salt_getter.h" +#include "chromeos/dbus/dbus_thread_manager.h" + +namespace chromeos { + +void PreEarlyInitDBus() { + SystemSaltGetter::Initialize(); + + // Initialize DBusThreadManager for the browser. + DBusThreadManager::Initialize(DBusThreadManager::kAll); + + // Initialize the device settings service so that we'll take actions per + // signals sent from the session manager. This needs to happen before + // g_browser_process initializes BrowserPolicyConnector. + DeviceSettingsService::Initialize(); + InstallAttributes::Initialize(); +} + +void ShutdownDBus() { + // NOTE: This must only be called if Initialize() was called. + DBusThreadManager::Shutdown(); + SystemSaltGetter::Shutdown(); +} + +} // namespace chromeos
diff --git a/chrome/browser/chromeos/dbus/dbus_helper.h b/chrome/browser/chromeos/dbus/dbus_helper.h new file mode 100644 index 0000000..f3f390c --- /dev/null +++ b/chrome/browser/chromeos/dbus/dbus_helper.h
@@ -0,0 +1,18 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_CHROMEOS_DBUS_DBUS_HELPER_H_ +#define CHROME_BROWSER_CHROMEOS_DBUS_DBUS_HELPER_H_ + +namespace chromeos { + +// Creates state needed for field trials. +void PreEarlyInitDBus(); + +// Shutdowns things initialized in the PreEarlyInitDBus(). +void ShutdownDBus(); + +} // namespace chromeos + +#endif // CHROME_BROWSER_CHROMEOS_DBUS_DBUS_HELPER_H_
diff --git a/chrome/browser/chromeos/login/active_directory_login_browsertest.cc b/chrome/browser/chromeos/login/active_directory_login_browsertest.cc index e4dc7d2..6883b261 100644 --- a/chrome/browser/chromeos/login/active_directory_login_browsertest.cc +++ b/chrome/browser/chromeos/login/active_directory_login_browsertest.cc
@@ -73,7 +73,7 @@ // Using the same realm as supervised user domain. Should be treated as // normal realm. test_realm_(user_manager::kSupervisedUserDomain), - autocomplete_realm_(test_realm_) {} + test_user_(kTestActiveDirectoryUser + ("@" + test_realm_)) {} ~ActiveDirectoryLoginTest() override = default; @@ -110,8 +110,7 @@ void MarkAsActiveDirectoryEnterprise() { StartupUtils::MarkOobeCompleted(); - active_directory_test_helper::PrepareLogin(kTestActiveDirectoryUser + - ("@" + test_realm_)); + active_directory_test_helper::PrepareLogin(test_user_); } void TriggerPasswordChangeScreen() { @@ -120,7 +119,7 @@ fake_auth_policy_client()->set_auth_error( authpolicy::ERROR_PASSWORD_EXPIRED); - SubmitActiveDirectoryCredentials(kTestActiveDirectoryUser, kPassword); + SubmitActiveDirectoryCredentials(test_user_, kPassword); screen_waiter.Wait(); TestAdPasswordChangeError(std::string()); } @@ -157,7 +156,7 @@ JSElement(kAdOfflineAuthId, kAdAutocompleteRealm) + innerText), base::kWhitespaceASCII, &autocomplete_domain_ui); // Checks if realm is set to autocomplete username. - EXPECT_EQ("@" + autocomplete_realm_, autocomplete_domain_ui); + EXPECT_EQ(autocomplete_realm_, autocomplete_domain_ui); // Checks if bottom bar is visible. JSExpect("!Oobe.getInstance().headerHidden"); @@ -180,6 +179,16 @@ JSExpect(JSElement(kAdOfflineAuthId, kAdUserInput) + ".invalid"); } + void SetUserInput(const std::string& value) { + js_checker().ExecuteAsync(JSElement(kAdOfflineAuthId, kAdUserInput) + + ".value='" + value + "'"); + } + + void TestUserInput(const std::string& value) { + js_checker().ExpectEQ(JSElement(kAdOfflineAuthId, kAdUserInput) + ".value", + value); + } + // Checks if password input is marked as invalid. void TestPasswordError() { TestLoginVisible(); @@ -277,6 +286,7 @@ } const std::string test_realm_; + const std::string test_user_; std::string autocomplete_realm_; private: @@ -295,7 +305,7 @@ device_settings.mutable_login_screen_domain_auto_complete() ->set_login_screen_domain_auto_complete(kTestUserRealm); fake_auth_policy_client()->set_device_policy(device_settings); - autocomplete_realm_ = kTestUserRealm; + autocomplete_realm_ = "@" + std::string(kTestUserRealm); } private: @@ -315,12 +325,12 @@ // Test successful Active Directory login. IN_PROC_BROWSER_TEST_F_WITH_PRE(ActiveDirectoryLoginTest, LoginSuccess) { TestNoError(); - TestDomainVisible(); + TestDomainHidden(); content::WindowedNotificationObserver session_start_waiter( chrome::NOTIFICATION_SESSION_STARTED, content::NotificationService::AllSources()); - SubmitActiveDirectoryCredentials(kTestActiveDirectoryUser, kPassword); + SubmitActiveDirectoryCredentials(test_user_, kPassword); session_start_waiter.Wait(); } @@ -328,17 +338,17 @@ IN_PROC_BROWSER_TEST_F_WITH_PRE(ActiveDirectoryLoginTest, LoginErrors) { SetupActiveDirectoryJSNotifications(); TestNoError(); - TestDomainVisible(); + TestDomainHidden(); content::DOMMessageQueue message_queue; SubmitActiveDirectoryCredentials("", ""); TestUserError(); - TestDomainVisible(); + TestDomainHidden(); - SubmitActiveDirectoryCredentials(kTestActiveDirectoryUser, ""); + SubmitActiveDirectoryCredentials(test_user_, ""); TestPasswordError(); - TestDomainVisible(); + TestDomainHidden(); SubmitActiveDirectoryCredentials(std::string(kTestActiveDirectoryUser) + "@", kPassword); @@ -347,31 +357,30 @@ TestDomainHidden(); fake_auth_policy_client()->set_auth_error(authpolicy::ERROR_BAD_USER_NAME); - SubmitActiveDirectoryCredentials( - std::string(kTestActiveDirectoryUser) + "@" + test_realm_, kPassword); + SubmitActiveDirectoryCredentials(test_user_, kPassword); WaitForMessage(&message_queue, "\"ShowAuthError\""); TestUserError(); - TestDomainVisible(); + TestDomainHidden(); fake_auth_policy_client()->set_auth_error(authpolicy::ERROR_BAD_PASSWORD); - SubmitActiveDirectoryCredentials(kTestActiveDirectoryUser, kPassword); + SubmitActiveDirectoryCredentials(test_user_, kPassword); WaitForMessage(&message_queue, "\"ShowAuthError\""); TestPasswordError(); - TestDomainVisible(); + TestDomainHidden(); fake_auth_policy_client()->set_auth_error(authpolicy::ERROR_UNKNOWN); - SubmitActiveDirectoryCredentials(kTestActiveDirectoryUser, kPassword); + SubmitActiveDirectoryCredentials(test_user_, kPassword); WaitForMessage(&message_queue, "\"ShowAuthError\""); // Inputs are not invalidated for the unknown error. TestNoError(); - TestDomainVisible(); + TestDomainHidden(); } // Test successful Active Directory login from the password change screen. IN_PROC_BROWSER_TEST_F_WITH_PRE(ActiveDirectoryLoginTest, PasswordChange_LoginSuccess) { TestLoginVisible(); - TestDomainVisible(); + TestDomainHidden(); TriggerPasswordChangeScreen(); @@ -389,7 +398,7 @@ IN_PROC_BROWSER_TEST_F_WITH_PRE(ActiveDirectoryLoginTest, PasswordChange_UIErrors) { TestLoginVisible(); - TestDomainVisible(); + TestDomainHidden(); TriggerPasswordChangeScreen(); // Password rejected by UX. @@ -421,7 +430,7 @@ IN_PROC_BROWSER_TEST_F_WITH_PRE(ActiveDirectoryLoginTest, PasswordChange_ReopenClearErrors) { TestLoginVisible(); - TestDomainVisible(); + TestDomainHidden(); TriggerPasswordChangeScreen(); @@ -434,12 +443,50 @@ TriggerPasswordChangeScreen(); } -// Tests that DeviceLoginScreenDomainAutoComplete policy overrides device realm -// for user autocomplete. +// Tests that autocomplete works. Submits username without domain. +IN_PROC_BROWSER_TEST_F_WITH_PRE(ActiveDirectoryLoginAutocompleteTest, + LoginSuccess) { + TestNoError(); + TestDomainVisible(); + + content::WindowedNotificationObserver session_start_waiter( + chrome::NOTIFICATION_SESSION_STARTED, + content::NotificationService::AllSources()); + SubmitActiveDirectoryCredentials(kTestActiveDirectoryUser, kPassword); + session_start_waiter.Wait(); +} + +// Tests that user could override autocomplete domain. IN_PROC_BROWSER_TEST_F_WITH_PRE(ActiveDirectoryLoginAutocompleteTest, TestAutocomplete) { + SetupActiveDirectoryJSNotifications(); + TestLoginVisible(); TestDomainVisible(); + fake_auth_policy_client()->set_auth_error(authpolicy::ERROR_BAD_PASSWORD); + content::DOMMessageQueue message_queue; + + // Submit with a different domain. + SetUserInput(test_user_); + TestDomainHidden(); + TestUserInput(test_user_); + SubmitActiveDirectoryCredentials(test_user_, "password"); + WaitForMessage(&message_queue, "\"ShowAuthError\""); + TestLoginVisible(); + TestDomainHidden(); + TestUserInput(test_user_); + + // Set userinput with the autocomplete domain. JS will remove the autocomplete + // domain. + SetUserInput(kTestActiveDirectoryUser + autocomplete_realm_); + TestDomainVisible(); + TestUserInput(kTestActiveDirectoryUser); + SubmitActiveDirectoryCredentials( + kTestActiveDirectoryUser + autocomplete_realm_, "password"); + WaitForMessage(&message_queue, "\"ShowAuthError\""); + TestLoginVisible(); + TestDomainVisible(); + TestUserInput(kTestActiveDirectoryUser); } #undef IN_PROC_BROWSER_TEST_F_WITH_PRE
diff --git a/chrome/browser/chromeos/login/oobe_interactive_ui_test.cc b/chrome/browser/chromeos/login/oobe_interactive_ui_test.cc index c0be25b4..a882ca1 100644 --- a/chrome/browser/chromeos/login/oobe_interactive_ui_test.cc +++ b/chrome/browser/chromeos/login/oobe_interactive_ui_test.cc
@@ -264,8 +264,14 @@ DISALLOW_COPY_AND_ASSIGN(OobeInteractiveUITest); }; -// crbug.com/891484 -IN_PROC_BROWSER_TEST_F(OobeInteractiveUITest, DISABLED_SimpleEndToEnd) { +// Times out on MSAN: crbug.com/891484. +#if defined(MEMORY_SANITIZER) || defined(LEAK_SANITIZER) || \ + defined(ADDRESS_SANITIZER) +#define MAYBE_SimpleEndToEnd DISABLED_SimpleEndToEnd +#else +#define MAYBE_SimpleEndToEnd SimpleEndToEnd +#endif +IN_PROC_BROWSER_TEST_F(OobeInteractiveUITest, MAYBE_SimpleEndToEnd) { WaitForOobeWelcomeScreen(); RunWelcomeScreenChecks(); TapWelcomeNext();
diff --git a/chrome/browser/download/download_ui_controller_unittest.cc b/chrome/browser/download/download_ui_controller_unittest.cc index ccbe0d6f1..30a4716 100644 --- a/chrome/browser/download/download_ui_controller_unittest.cc +++ b/chrome/browser/download/download_ui_controller_unittest.cc
@@ -196,7 +196,8 @@ TestDownloadCoreService* download_core_service = static_cast<TestDownloadCoreService*>( DownloadCoreServiceFactory::GetInstance()->SetTestingFactoryAndUse( - browser_context(), &TestingDownloadCoreServiceFactory)); + browser_context(), + base::BindRepeating(&TestingDownloadCoreServiceFactory))); ASSERT_TRUE(download_core_service); download_core_service->set_download_history(std::move(download_history)); }
diff --git a/chrome/browser/extensions/api/identity/identity_apitest.cc b/chrome/browser/extensions/api/identity/identity_apitest.cc index 1dad36f..9806b07 100644 --- a/chrome/browser/extensions/api/identity/identity_apitest.cc +++ b/chrome/browser/extensions/api/identity/identity_apitest.cc
@@ -8,6 +8,7 @@ #include <utility> #include <vector> +#include "base/bind.h" #include "base/command_line.h" #include "base/memory/ptr_util.h" #include "base/run_loop.h" @@ -436,11 +437,12 @@ // creating the browser so that a bunch of classes don't register as // observers and end up needing to unregister when the fake is substituted. SigninManagerFactory::GetInstance()->SetTestingFactory( - context, &BuildFakeSigninManagerBase); + context, base::BindRepeating(&BuildFakeSigninManagerBase)); ProfileOAuth2TokenServiceFactory::GetInstance()->SetTestingFactory( - context, &BuildFakeProfileOAuth2TokenService); + context, base::BindRepeating(&BuildFakeProfileOAuth2TokenService)); GaiaCookieManagerServiceFactory::GetInstance()->SetTestingFactory( - context, &BuildFakeGaiaCookieManagerServiceNoFakeUrlFetcher); + context, base::BindRepeating( + &BuildFakeGaiaCookieManagerServiceNoFakeUrlFetcher)); // Ensure that AccountFetcherService is (1) created at all and (2) created // early enough for it to observe the Profile initialization process and
diff --git a/chrome/browser/extensions/api/language_settings_private/language_settings_private_api_unittest.cc b/chrome/browser/extensions/api/language_settings_private/language_settings_private_api_unittest.cc index e112824..8c56a8e 100644 --- a/chrome/browser/extensions/api/language_settings_private/language_settings_private_api_unittest.cc +++ b/chrome/browser/extensions/api/language_settings_private/language_settings_private_api_unittest.cc
@@ -5,6 +5,7 @@ #include <string> #include <vector> +#include "base/bind.h" #include "base/macros.h" #include "base/memory/ref_counted.h" #include "base/memory/scoped_refptr.h" @@ -91,11 +92,11 @@ void SetUp() override { ExtensionServiceTestBase::SetUp(); ExtensionServiceTestBase::InitializeEmptyExtensionService(); - EventRouterFactory::GetInstance()->SetTestingFactory(profile(), - &BuildEventRouter); + EventRouterFactory::GetInstance()->SetTestingFactory( + profile(), base::BindRepeating(&BuildEventRouter)); LanguageSettingsPrivateDelegateFactory::GetInstance()->SetTestingFactory( - profile(), &BuildLanguageSettingsPrivateDelegate); + profile(), base::BindRepeating(&BuildLanguageSettingsPrivateDelegate)); } void TearDown() override { ExtensionServiceTestBase::TearDown(); }
diff --git a/chrome/browser/extensions/api/language_settings_private/language_settings_private_delegate_unittest.cc b/chrome/browser/extensions/api/language_settings_private/language_settings_private_delegate_unittest.cc index c6cc3c9..743b339 100644 --- a/chrome/browser/extensions/api/language_settings_private/language_settings_private_delegate_unittest.cc +++ b/chrome/browser/extensions/api/language_settings_private/language_settings_private_delegate_unittest.cc
@@ -3,6 +3,8 @@ // found in the LICENSE file. #include "chrome/browser/extensions/api/language_settings_private/language_settings_private_delegate.h" + +#include "base/bind.h" #include "chrome/browser/chrome_notification_types.h" #include "chrome/browser/extensions/extension_service_test_base.h" #include "chrome/browser/spellchecker/spellcheck_factory.h" @@ -40,8 +42,8 @@ void SetUp() override { ExtensionServiceTestBase::SetUp(); ExtensionServiceTestBase::InitializeEmptyExtensionService(); - EventRouterFactory::GetInstance()->SetTestingFactory(profile(), - &BuildEventRouter); + EventRouterFactory::GetInstance()->SetTestingFactory( + profile(), base::BindRepeating(&BuildEventRouter)); base::ListValue language_codes; language_codes.AppendString("fr"); @@ -49,7 +51,7 @@ language_codes); SpellcheckServiceFactory::GetInstance()->SetTestingFactory( - profile(), &BuildSpellcheckService); + profile(), base::BindRepeating(&BuildSpellcheckService)); // Wait until dictionary file is loaded. SpellcheckService* service =
diff --git a/chrome/browser/extensions/cross_origin_read_blocking_browsertest.cc b/chrome/browser/extensions/cross_origin_read_blocking_browsertest.cc index 8020fe8..a97ddcf 100644 --- a/chrome/browser/extensions/cross_origin_read_blocking_browsertest.cc +++ b/chrome/browser/extensions/cross_origin_read_blocking_browsertest.cc
@@ -44,17 +44,19 @@ } protected: - void InstallExtension( + const Extension* InstallExtension( GURL resource_to_fetch_from_declarative_content_script = GURL()) { bool use_declarative_content_script = resource_to_fetch_from_declarative_content_script.is_valid(); - const char kContentScriptManifestEntry[] = R"( "content_scripts": [{ + "all_frames": true, + "match_about_blank": true, "matches": ["*://*/*"], "js": ["content_script.js"] }], )"; + const char kManifestTemplate[] = R"( { "name": "CrossOriginReadBlockingTest", @@ -69,6 +71,7 @@ use_declarative_content_script ? kContentScriptManifestEntry : "")); dir_.WriteFile(FILE_PATH_LITERAL("background_script.js"), ""); + dir_.WriteFile(FILE_PATH_LITERAL("page.html"), "<body>Hello World!</body>"); if (use_declarative_content_script) { dir_.WriteFile( @@ -76,6 +79,34 @@ CreateFetchScript(resource_to_fetch_from_declarative_content_script)); } extension_ = LoadExtension(dir_.UnpackedPath()); + return extension_; + } + + bool RegisterServiceWorkerForExtension( + const std::string& service_worker_script) { + const char kServiceWorkerPath[] = "service_worker.js"; + dir_.WriteFile(base::FilePath::FromUTF8Unsafe(kServiceWorkerPath).value(), + service_worker_script); + + const char kRegistrationScript[] = R"( + navigator.serviceWorker.register($1).then(function() { + // Wait until the service worker is active. + return navigator.serviceWorker.ready; + }).then(function(r) { + window.domAutomationController.send('SUCCESS'); + }).catch(function(err) { + window.domAutomationController.send('ERROR: ' + err.message); + }); )"; + std::string registration_script = + content::JsReplace(kRegistrationScript, kServiceWorkerPath); + + std::string result = browsertest_util::ExecuteScriptInBackgroundPage( + browser()->profile(), extension_->id(), registration_script); + if (result != "SUCCESS") { + ADD_FAILURE() << "Failed to register the service worker: " << result; + return false; + } + return !::testing::Test::HasFailure(); } // Injects (into |web_contents|) a content_script that performs a fetch of @@ -95,13 +126,33 @@ // Performs a fetch of |url| from the background page of the test extension. // Returns the body of the response. - std::string FetchViaBackgroundPage(GURL url) { + std::string FetchViaBackgroundPage(const GURL& url) { return FetchHelper( url, base::BindOnce( &browsertest_util::ExecuteScriptInBackgroundPageNoWait, base::Unretained(browser()->profile()), extension_->id())); } + // Performs a fetch of |url| from |web_contents| (directly, without going + // through content scripts). Returns the body of the response. + std::string FetchViaWebContents(const GURL& url, + content::WebContents* web_contents) { + return FetchHelper( + url, base::BindOnce( + &CrossOriginReadBlockingExtensionTest::ExecuteRegularScript, + base::Unretained(this), base::Unretained(web_contents))); + } + + // Performs a fetch of |url| from a srcdoc subframe added to |parent_frame| + // and executing a script via <script> tag. Returns the body of the response. + std::string FetchViaSrcDocFrame(GURL url, + content::RenderFrameHost* parent_frame) { + return FetchHelper( + url, base::BindOnce( + &CrossOriginReadBlockingExtensionTest::ExecuteInSrcDocFrame, + base::Unretained(this), base::Unretained(parent_frame))); + } + void VerifyContentScriptHistogramIsPresent( const base::HistogramTester& histograms, content::ResourceType resource_type) { @@ -124,9 +175,19 @@ return result; } + GURL GetExtensionResource(const std::string& relative_path) { + return extension_->GetResourceURL(relative_path); + } + + url::Origin GetExtensionOrigin() { + return url::Origin::Create(extension_->url()); + } + private: // Asks the test |extension_| to inject |content_script| into |web_contents|. - // Returns true if the content script injection succeeded. + // + // This is an implementation of FetchCallback. + // Returns true if the content script execution started succeessfully. bool ExecuteContentScript(content::WebContents* web_contents, const std::string& content_script) { int tab_id = ExtensionTabUtil::GetTabId(web_contents); @@ -136,19 +197,79 @@ browser()->profile(), extension_->id(), background_script); } + // Executes |regular_script| in |web_contents|. + // + // This is an implementation of FetchCallback. + // Returns true if the script execution started succeessfully. + bool ExecuteRegularScript(content::WebContents* web_contents, + const std::string& regular_script) { + content::ExecuteScriptAsync(web_contents, regular_script); + + // Report artificial success to meet FetchCallback's requirements. + return true; + } + + // Injects into |parent_frame| an "srcdoc" subframe that contains/executes + // |script_to_run_in_subframe| via <script> tag. + // + // This function is useful to exercise a scenario when a <script> tag may + // execute before the browser gets a chance to see the a frame/navigation + // commit is happening. + // + // This is an implementation of FetchCallback. + // Returns true if the script execution started succeessfully. + bool ExecuteInSrcDocFrame(content::RenderFrameHost* parent_frame, + const std::string& script_to_run_in_subframe) { + static int sequence_id = 0; + sequence_id++; + std::string filename = + base::StringPrintf("srcdoc_script_%d.js", sequence_id); + dir_.WriteFile(base::FilePath::FromUTF8Unsafe(filename).value(), + script_to_run_in_subframe); + + // Using <script src=...></script> instead of <script>...</script> to avoid + // extensions CSP which forbids inline scripts. + const char kScriptTemplate[] = R"( + var subframe = document.createElement('iframe'); + subframe.srcdoc = '<script src=' + $1 + '></script>'; + document.body.appendChild(subframe); )"; + std::string subframe_injection_script = + content::JsReplace(kScriptTemplate, filename); + content::ExecuteScriptAsync(parent_frame, subframe_injection_script); + + // Report artificial success to meet FetchCallback's requirements. + return true; + } + std::string CreateFetchScript(const GURL& resource) { const char kXhrScriptTemplate[] = R"( fetch($1) .then(response => response.text()) .then(text => domAutomationController.send(text)) - .catch(err => domAutomationController.send("error: " + err)); + .catch(err => domAutomationController.send('error: ' + err)); )"; return content::JsReplace(kXhrScriptTemplate, resource); } + // FetchCallback represents a function that executes |fetch_script|. + // + // |fetch_script| will include calls to |domAutomationController.send| and + // therefore instances of FetchCallback should not inject their own calls to + // |domAutomationController.send| (e.g. this constraint rules out + // browsertest_util::ExecuteScriptInBackgroundPage and/or + // content::ExecuteScript). + // + // The function should return true if script execution started successfully. + // + // Currently used "implementations": + // - CrossOriginReadBlockingExtensionTest::ExecuteContentScript(web_contents) + // - CrossOriginReadBlockingExtensionTest::ExecuteRegularScript(web_contents) + // - browsertest_util::ExecuteScriptInBackgroundPageNoWait(profile, ext_id) using FetchCallback = base::OnceCallback<bool(const std::string& fetch_script)>; - std::string FetchHelper(GURL url, FetchCallback fetch_callback) { + + // Returns response body of a fetch of |url| initiated via |fetch_callback|. + std::string FetchHelper(const GURL& url, FetchCallback fetch_callback) { content::DOMMessageQueue message_queue; // Inject a content script that performs a cross-origin XHR to bar.com. @@ -186,33 +307,68 @@ IN_PROC_BROWSER_TEST_F(CrossOriginReadBlockingExtensionTest, FromDeclarativeContentScript_NoSniffXml) { + content::WebContents* web_contents = + browser()->tab_strip_model()->GetActiveWebContents(); + // Load the test extension. GURL cross_site_resource( embedded_test_server()->GetURL("bar.com", "/nosniff.xml")); - InstallExtension(cross_site_resource); + ASSERT_TRUE(InstallExtension(cross_site_resource)); - // Navigate to a foo.com page - this should trigger execution of the - // |content_script| declared in the extension manifest. - base::HistogramTester histograms; - content::DOMMessageQueue message_queue; - content::WebContents* web_contents = - browser()->tab_strip_model()->GetActiveWebContents(); - GURL page_url(embedded_test_server()->GetURL("foo.com", "/title1.html")); - ui_test_utils::NavigateToURL(browser(), page_url); - EXPECT_EQ(page_url, web_contents->GetMainFrame()->GetLastCommittedURL()); - EXPECT_EQ(url::Origin::Create(page_url), - web_contents->GetMainFrame()->GetLastCommittedOrigin()); + // Test case #1: Declarative script injected after a browser-initiated + // navigation of the main frame. + { + // Monitor CORB behavior + result of the fetch. + base::HistogramTester histograms; + content::DOMMessageQueue message_queue; - // Extract results of the fetch done in the declarative content script. - std::string fetch_result = PopString(&message_queue); + // Navigate to a foo.com page - this should trigger execution of the + // |content_script| declared in the extension manifest. + GURL page_url(embedded_test_server()->GetURL("foo.com", "/title1.html")); + ui_test_utils::NavigateToURL(browser(), page_url); + EXPECT_EQ(page_url, web_contents->GetMainFrame()->GetLastCommittedURL()); + EXPECT_EQ(url::Origin::Create(page_url), + web_contents->GetMainFrame()->GetLastCommittedOrigin()); - // Verify that no blocking occurred. - EXPECT_EQ("nosniff.xml - body\n", fetch_result); - EXPECT_THAT(histograms.GetAllSamples("SiteIsolation.XSD.Browser.Blocked"), - testing::IsEmpty()); + // Extract results of the fetch done in the declarative content script. + std::string fetch_result = PopString(&message_queue); - // Verify that LogInitiatorSchemeBypassingDocumentBlocking was called. - VerifyContentScriptHistogramIsPresent(histograms, content::RESOURCE_TYPE_XHR); + // Verify that no blocking occurred. + EXPECT_EQ("nosniff.xml - body\n", fetch_result); + EXPECT_THAT(histograms.GetAllSamples("SiteIsolation.XSD.Browser.Blocked"), + testing::IsEmpty()); + + // Verify that LogInitiatorSchemeBypassingDocumentBlocking was called. + VerifyContentScriptHistogramIsPresent(histograms, + content::RESOURCE_TYPE_XHR); + } + + // Test case #2: Declarative script injected after a renderer-initiated + // creation of an about:blank frame. + { + // Monitor CORB behavior + result of the fetch. + base::HistogramTester histograms; + content::DOMMessageQueue message_queue; + + // Inject an about:blank subframe - this should trigger execution of the + // |content_script| declared in the extension manifest. + const char kBlankSubframeInjectionScript[] = R"( + var subframe = document.createElement('iframe'); + document.body.appendChild(subframe); )"; + content::ExecuteScriptAsync(web_contents, kBlankSubframeInjectionScript); + + // Extract results of the fetch done in the declarative content script. + std::string fetch_result = PopString(&message_queue); + + // Verify that no blocking occurred. + EXPECT_EQ("nosniff.xml - body\n", fetch_result); + EXPECT_THAT(histograms.GetAllSamples("SiteIsolation.XSD.Browser.Blocked"), + testing::IsEmpty()); + + // Verify that LogInitiatorSchemeBypassingDocumentBlocking was called. + VerifyContentScriptHistogramIsPresent(histograms, + content::RESOURCE_TYPE_XHR); + } } // Test that verifies the current, baked-in (but not necessarily desirable @@ -222,7 +378,7 @@ IN_PROC_BROWSER_TEST_F(CrossOriginReadBlockingExtensionTest, FromProgrammaticContentScript_NoSniffXml) { // Load the test extension. - InstallExtension(); + ASSERT_TRUE(InstallExtension()); // Navigate to a foo.com page. content::WebContents* web_contents = @@ -254,7 +410,7 @@ IN_PROC_BROWSER_TEST_F(CrossOriginReadBlockingExtensionTest, FromProgrammaticContentScript_AllowedTextResource) { // Load the test extension. - InstallExtension(); + ASSERT_TRUE(InstallExtension()); // Navigate to a foo.com page. content::WebContents* web_contents = @@ -292,7 +448,7 @@ IN_PROC_BROWSER_TEST_F(CrossOriginReadBlockingExtensionTest, FromProgrammaticContentScript_EmptyAndBlocked) { // Load the test extension. - InstallExtension(); + ASSERT_TRUE(InstallExtension()); // Navigate to a foo.com page. content::WebContents* web_contents = @@ -323,7 +479,7 @@ IN_PROC_BROWSER_TEST_F(CrossOriginReadBlockingExtensionTest, FromBackgroundPage_NoSniffXml) { // Load the test extension. - InstallExtension(); + ASSERT_TRUE(InstallExtension()); // Performs a cross-origin XHR from the background page. base::HistogramTester histograms; @@ -341,4 +497,165 @@ VerifyContentScriptHistogramIsMissing(histograms); } +// Test that requests from a extension page hosted in a foreground tab use +// relaxed CORB processing. +IN_PROC_BROWSER_TEST_F(CrossOriginReadBlockingExtensionTest, + FromForegroundPage_NoSniffXml) { + // Load the test extension. + ASSERT_TRUE(InstallExtension()); + + // Navigate a tab to an extension page. + ui_test_utils::NavigateToURL(browser(), GetExtensionResource("page.html")); + content::WebContents* web_contents = + browser()->tab_strip_model()->GetActiveWebContents(); + EXPECT_EQ(GetExtensionOrigin(), + web_contents->GetMainFrame()->GetLastCommittedOrigin()); + + // Test case #1: Fetch from a chrome-extension://... main frame. + { + // Perform a cross-origin XHR from the foreground extension page. + base::HistogramTester histograms; + GURL cross_site_resource( + embedded_test_server()->GetURL("bar.com", "/nosniff.xml")); + std::string fetch_result = + FetchViaWebContents(cross_site_resource, web_contents); + + // Verify that no blocking occurred. + EXPECT_EQ("nosniff.xml - body\n", fetch_result); + EXPECT_THAT(histograms.GetAllSamples("SiteIsolation.XSD.Browser.Blocked"), + testing::IsEmpty()); + + // Verify that LogInitiatorSchemeBypassingDocumentBlocking returned early + // for a request that wasn't from a content script. + VerifyContentScriptHistogramIsMissing(histograms); + } + + // Test case #2: Fetch from an about:srcdoc subframe of a + // chrome-extension://... frame. + { + // Perform a cross-origin XHR from the foreground extension page. + base::HistogramTester histograms; + GURL cross_site_resource( + embedded_test_server()->GetURL("bar.com", "/nosniff.xml")); + std::string fetch_result = + FetchViaSrcDocFrame(cross_site_resource, web_contents->GetMainFrame()); + + // Verify that no blocking occurred. + EXPECT_EQ("nosniff.xml - body\n", fetch_result); + EXPECT_THAT(histograms.GetAllSamples("SiteIsolation.XSD.Browser.Blocked"), + testing::IsEmpty()); + + // Verify that LogInitiatorSchemeBypassingDocumentBlocking returned early + // for a request that wasn't from a content script. + VerifyContentScriptHistogramIsMissing(histograms); + } +} + +// Test that requests from an extension's service worker to the network use +// relaxed CORB processing (both in the case of requests that 1) are initiated +// by the service worker and/or 2) are ignored by the service worker and fall +// back to the network). +IN_PROC_BROWSER_TEST_F(CrossOriginReadBlockingExtensionTest, + FromServiceWorker_NoSniffXml) { + // Load the test extension. + ASSERT_TRUE(InstallExtension()); + + // Register the service worker which injects "SERVICE WORKER INTERCEPT: " + // prefix to the body of each response. + const char kServiceWorkerScript[] = R"( + self.addEventListener('fetch', function(event) { + // Intercept all http requests to bar.com and inject + // 'SERVICE WORKER INTERCEPT:' prefix. + if (event.request.url.startsWith('http://bar.com')) { + event.respondWith( + // By using the 'fetch' call below, the service worker initiates + // a network request that will go through the URLLoaderFactory + // created via CreateFactoryBundle called / posted indirectly + // from EmbeddedWorkerInstance::StartTask::Start. + fetch(event.request) + .then(response => response.text()) + .then(text => new Response( + 'SERVICE WORKER INTERCEPT: >>>' + text + '<<<'))); + } + + // Let the request go directly to the network in all the other cases, + // like: + // - loading the extension resources like page.html (avoiding going + // through the service worker is required for correctness of test + // setup), + // - handling the cross-origin fetch to other.com in test case #2. + // Note that these requests will use the URLLoaderFactory owned by + // ServiceWorkerSubresourceLoader which can be different to the + // network loader factory owned by the ServiceWorker thread (which is + // used for fetch intiated by the service worker above). + }); )"; + ASSERT_TRUE(RegisterServiceWorkerForExtension(kServiceWorkerScript)); + + // Navigate a tab to an extension page. + ui_test_utils::NavigateToURL(browser(), GetExtensionResource("page.html")); + content::WebContents* web_contents = + browser()->tab_strip_model()->GetActiveWebContents(); + EXPECT_EQ(GetExtensionOrigin(), + web_contents->GetMainFrame()->GetLastCommittedOrigin()); + + // Verify that the service worker controls the fetches. + bool is_controlled_by_service_worker = false; + ASSERT_TRUE(ExecuteScriptAndExtractBool( + web_contents, + "domAutomationController.send(!!navigator.serviceWorker.controller)", + &is_controlled_by_service_worker)); + ASSERT_TRUE(is_controlled_by_service_worker); + + // Test case #1: Network fetch initiated by the service worker. + // + // This covers URLLoaderFactory owned by the ServiceWorker thread and created + // created via CreateFactoryBundle called / posted indirectly from + // EmbeddedWorkerInstance::StartTask::Start. + { + // Perform a cross-origin XHR from the foreground extension page. + // This should be intercepted by the service worker installed above. + base::HistogramTester histograms; + GURL cross_site_resource_intercepted_by_service_worker( + embedded_test_server()->GetURL("bar.com", "/nosniff.xml")); + std::string fetch_result = FetchViaWebContents( + cross_site_resource_intercepted_by_service_worker, web_contents); + + // Verify that no blocking occurred (and that the response really did go + // through the service worker). + EXPECT_EQ("SERVICE WORKER INTERCEPT: >>>nosniff.xml - body\n<<<", + fetch_result); + EXPECT_THAT(histograms.GetAllSamples("SiteIsolation.XSD.Browser.Blocked"), + testing::IsEmpty()); + + // Verify that LogInitiatorSchemeBypassingDocumentBlocking returned early + // for a request that wasn't from a content script. + VerifyContentScriptHistogramIsMissing(histograms); + } + + // Test case #2: Network fetch used as a fallback when service worker ignores + // the 'fetch' event. + // + // This covers URLLoaderFactory owned by the ServiceWorkerSubresourceLoader, + // which can be different to the network loader factory owned by the + // ServiceWorker thread (which is used in test case #1). + { + // Perform a cross-origin XHR from the foreground extension page. + // This should be intercepted by the service worker installed above. + base::HistogramTester histograms; + GURL cross_site_resource_ignored_by_service_worker( + embedded_test_server()->GetURL("other.com", "/nosniff.xml")); + std::string fetch_result = FetchViaWebContents( + cross_site_resource_ignored_by_service_worker, web_contents); + + // Verify that no blocking occurred. + EXPECT_EQ("nosniff.xml - body\n", fetch_result); + EXPECT_THAT(histograms.GetAllSamples("SiteIsolation.XSD.Browser.Blocked"), + testing::IsEmpty()); + + // Verify that LogInitiatorSchemeBypassingDocumentBlocking returned early + // for a request that wasn't from a content script. + VerifyContentScriptHistogramIsMissing(histograms); + } +} + } // namespace extensions
diff --git a/chrome/browser/extensions/extension_action_runner_unittest.cc b/chrome/browser/extensions/extension_action_runner_unittest.cc index 647784792..9b56ed3 100644 --- a/chrome/browser/extensions/extension_action_runner_unittest.cc +++ b/chrome/browser/extensions/extension_action_runner_unittest.cc
@@ -178,8 +178,8 @@ extensions_features::kRuntimeHostPermissions); // Skip syncing for testing purposes. - ExtensionSyncServiceFactory::GetInstance()->SetTestingFactory(profile(), - nullptr); + ExtensionSyncServiceFactory::GetInstance()->SetTestingFactory( + profile(), BrowserContextKeyedServiceFactory::TestingFactory()); TabHelper::CreateForWebContents(web_contents()); TabHelper* tab_helper = TabHelper::FromWebContents(web_contents());
diff --git a/chrome/browser/extensions/extension_action_test_util.cc b/chrome/browser/extensions/extension_action_test_util.cc index b4ff1103..d98e1088 100644 --- a/chrome/browser/extensions/extension_action_test_util.cc +++ b/chrome/browser/extensions/extension_action_test_util.cc
@@ -6,6 +6,7 @@ #include <memory> +#include "base/bind.h" #include "base/run_loop.h" #include "chrome/browser/extensions/extension_action.h" #include "chrome/browser/extensions/extension_action_manager.h" @@ -71,7 +72,7 @@ // No existing model means it's a new profile (since we, by default, don't // create the ToolbarModel in testing). ToolbarActionsModelFactory::GetInstance()->SetTestingFactory( - profile, &BuildToolbarModel); + profile, base::BindRepeating(&BuildToolbarModel)); model = ToolbarActionsModel::Get(profile); if (wait_for_ready) { // Fake the extension system ready signal.
diff --git a/chrome/browser/extensions/extension_context_menu_model_unittest.cc b/chrome/browser/extensions/extension_context_menu_model_unittest.cc index b57291bf..f4e17d3 100644 --- a/chrome/browser/extensions/extension_context_menu_model_unittest.cc +++ b/chrome/browser/extensions/extension_context_menu_model_unittest.cc
@@ -6,6 +6,7 @@ #include <utility> +#include "base/bind.h" #include "base/macros.h" #include "base/memory/ptr_util.h" #include "base/strings/utf_string_conversions.h" @@ -448,7 +449,8 @@ MenuManager* manager = static_cast<MenuManager*>( (MenuManagerFactory::GetInstance()->SetTestingFactoryAndUse( profile(), - &MenuManagerFactory::BuildServiceInstanceForTesting))); + base::BindRepeating( + &MenuManagerFactory::BuildServiceInstanceForTesting)))); ASSERT_TRUE(manager); MenuBuilder builder(extension, GetBrowser(), manager); @@ -496,7 +498,8 @@ // Create a MenuManager for adding context items. MenuManager* manager = static_cast<MenuManager*>( MenuManagerFactory::GetInstance()->SetTestingFactoryAndUse( - profile(), &MenuManagerFactory::BuildServiceInstanceForTesting)); + profile(), base::BindRepeating( + &MenuManagerFactory::BuildServiceInstanceForTesting))); ASSERT_TRUE(manager); MenuBuilder builder(extension, GetBrowser(), manager); @@ -1374,7 +1377,9 @@ // Create a MenuManager for adding context items. MenuManager* manager = static_cast<MenuManager*>( (MenuManagerFactory::GetInstance()->SetTestingFactoryAndUse( - profile(), &MenuManagerFactory::BuildServiceInstanceForTesting))); + profile(), + base::BindRepeating( + &MenuManagerFactory::BuildServiceInstanceForTesting)))); ASSERT_TRUE(manager); MenuBuilder builder(extension, GetBrowser(), manager);
diff --git a/chrome/browser/extensions/extension_message_bubble_controller_unittest.cc b/chrome/browser/extensions/extension_message_bubble_controller_unittest.cc index 5573415..4da06134 100644 --- a/chrome/browser/extensions/extension_message_bubble_controller_unittest.cc +++ b/chrome/browser/extensions/extension_message_bubble_controller_unittest.cc
@@ -7,6 +7,7 @@ #include <memory> #include <utility> +#include "base/bind.h" #include "base/bind_helpers.h" #include "base/command_line.h" #include "base/macros.h" @@ -342,12 +343,13 @@ service_ = ExtensionSystem::Get(profile())->extension_service(); service_->Init(); - extensions::ExtensionWebUIOverrideRegistrar::GetFactoryInstance()-> - SetTestingFactory(profile(), &BuildOverrideRegistrar); + extensions::ExtensionWebUIOverrideRegistrar::GetFactoryInstance() + ->SetTestingFactory(profile(), + base::BindRepeating(&BuildOverrideRegistrar)); extensions::ExtensionWebUIOverrideRegistrar::GetFactoryInstance()->Get( profile()); ToolbarActionsModelFactory::GetInstance()->SetTestingFactory( - profile(), &BuildToolbarModel); + profile(), base::BindRepeating(&BuildToolbarModel)); } ~ExtensionMessageBubbleTest() override {} @@ -725,7 +727,7 @@ Profile* off_the_record_profile = profile()->GetOffTheRecordProfile(); ToolbarActionsModelFactory::GetInstance()->SetTestingFactory( - off_the_record_profile, &BuildToolbarModel); + off_the_record_profile, base::BindRepeating(&BuildToolbarModel)); std::unique_ptr<BrowserWindow> off_the_record_window(CreateBrowserWindow()); std::unique_ptr<Browser> off_the_record_browser(
diff --git a/chrome/browser/extensions/extension_service_test_base.cc b/chrome/browser/extensions/extension_service_test_base.cc index 09a169b..ff4893c 100644 --- a/chrome/browser/extensions/extension_service_test_base.cc +++ b/chrome/browser/extensions/extension_service_test_base.cc
@@ -6,6 +6,7 @@ #include <utility> +#include "base/bind.h" #include "base/command_line.h" #include "base/files/file_util.h" #include "base/memory/ref_counted.h" @@ -135,7 +136,8 @@ // Garbage collector is typically NULL during tests, so give it a build. ExtensionGarbageCollectorFactory::GetInstance()->SetTestingFactoryAndUse( - profile_.get(), &ExtensionGarbageCollectorFactory::BuildInstanceFor); + profile_.get(), + base::BindRepeating(&ExtensionGarbageCollectorFactory::BuildInstanceFor)); } void ExtensionServiceTestBase::InitializeEmptyExtensionService() {
diff --git a/chrome/browser/extensions/extension_storage_monitor_browsertest.cc b/chrome/browser/extensions/extension_storage_monitor_browsertest.cc index 64d30d0..fdd1eff 100644 --- a/chrome/browser/extensions/extension_storage_monitor_browsertest.cc +++ b/chrome/browser/extensions/extension_storage_monitor_browsertest.cc
@@ -9,6 +9,7 @@ #include <string> #include <vector> +#include "base/bind.h" #include "base/optional.h" #include "base/run_loop.h" #include "base/strings/string_number_conversions.h" @@ -197,7 +198,7 @@ // Setting a testing factory function deletes the current // ExtensionStorageMonitor; see KeyedServiceFactory::SetTestingFactory(). ExtensionStorageMonitorFactory::GetInstance()->SetTestingFactoryAndUse( - profile(), &CreateExtensionStorageMonitorInstance); + profile(), base::BindRepeating(&CreateExtensionStorageMonitorInstance)); InitStorageMonitor(); }
diff --git a/chrome/browser/extensions/extension_web_ui_unittest.cc b/chrome/browser/extensions/extension_web_ui_unittest.cc index 1c016c3..c8b82c55 100644 --- a/chrome/browser/extensions/extension_web_ui_unittest.cc +++ b/chrome/browser/extensions/extension_web_ui_unittest.cc
@@ -4,6 +4,7 @@ #include "chrome/browser/extensions/extension_web_ui.h" +#include "base/bind.h" #include "base/command_line.h" #include "base/run_loop.h" #include "build/build_config.h" @@ -50,7 +51,7 @@ extension_service_ = system->CreateExtensionService( base::CommandLine::ForCurrentProcess(), base::FilePath(), false); ExtensionWebUIOverrideRegistrar::GetFactoryInstance()->SetTestingFactory( - profile_.get(), &BuildOverrideRegistrar); + profile_.get(), base::BindRepeating(&BuildOverrideRegistrar)); ExtensionWebUIOverrideRegistrar::GetFactoryInstance()->Get(profile_.get()); }
diff --git a/chrome/browser/extensions/external_pref_loader_unittest.cc b/chrome/browser/extensions/external_pref_loader_unittest.cc index ffb73e0..edcb817 100644 --- a/chrome/browser/extensions/external_pref_loader_unittest.cc +++ b/chrome/browser/extensions/external_pref_loader_unittest.cc
@@ -3,6 +3,8 @@ // found in the LICENSE file. #include "chrome/browser/extensions/external_pref_loader.h" + +#include "base/bind.h" #include "base/macros.h" #include "base/run_loop.h" #include "base/task/post_task.h" @@ -125,7 +127,7 @@ TEST_F(ExternalPrefLoaderTest, PrefReadInitiatesCorrectly) { TestSyncService* test_service = static_cast<TestSyncService*>( ProfileSyncServiceFactory::GetInstance()->SetTestingFactoryAndUse( - profile(), &TestingSyncFactoryFunction)); + profile(), base::BindRepeating(&TestingSyncFactoryFunction))); base::RunLoop run_loop; scoped_refptr<ExternalPrefLoader> loader(
diff --git a/chrome/browser/extensions/menu_manager_unittest.cc b/chrome/browser/extensions/menu_manager_unittest.cc index 1ac3429..98583abd 100644 --- a/chrome/browser/extensions/menu_manager_unittest.cc +++ b/chrome/browser/extensions/menu_manager_unittest.cc
@@ -8,6 +8,7 @@ #include <utility> #include <vector> +#include "base/bind.h" #include "base/files/scoped_temp_dir.h" #include "base/json/json_reader.h" #include "base/macros.h" @@ -571,7 +572,7 @@ TestingProfile profile; MockEventRouter* mock_event_router = static_cast<MockEventRouter*>( EventRouterFactory::GetInstance()->SetTestingFactoryAndUse( - &profile, &MockEventRouterFactoryFunction)); + &profile, base::BindRepeating(&MockEventRouterFactoryFunction))); content::ContextMenuParams params; params.media_type = blink::WebContextMenuData::kMediaTypeImage;
diff --git a/chrome/browser/extensions/ntp_overridden_bubble_delegate_unittest.cc b/chrome/browser/extensions/ntp_overridden_bubble_delegate_unittest.cc index 65624e8..70a2e0eb 100644 --- a/chrome/browser/extensions/ntp_overridden_bubble_delegate_unittest.cc +++ b/chrome/browser/extensions/ntp_overridden_bubble_delegate_unittest.cc
@@ -6,6 +6,7 @@ #include <memory> +#include "base/bind.h" #include "chrome/browser/extensions/extension_service.h" #include "chrome/browser/extensions/extension_service_test_base.h" #include "chrome/browser/extensions/extension_web_ui_override_registrar.h" @@ -48,7 +49,7 @@ InitializeEmptyExtensionService(); ExtensionWebUIOverrideRegistrar::GetFactoryInstance()->SetTestingFactory( - profile(), &BuildOverrideRegistrar); + profile(), base::BindRepeating(&BuildOverrideRegistrar)); // We need to trigger the instantiation of the WebUIOverrideRegistrar for // it to be constructed, since by default it's not constructed in tests. ExtensionWebUIOverrideRegistrar::GetFactoryInstance()->Get(profile());
diff --git a/chrome/browser/extensions/service_worker_apitest.cc b/chrome/browser/extensions/service_worker_apitest.cc index 34ec1a5..5d10948 100644 --- a/chrome/browser/extensions/service_worker_apitest.cc +++ b/chrome/browser/extensions/service_worker_apitest.cc
@@ -508,7 +508,8 @@ void SetUpOnMainThread() override { NotificationDisplayServiceFactory::GetInstance()->SetTestingFactory( - profile(), &StubNotificationDisplayService::FactoryForTests); + profile(), + base::BindRepeating(&StubNotificationDisplayService::FactoryForTests)); gcm::FakeGCMProfileService* gcm_service = static_cast<gcm::FakeGCMProfileService*>(
diff --git a/chrome/browser/extensions/update_install_gate_unittest.cc b/chrome/browser/extensions/update_install_gate_unittest.cc index b27ca18a..7e1bf6a 100644 --- a/chrome/browser/extensions/update_install_gate_unittest.cc +++ b/chrome/browser/extensions/update_install_gate_unittest.cc
@@ -6,6 +6,7 @@ #include <memory> +#include "base/bind.h" #include "base/command_line.h" #include "base/memory/ptr_util.h" #include "base/run_loop.h" @@ -137,7 +138,7 @@ event_router_ = static_cast<EventRouter*>( EventRouterFactory::GetInstance()->SetTestingFactoryAndUse( - profile_, &BuildEventRouter)); + profile_, base::BindRepeating(&BuildEventRouter))); delayer_.reset(new UpdateInstallGate(service_));
diff --git a/chrome/browser/flag_descriptions.cc b/chrome/browser/flag_descriptions.cc index c4a87258..ce4ed50 100644 --- a/chrome/browser/flag_descriptions.cc +++ b/chrome/browser/flag_descriptions.cc
@@ -308,6 +308,13 @@ "With this flag on, desktop share picker window will not let the user " "choose whether to share audio."; +const char kDisableIpcFloodingProtectionName[] = + "Disable IPC flooding protection"; +const char kDisableIpcFloodingProtectionDescription[] = + "Some javascript code can flood the inter process communication system. " + "This protection limits the rate (calls/seconds) at which theses function " + "can be used. This flag disables the protection."; + const char kDisablePushStateThrottleName[] = "Disable pushState throttling"; const char kDisablePushStateThrottleDescription[] = "Disables throttling of history.pushState and history.replaceState method "
diff --git a/chrome/browser/flag_descriptions.h b/chrome/browser/flag_descriptions.h index cedbb44..1baf611 100644 --- a/chrome/browser/flag_descriptions.h +++ b/chrome/browser/flag_descriptions.h
@@ -219,6 +219,9 @@ extern const char kDisableAudioForDesktopShareName[]; extern const char kDisableAudioForDesktopShareDescription[]; +extern const char kDisableIpcFloodingProtectionName[]; +extern const char kDisableIpcFloodingProtectionDescription[]; + extern const char kDisablePushStateThrottleName[]; extern const char kDisablePushStateThrottleDescription[];
diff --git a/chrome/browser/gcm/gcm_profile_service_unittest.cc b/chrome/browser/gcm/gcm_profile_service_unittest.cc index 0b26e12..b2a10e8 100644 --- a/chrome/browser/gcm/gcm_profile_service_unittest.cc +++ b/chrome/browser/gcm/gcm_profile_service_unittest.cc
@@ -177,8 +177,7 @@ void GCMProfileServiceTest::CreateGCMProfileService() { gcm_profile_service_ = static_cast<GCMProfileService*>( GCMProfileServiceFactory::GetInstance()->SetTestingFactoryAndUse( - profile_.get(), - &BuildGCMProfileService)); + profile_.get(), base::BindRepeating(&BuildGCMProfileService))); gcm_profile_service_->driver()->AddAppHandler( kTestAppID, gcm_app_handler_.get()); }
diff --git a/chrome/browser/media/media_engagement_service_unittest.cc b/chrome/browser/media/media_engagement_service_unittest.cc index e9173301..8835649 100644 --- a/chrome/browser/media/media_engagement_service_unittest.cc +++ b/chrome/browser/media/media_engagement_service_unittest.cc
@@ -4,6 +4,7 @@ #include "chrome/browser/media/media_engagement_service.h" +#include "base/bind.h" #include "base/macros.h" #include "base/memory/ptr_util.h" #include "base/run_loop.h" @@ -129,7 +130,7 @@ void ConfigureHistoryService() { HistoryServiceFactory::GetInstance()->SetTestingFactory( - profile(), &BuildTestHistoryService); + profile(), base::BindRepeating(&BuildTestHistoryService)); } void RestartHistoryService() {
diff --git a/chrome/browser/media/router/event_page_request_manager_unittest.cc b/chrome/browser/media/router/event_page_request_manager_unittest.cc index 8e8ce8cc..3201b9c 100644 --- a/chrome/browser/media/router/event_page_request_manager_unittest.cc +++ b/chrome/browser/media/router/event_page_request_manager_unittest.cc
@@ -6,6 +6,7 @@ #include <memory> +#include "base/bind.h" #include "base/macros.h" #include "base/test/metrics/histogram_tester.h" #include "base/test/mock_callback.h" @@ -70,7 +71,7 @@ profile_ = std::make_unique<TestingProfile>(); // Set up a mock ProcessManager instance. extensions::ProcessManagerFactory::GetInstance()->SetTestingFactory( - profile_.get(), &TestProcessManager::Create); + profile_.get(), base::BindRepeating(&TestProcessManager::Create)); process_manager_ = static_cast<TestProcessManager*>( extensions::ProcessManager::Get(profile_.get())); DCHECK(process_manager_);
diff --git a/chrome/browser/media/router/media_router_factory_unittest.cc b/chrome/browser/media/router/media_router_factory_unittest.cc index 3cb9c9b..5e724d5 100644 --- a/chrome/browser/media/router/media_router_factory_unittest.cc +++ b/chrome/browser/media/router/media_router_factory_unittest.cc
@@ -4,6 +4,7 @@ #include <memory> +#include "base/bind.h" #include "chrome/browser/media/router/media_router_factory.h" #include "chrome/browser/media/router/test/mock_media_router.h" #include "chrome/test/base/testing_profile.h" @@ -20,7 +21,7 @@ void SetUp() override { MediaRouterFactory::GetInstance()->SetTestingFactory( - profile(), &MockMediaRouter::Create); + profile(), base::BindRepeating(&MockMediaRouter::Create)); } Profile* profile() { return &profile_; }
diff --git a/chrome/browser/media/router/mojo/media_route_controller_unittest.cc b/chrome/browser/media/router/mojo/media_route_controller_unittest.cc index 994b845..f919ab6 100644 --- a/chrome/browser/media/router/mojo/media_route_controller_unittest.cc +++ b/chrome/browser/media/router/mojo/media_route_controller_unittest.cc
@@ -7,6 +7,7 @@ #include <string> #include <utility> +#include "base/bind.h" #include "base/run_loop.h" #include "chrome/browser/media/router/event_page_request_manager_factory.h" #include "chrome/browser/media/router/media_router_factory.h" @@ -78,7 +79,8 @@ void SetUpMockObjects() { request_manager_ = static_cast<MockEventPageRequestManager*>( EventPageRequestManagerFactory::GetInstance()->SetTestingFactoryAndUse( - &profile_, &MockEventPageRequestManager::Create)); + &profile_, + base::BindRepeating(&MockEventPageRequestManager::Create))); request_manager_->set_mojo_connections_ready_for_test(true); }
diff --git a/chrome/browser/media/router/presentation/presentation_service_delegate_impl_unittest.cc b/chrome/browser/media/router/presentation/presentation_service_delegate_impl_unittest.cc index c17f965..45bf9b1 100644 --- a/chrome/browser/media/router/presentation/presentation_service_delegate_impl_unittest.cc +++ b/chrome/browser/media/router/presentation/presentation_service_delegate_impl_unittest.cc
@@ -4,6 +4,7 @@ #include "chrome/browser/media/router/presentation/presentation_service_delegate_impl.h" +#include "base/bind.h" #include "base/test/mock_callback.h" #include "build/build_config.h" #include "chrome/browser/media/router/media_router_factory.h" @@ -138,7 +139,8 @@ content::WebContents* wc = GetWebContents(); router_ = static_cast<MockMediaRouter*>( MediaRouterFactory::GetInstance()->SetTestingFactoryAndUse( - web_contents()->GetBrowserContext(), &MockMediaRouter::Create)); + web_contents()->GetBrowserContext(), + base::BindRepeating(&MockMediaRouter::Create))); ASSERT_TRUE(wc); PresentationServiceDelegateImpl::CreateForWebContents(wc); delegate_impl_ = PresentationServiceDelegateImpl::FromWebContents(wc); @@ -209,7 +211,7 @@ void SetMockLocalPresentationManager() { LocalPresentationManagerFactory::GetInstanceForTest()->SetTestingFactory( - profile(), &BuildMockLocalPresentationManager); + profile(), base::BindRepeating(&BuildMockLocalPresentationManager)); mock_local_manager_ = static_cast<MockLocalPresentationManager*>( LocalPresentationManagerFactory::GetOrCreateForBrowserContext( profile()));
diff --git a/chrome/browser/media/router/providers/extension/extension_media_route_provider_proxy_unittest.cc b/chrome/browser/media/router/providers/extension/extension_media_route_provider_proxy_unittest.cc index 04f78af..7897ea2 100644 --- a/chrome/browser/media/router/providers/extension/extension_media_route_provider_proxy_unittest.cc +++ b/chrome/browser/media/router/providers/extension/extension_media_route_provider_proxy_unittest.cc
@@ -6,6 +6,7 @@ #include <memory> +#include "base/bind.h" #include "base/macros.h" #include "base/run_loop.h" #include "base/test/mock_callback.h" @@ -57,7 +58,8 @@ void SetUp() override { request_manager_ = static_cast<MockEventPageRequestManager*>( EventPageRequestManagerFactory::GetInstance()->SetTestingFactoryAndUse( - &profile_, &MockEventPageRequestManager::Create)); + &profile_, + base::BindRepeating(&MockEventPageRequestManager::Create))); ON_CALL(*request_manager_, RunOrDeferInternal(_, _)) .WillByDefault(Invoke([](base::OnceClosure& request, MediaRouteProviderWakeReason wake_reason) {
diff --git a/chrome/browser/media/router/test/media_router_mojo_test.cc b/chrome/browser/media/router/test/media_router_mojo_test.cc index 60d9c0e..a8446126 100644 --- a/chrome/browser/media/router/test/media_router_mojo_test.cc +++ b/chrome/browser/media/router/test/media_router_mojo_test.cc
@@ -6,6 +6,7 @@ #include <utility> +#include "base/bind.h" #include "base/run_loop.h" #include "chrome/browser/media/router/event_page_request_manager_factory.h" #include "extensions/common/extension_builder.h" @@ -165,7 +166,8 @@ MediaRouterMojoTest::MediaRouterMojoTest() { request_manager_ = static_cast<MockEventPageRequestManager*>( EventPageRequestManagerFactory::GetInstance()->SetTestingFactoryAndUse( - profile(), &MockEventPageRequestManager::Create)); + profile(), + base::BindRepeating(&MockEventPageRequestManager::Create))); request_manager_->set_mojo_connections_ready_for_test(true); ON_CALL(*request_manager_, RunOrDeferInternal(_, _)) .WillByDefault(Invoke([](base::OnceClosure& request,
diff --git a/chrome/browser/media/webrtc/media_stream_devices_controller.cc b/chrome/browser/media/webrtc/media_stream_devices_controller.cc index 43c5271..4eaca9de 100644 --- a/chrome/browser/media/webrtc/media_stream_devices_controller.cc +++ b/chrome/browser/media/webrtc/media_stream_devices_controller.cc
@@ -5,7 +5,9 @@ #include "chrome/browser/media/webrtc/media_stream_devices_controller.h" #include <algorithm> +#include <memory> #include <utility> +#include <vector> #include "base/callback_helpers.h" #include "base/metrics/histogram_macros.h" @@ -37,8 +39,6 @@ #include "third_party/blink/public/mojom/feature_policy/feature_policy.mojom.h" #if defined(OS_ANDROID) -#include <vector> - #include "chrome/browser/android/android_theme_resources.h" #include "chrome/browser/android/preferences/pref_service_bridge.h" #include "chrome/browser/permissions/permission_dialog_delegate.h" @@ -135,22 +135,36 @@ bool will_prompt_for_video = false; if (controller->ShouldRequestAudio()) { + PermissionResult permission_status = + permission_manager->GetPermissionStatusForFrame( + CONTENT_SETTINGS_TYPE_MEDIASTREAM_MIC, rfh, + request.security_origin); + if (permission_status.content_setting == CONTENT_SETTING_BLOCK) { + controller->denial_reason_ = content::MEDIA_DEVICE_PERMISSION_DENIED; + controller->RunCallback(permission_status.source == + PermissionStatusSource::FEATURE_POLICY); + return; + } + content_settings_types.push_back(CONTENT_SETTINGS_TYPE_MEDIASTREAM_MIC); will_prompt_for_audio = - permission_manager->GetPermissionStatusForFrame( - CONTENT_SETTINGS_TYPE_MEDIASTREAM_MIC, - rfh, - request.security_origin).content_setting == - CONTENT_SETTING_ASK; + permission_status.content_setting == CONTENT_SETTING_ASK; } if (controller->ShouldRequestVideo()) { + PermissionResult permission_status = + permission_manager->GetPermissionStatusForFrame( + CONTENT_SETTINGS_TYPE_MEDIASTREAM_CAMERA, rfh, + request.security_origin); + if (permission_status.content_setting == CONTENT_SETTING_BLOCK) { + controller->denial_reason_ = content::MEDIA_DEVICE_PERMISSION_DENIED; + controller->RunCallback(permission_status.source == + PermissionStatusSource::FEATURE_POLICY); + return; + } + content_settings_types.push_back(CONTENT_SETTINGS_TYPE_MEDIASTREAM_CAMERA); will_prompt_for_video = - permission_manager->GetPermissionStatusForFrame( - CONTENT_SETTINGS_TYPE_MEDIASTREAM_CAMERA, - rfh, - request.security_origin).content_setting == - CONTENT_SETTING_ASK; + permission_status.content_setting == CONTENT_SETTING_ASK; } permission_manager->RequestPermissions( @@ -417,20 +431,24 @@ UpdateTabSpecificContentSettings(audio_setting_, video_setting_); } - content::MediaStreamDevices devices = - GetDevices(audio_setting_, video_setting_); + content::MediaStreamDevices devices; - // If either audio or video are allowed then the callback should report + // If all requested permissions are allowed then the callback should report // success, otherwise we report |denial_reason_|. content::MediaStreamRequestResult request_result = content::MEDIA_DEVICE_OK; - if (audio_setting_ != CONTENT_SETTING_ALLOW && - video_setting_ != CONTENT_SETTING_ALLOW) { + if ((audio_setting_ == CONTENT_SETTING_ALLOW || + audio_setting_ == CONTENT_SETTING_DEFAULT) && + (video_setting_ == CONTENT_SETTING_ALLOW || + video_setting_ == CONTENT_SETTING_DEFAULT)) { + devices = GetDevices(audio_setting_, video_setting_); + if (devices.empty()) { + // Even if all requested permissions are allowed, if there are no devices + // at this point we still report a failure. + request_result = content::MEDIA_DEVICE_NO_HARDWARE; + } + } else { DCHECK_NE(content::MEDIA_DEVICE_OK, denial_reason_); request_result = denial_reason_; - } else if (devices.empty()) { - // Even if one of the content settings was allowed, if there are no devices - // at this point we still report a failure. - request_result = content::MEDIA_DEVICE_NO_HARDWARE; } std::unique_ptr<content::MediaStreamUI> ui;
diff --git a/chrome/browser/media/webrtc/media_stream_devices_controller_browsertest.cc b/chrome/browser/media/webrtc/media_stream_devices_controller_browsertest.cc index f4f2495..34c002c 100644 --- a/chrome/browser/media/webrtc/media_stream_devices_controller_browsertest.cc +++ b/chrome/browser/media/webrtc/media_stream_devices_controller_browsertest.cc
@@ -403,7 +403,8 @@ GetContentSettings()->media_stream_selected_video_device()); } -// Request microphone and camera access. Allow microphone, block camera. +// Request microphone and camera access. Camera is denied, thus everything +// must be denied. IN_PROC_BROWSER_TEST_F(MediaStreamDevicesControllerTest, RequestMicCamBlockCam) { InitWithUrl(embedded_test_server()->GetURL("/simple.html")); @@ -417,15 +418,16 @@ base::Bind(&MediaStreamDevicesControllerTest::OnMediaStreamResponse, base::Unretained(this))); - EXPECT_TRUE(GetContentSettings()->IsContentAllowed( + EXPECT_FALSE(GetContentSettings()->IsContentAllowed( CONTENT_SETTINGS_TYPE_MEDIASTREAM_MIC)); - EXPECT_FALSE(GetContentSettings()->IsContentBlocked( + EXPECT_TRUE(GetContentSettings()->IsContentBlocked( CONTENT_SETTINGS_TYPE_MEDIASTREAM_MIC)); EXPECT_FALSE(GetContentSettings()->IsContentAllowed( CONTENT_SETTINGS_TYPE_MEDIASTREAM_CAMERA)); EXPECT_TRUE(GetContentSettings()->IsContentBlocked( CONTENT_SETTINGS_TYPE_MEDIASTREAM_CAMERA)); EXPECT_EQ(TabSpecificContentSettings::MICROPHONE_ACCESSED | + TabSpecificContentSettings::MICROPHONE_BLOCKED | TabSpecificContentSettings::CAMERA_ACCESSED | TabSpecificContentSettings::CAMERA_BLOCKED, GetContentSettings()->GetMicrophoneCameraState()); @@ -439,7 +441,8 @@ GetContentSettings()->media_stream_selected_video_device()); } -// Request microphone and camera access. Block microphone, allow camera. +// Request microphone and camera access. Microphone is denied, thus everything +// must be denied. IN_PROC_BROWSER_TEST_F(MediaStreamDevicesControllerTest, RequestMicCamBlockMic) { InitWithUrl(embedded_test_server()->GetURL("/simple.html")); @@ -457,13 +460,14 @@ CONTENT_SETTINGS_TYPE_MEDIASTREAM_MIC)); EXPECT_TRUE(GetContentSettings()->IsContentBlocked( CONTENT_SETTINGS_TYPE_MEDIASTREAM_MIC)); - EXPECT_TRUE(GetContentSettings()->IsContentAllowed( + EXPECT_FALSE(GetContentSettings()->IsContentAllowed( CONTENT_SETTINGS_TYPE_MEDIASTREAM_CAMERA)); - EXPECT_FALSE(GetContentSettings()->IsContentBlocked( + EXPECT_TRUE(GetContentSettings()->IsContentBlocked( CONTENT_SETTINGS_TYPE_MEDIASTREAM_CAMERA)); EXPECT_EQ(TabSpecificContentSettings::MICROPHONE_ACCESSED | TabSpecificContentSettings::MICROPHONE_BLOCKED | - TabSpecificContentSettings::CAMERA_ACCESSED, + TabSpecificContentSettings::CAMERA_ACCESSED | + TabSpecificContentSettings::CAMERA_BLOCKED, GetContentSettings()->GetMicrophoneCameraState()); EXPECT_EQ(example_audio_id(), GetContentSettings()->media_stream_requested_audio_device()); @@ -612,8 +616,12 @@ // Whether the infobar should be displayed to request mic/cam for the given // content settings inputs. - bool ExpectMicInfobar() const { return mic == CONTENT_SETTING_ASK; } - bool ExpectCamInfobar() const { return cam == CONTENT_SETTING_ASK; } + bool ExpectMicInfobar() const { + return mic == CONTENT_SETTING_ASK && cam != CONTENT_SETTING_BLOCK; + } + bool ExpectCamInfobar() const { + return cam == CONTENT_SETTING_ASK && mic != CONTENT_SETTING_BLOCK; + } // Whether or not the mic/cam should be allowed after clicking accept/deny for // the given inputs. @@ -629,7 +637,7 @@ // The expected media stream result after clicking accept/deny for the given // inputs. content::MediaStreamRequestResult ExpectedMediaStreamResult() const { - if (ExpectMicAllowed() || ExpectCamAllowed()) + if (ExpectMicAllowed() && ExpectCamAllowed()) return content::MEDIA_DEVICE_OK; return content::MEDIA_DEVICE_PERMISSION_DENIED; } @@ -645,6 +653,8 @@ {CONTENT_SETTING_ALLOW, CONTENT_SETTING_BLOCK, false}, {CONTENT_SETTING_BLOCK, CONTENT_SETTING_ALLOW, false}, {CONTENT_SETTING_BLOCK, CONTENT_SETTING_BLOCK, false}, + {CONTENT_SETTING_BLOCK, CONTENT_SETTING_ASK, false}, + {CONTENT_SETTING_ASK, CONTENT_SETTING_BLOCK, false}, // Settings that will result in an infobar. Test both accept and deny. {CONTENT_SETTING_ALLOW, CONTENT_SETTING_ASK, false}, @@ -653,14 +663,8 @@ {CONTENT_SETTING_ASK, CONTENT_SETTING_ASK, false}, {CONTENT_SETTING_ASK, CONTENT_SETTING_ASK, true}, - {CONTENT_SETTING_BLOCK, CONTENT_SETTING_ASK, false}, - {CONTENT_SETTING_BLOCK, CONTENT_SETTING_ASK, true}, - {CONTENT_SETTING_ASK, CONTENT_SETTING_ALLOW, false}, {CONTENT_SETTING_ASK, CONTENT_SETTING_ALLOW, true}, - - {CONTENT_SETTING_ASK, CONTENT_SETTING_BLOCK, false}, - {CONTENT_SETTING_ASK, CONTENT_SETTING_BLOCK, true}, }; for (auto& test : tests) { @@ -696,9 +700,9 @@ // expected; ASSERT_EQ(test.ExpectedMediaStreamResult(), media_stream_result()); ASSERT_EQ(CheckDevicesListContains(content::MEDIA_DEVICE_AUDIO_CAPTURE), - test.ExpectMicAllowed()); + test.ExpectMicAllowed() && test.ExpectCamAllowed()); ASSERT_EQ(CheckDevicesListContains(content::MEDIA_DEVICE_VIDEO_CAPTURE), - test.ExpectCamAllowed()); + test.ExpectMicAllowed() && test.ExpectCamAllowed()); } }
diff --git a/chrome/browser/metrics/chrome_feature_list_creator.cc b/chrome/browser/metrics/chrome_feature_list_creator.cc new file mode 100644 index 0000000..06eb1fe --- /dev/null +++ b/chrome/browser/metrics/chrome_feature_list_creator.cc
@@ -0,0 +1,170 @@ +// 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/metrics/chrome_feature_list_creator.h" + +#include <set> + +#include "base/base_switches.h" +#include "base/feature_list.h" +#include "base/files/file_path.h" +#include "base/files/file_util.h" +#include "base/memory/scoped_refptr.h" +#include "base/path_service.h" +#include "base/time/time.h" +#include "base/trace_event/trace_event.h" +#include "cc/base/switches.h" +#include "chrome/browser/about_flags.h" +#include "chrome/browser/metrics/chrome_metrics_service_accessor.h" +#include "chrome/browser/metrics/chrome_metrics_services_manager_client.h" +#include "chrome/browser/prefs/browser_prefs.h" +#include "chrome/browser/prefs/chrome_pref_service_factory.h" +#include "chrome/common/chrome_paths.h" +#include "chrome/common/pref_names.h" +#include "components/flags_ui/flags_ui_pref_names.h" +#include "components/flags_ui/pref_service_flags_storage.h" +#include "components/language/core/browser/pref_names.h" +#include "components/metrics/clean_exit_beacon.h" +#include "components/metrics/metrics_pref_names.h" +#include "components/metrics/metrics_state_manager.h" +#include "components/metrics_services_manager/metrics_services_manager.h" +#include "components/policy/core/common/policy_service.h" +#include "components/prefs/pref_registry.h" +#include "components/prefs/pref_registry_simple.h" +#include "components/prefs/pref_service_factory.h" +#include "components/variations/pref_names.h" +#include "components/variations/service/variations_service.h" +#include "components/variations/variations_crash_keys.h" +#include "ui/base/resource/resource_bundle.h" + +#if defined(OS_CHROMEOS) +#include "chrome/browser/chromeos/dbus/dbus_helper.h" +#include "chrome/browser/chromeos/policy/browser_policy_connector_chromeos.h" +#endif + +ChromeFeatureListCreator::ChromeFeatureListCreator() = default; + +ChromeFeatureListCreator::~ChromeFeatureListCreator() = default; + +void ChromeFeatureListCreator::CreateFeatureList() { + CreatePrefService(); + ConvertFlagsToSwitches(); + CreateMetricsServices(); + SetupFieldTrials(); +} + +metrics_services_manager::MetricsServicesManagerClient* +ChromeFeatureListCreator::GetMetricsServicesManagerClient() { + return metrics_services_manager_client_; +} + +std::unique_ptr<PrefService> ChromeFeatureListCreator::TakePrefService() { + return std::move(local_state_); +} + +std::unique_ptr<metrics_services_manager::MetricsServicesManager> +ChromeFeatureListCreator::TakeMetricsServicesManager() { + return std::move(metrics_services_manager_); +} + +std::unique_ptr<policy::ChromeBrowserPolicyConnector> +ChromeFeatureListCreator::TakeChromeBrowserPolicyConnector() { + return std::move(browser_policy_connector_); +} + +std::unique_ptr<prefs::InProcessPrefServiceFactory> +ChromeFeatureListCreator::TakePrefServiceFactory() { + return std::move(pref_service_factory_); +} + +void ChromeFeatureListCreator::CreatePrefService() { + base::FilePath local_state_file; + bool result = + base::PathService::Get(chrome::FILE_LOCAL_STATE, &local_state_file); + DCHECK(result); + + auto pref_registry = base::MakeRefCounted<PrefRegistrySimple>(); + RegisterLocalState(pref_registry.get()); + +#if defined(OS_CHROMEOS) + chromeos::PreEarlyInitDBus(); + browser_policy_connector_ = + std::make_unique<policy::BrowserPolicyConnectorChromeOS>(); +#else + browser_policy_connector_ = + std::make_unique<policy::ChromeBrowserPolicyConnector>(); +#endif // defined(OS_CHROMEOS) + + pref_service_factory_ = + std::make_unique<prefs::InProcessPrefServiceFactory>(); + auto delegate = pref_service_factory_->CreateDelegate(); + delegate->InitPrefRegistry(pref_registry.get()); + + local_state_ = chrome_prefs::CreateLocalState( + local_state_file, browser_policy_connector_->GetPolicyService(), + std::move(pref_registry), false, std::move(delegate), + browser_policy_connector_.get()); +} + +void ChromeFeatureListCreator::ConvertFlagsToSwitches() { +#if !defined(OS_CHROMEOS) + // Convert active flags into switches. This needs to be done before + // ui::ResourceBundle::InitSharedInstanceWithLocale as some loaded resources + // are affected by experiment flags (--touch-optimized-ui in particular). On + // ChromeOS system level flags are applied from the device settings from the + // session manager. + DCHECK(!ui::ResourceBundle::HasSharedInstance()); + TRACE_EVENT0("startup", "ChromeFeatureListCreator::ConvertFlagsToSwitches"); + flags_ui::PrefServiceFlagsStorage flags_storage(local_state_.get()); + about_flags::ConvertFlagsToSwitches(&flags_storage, + base::CommandLine::ForCurrentProcess(), + flags_ui::kAddSentinels); +#endif // !defined(OS_CHROMEOS) +} + +void ChromeFeatureListCreator::SetupFieldTrials() { + browser_field_trials_ = std::make_unique<ChromeBrowserFieldTrials>(); + + // Initialize FieldTrialList to support FieldTrials. This is intentionally + // leaked since it needs to live for the duration of the browser process and + // there's no benefit in cleaning it up at exit. + base::FieldTrialList* leaked_field_trial_list = new base::FieldTrialList( + metrics_services_manager_.get()->CreateEntropyProvider()); + ANNOTATE_LEAKING_OBJECT_PTR(leaked_field_trial_list); + ignore_result(leaked_field_trial_list); + + auto feature_list = std::make_unique<base::FeatureList>(); + + // Associate parameters chosen in about:flags and create trial/group for them. + flags_ui::PrefServiceFlagsStorage flags_storage(local_state_.get()); + std::vector<std::string> variation_ids = + about_flags::RegisterAllFeatureVariationParameters(&flags_storage, + feature_list.get()); + + std::set<std::string> unforceable_field_trials; +#if defined(OFFICIAL_BUILD) + unforceable_field_trials.insert("SettingsEnforcement"); +#endif // defined(OFFICIAL_BUILD) + + variations::VariationsService* variations_service = + metrics_services_manager_.get()->GetVariationsService(); + variations_service->SetupFieldTrials( + cc::switches::kEnableGpuBenchmarking, switches::kEnableFeatures, + switches::kDisableFeatures, unforceable_field_trials, variation_ids, + std::move(feature_list), browser_field_trials_.get()); + variations::InitCrashKeys(); + + // Initialize FieldTrialSynchronizer system, which is used to synchronize + // field trial state with child process. + field_trial_synchronizer_ = base::MakeRefCounted<FieldTrialSynchronizer>(); +} + +void ChromeFeatureListCreator::CreateMetricsServices() { + auto client = + std::make_unique<ChromeMetricsServicesManagerClient>(local_state_.get()); + metrics_services_manager_client_ = client.get(); + metrics_services_manager_ = + std::make_unique<metrics_services_manager::MetricsServicesManager>( + std::move(client)); +}
diff --git a/chrome/browser/metrics/chrome_feature_list_creator.h b/chrome/browser/metrics/chrome_feature_list_creator.h new file mode 100644 index 0000000..39a32d7 --- /dev/null +++ b/chrome/browser/metrics/chrome_feature_list_creator.h
@@ -0,0 +1,80 @@ +// 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_METRICS_CHROME_FEATURE_LIST_CREATOR_H_ +#define CHROME_BROWSER_METRICS_CHROME_FEATURE_LIST_CREATOR_H_ + +#include "base/macros.h" +#include "chrome/browser/chrome_browser_field_trials.h" +#include "chrome/browser/metrics/field_trial_synchronizer.h" +#include "chrome/browser/policy/chrome_browser_policy_connector.h" +#include "components/metrics_services_manager/metrics_services_manager.h" +#include "components/prefs/pref_service.h" +#include "services/preferences/public/cpp/in_process_service_factory.h" + +class ChromeMetricsServicesManagerClient; + +// The ChromeFeatureListCreator creates the FeatureList and classes required for +// setting up field trials, e.g. VariationsService, MetricsServicesManager etc. +// before the full browser loop starts. The |local_state| is instantiated, and +// its ownership will be taken by BrowserProcessImpl when the full browser +// starts. +class ChromeFeatureListCreator { + public: + ChromeFeatureListCreator(); + ~ChromeFeatureListCreator(); + + // Initializes all necessary parameters to create the feature list and calls + // base::FeatureList::SetInstance() to set the global instance. + void CreateFeatureList(); + + // Gets the MetricsServicesManagerClient* used in this class. + metrics_services_manager::MetricsServicesManagerClient* + GetMetricsServicesManagerClient(); + + // Passes ownership of the |local_state_| to the caller. + std::unique_ptr<PrefService> TakePrefService(); + + // Passes ownership of the |metrics_services_manager_| to the caller. + std::unique_ptr<metrics_services_manager::MetricsServicesManager> + TakeMetricsServicesManager(); + + // Passes ownership of the |browser_policy_connector_| to the caller. + std::unique_ptr<policy::ChromeBrowserPolicyConnector> + TakeChromeBrowserPolicyConnector(); + + // Passes ownership of the |pref_service_factory_| to the caller. + std::unique_ptr<prefs::InProcessPrefServiceFactory> TakePrefServiceFactory(); + + PrefService* local_state() { return local_state_.get(); } + + private: + void CreatePrefService(); + void ConvertFlagsToSwitches(); + void SetupFieldTrials(); + void CreateMetricsServices(); + + // If TakePrefService() is called, the caller will take the ownership + // of this variable. Stop using this variable afterwards. + std::unique_ptr<PrefService> local_state_; + + // This is owned by |metrics_services_manager_| but we need to expose it. + ChromeMetricsServicesManagerClient* metrics_services_manager_client_; + + std::unique_ptr<metrics_services_manager::MetricsServicesManager> + metrics_services_manager_; + + scoped_refptr<FieldTrialSynchronizer> field_trial_synchronizer_; + + std::unique_ptr<ChromeBrowserFieldTrials> browser_field_trials_; + + std::unique_ptr<policy::ChromeBrowserPolicyConnector> + browser_policy_connector_; + + std::unique_ptr<prefs::InProcessPrefServiceFactory> pref_service_factory_; + + DISALLOW_COPY_AND_ASSIGN(ChromeFeatureListCreator); +}; + +#endif // CHROME_BROWSER_METRICS_CHROME_FEATURE_LIST_CREATOR_H_
diff --git a/chrome/browser/metrics/chrome_metrics_service_accessor.cc b/chrome/browser/metrics/chrome_metrics_service_accessor.cc index b4ca128..76b98cc 100644 --- a/chrome/browser/metrics/chrome_metrics_service_accessor.cc +++ b/chrome/browser/metrics/chrome_metrics_service_accessor.cc
@@ -32,6 +32,12 @@ // static bool ChromeMetricsServiceAccessor::IsMetricsAndCrashReportingEnabled() { + return IsMetricsAndCrashReportingEnabled(g_browser_process->local_state()); +} + +// static +bool ChromeMetricsServiceAccessor::IsMetricsAndCrashReportingEnabled( + PrefService* local_state) { if (g_metrics_consent_for_testing) return *g_metrics_consent_for_testing; @@ -44,12 +50,12 @@ // This is only possible during unit tests. If the unit test didn't set the // local_state then it doesn't care about pref value and therefore we return // false. - if (!g_browser_process->local_state()) { + if (!local_state) { DLOG(WARNING) << "Local state has not been set and pref cannot be read"; return false; } - return IsMetricsReportingEnabled(g_browser_process->local_state()); + return IsMetricsReportingEnabled(local_state); } // static
diff --git a/chrome/browser/metrics/chrome_metrics_service_accessor.h b/chrome/browser/metrics/chrome_metrics_service_accessor.h index f6ee3ad..9b8ffa1 100644 --- a/chrome/browser/metrics/chrome_metrics_service_accessor.h +++ b/chrome/browser/metrics/chrome_metrics_service_accessor.h
@@ -18,6 +18,7 @@ class ChromeMetricsServiceClient; class ChromePasswordManagerClient; class NavigationMetricsRecorder; +class PrefService; class Profile; namespace { @@ -155,6 +156,11 @@ // http://crbug.com/362192, http://crbug.com/532084 static bool IsMetricsAndCrashReportingEnabled(); + // This is identical to the function without the |local_state| param but can + // be called before |g_browser_process| has been created by specifying the + // Local State pref service. + static bool IsMetricsAndCrashReportingEnabled(PrefService* local_state); + // Calls metrics::MetricsServiceAccessor::RegisterSyntheticFieldTrial() with // g_browser_process->metrics_service(). See that function's declaration for // details.
diff --git a/chrome/browser/metrics/chrome_metrics_services_manager_client.cc b/chrome/browser/metrics/chrome_metrics_services_manager_client.cc index 38cae30..0c3e8cf 100644 --- a/chrome/browser/metrics/chrome_metrics_services_manager_client.cc +++ b/chrome/browser/metrics/chrome_metrics_services_manager_client.cc
@@ -120,11 +120,13 @@ class ChromeMetricsServicesManagerClient::ChromeEnabledStateProvider : public metrics::EnabledStateProvider { public: - ChromeEnabledStateProvider() {} + explicit ChromeEnabledStateProvider(PrefService* local_state) + : local_state_(local_state) {} ~ChromeEnabledStateProvider() override {} bool IsConsentGiven() const override { - return ChromeMetricsServiceAccessor::IsMetricsAndCrashReportingEnabled(); + return ChromeMetricsServiceAccessor::IsMetricsAndCrashReportingEnabled( + local_state_); } bool IsReportingEnabled() const override { @@ -132,12 +134,16 @@ ChromeMetricsServicesManagerClient::IsClientInSample(); } + private: + PrefService* const local_state_; + DISALLOW_COPY_AND_ASSIGN(ChromeEnabledStateProvider); }; ChromeMetricsServicesManagerClient::ChromeMetricsServicesManagerClient( PrefService* local_state) - : enabled_state_provider_(std::make_unique<ChromeEnabledStateProvider>()), + : enabled_state_provider_( + std::make_unique<ChromeEnabledStateProvider>(local_state)), local_state_(local_state) { DCHECK(local_state); }
diff --git a/chrome/browser/metrics/variations/chrome_variations_service_client.cc b/chrome/browser/metrics/variations/chrome_variations_service_client.cc index 420e21eb..2eef13c 100644 --- a/chrome/browser/metrics/variations/chrome_variations_service_client.cc +++ b/chrome/browser/metrics/variations/chrome_variations_service_client.cc
@@ -43,10 +43,6 @@ ChromeVariationsServiceClient::~ChromeVariationsServiceClient() {} -std::string ChromeVariationsServiceClient::GetApplicationLocale() { - return g_browser_process->GetApplicationLocale(); -} - base::Callback<base::Version(void)> ChromeVariationsServiceClient::GetVersionForSimulationCallback() { return base::Bind(&GetVersionForSimulation);
diff --git a/chrome/browser/metrics/variations/chrome_variations_service_client.h b/chrome/browser/metrics/variations/chrome_variations_service_client.h index 84c50dc..f65b92e 100644 --- a/chrome/browser/metrics/variations/chrome_variations_service_client.h +++ b/chrome/browser/metrics/variations/chrome_variations_service_client.h
@@ -24,7 +24,6 @@ ~ChromeVariationsServiceClient() override; // variations::VariationsServiceClient: - std::string GetApplicationLocale() override; base::Callback<base::Version(void)> GetVersionForSimulationCallback() override; scoped_refptr<network::SharedURLLoaderFactory> GetURLLoaderFactory() override;
diff --git a/chrome/browser/password_manager/chrome_password_manager_client_unittest.cc b/chrome/browser/password_manager/chrome_password_manager_client_unittest.cc index a2ef93aa..4ddfd67a 100644 --- a/chrome/browser/password_manager/chrome_password_manager_client_unittest.cc +++ b/chrome/browser/password_manager/chrome_password_manager_client_unittest.cc
@@ -9,6 +9,7 @@ #include <string> #include <utility> +#include "base/bind.h" #include "base/command_line.h" #include "base/macros.h" #include "base/metrics/field_trial.h" @@ -186,7 +187,7 @@ ProfileSyncServiceMock* mock_sync_service = static_cast<ProfileSyncServiceMock*>( ProfileSyncServiceFactory::GetInstance()->SetTestingFactoryAndUse( - profile(), BuildMockProfileSyncService)); + profile(), base::BindRepeating(&BuildMockProfileSyncService))); EXPECT_CALL(*mock_sync_service, IsFirstSetupComplete()) .WillRepeatedly(Return(true)); @@ -493,9 +494,11 @@ // PasswordStore is needed for processing forms in PasswordManager later in // the test. PasswordStoreFactory::GetInstance()->SetTestingFactoryAndUse( - profile(), password_manager::BuildPasswordStore< - content::BrowserContext, - testing::NiceMock<password_manager::MockPasswordStore>>); + profile(), + base::BindRepeating( + &password_manager::BuildPasswordStore< + content::BrowserContext, + testing::NiceMock<password_manager::MockPasswordStore>>)); // about:blank is one of the pages where password manager should not work. const GURL kUrlOff(url::kAboutBlankURL);
diff --git a/chrome/browser/password_manager/password_manager_test_base.cc b/chrome/browser/password_manager/password_manager_test_base.cc index 7fdba08..e38c50e 100644 --- a/chrome/browser/password_manager/password_manager_test_base.cc +++ b/chrome/browser/password_manager/password_manager_test_base.cc
@@ -9,6 +9,7 @@ #include <utility> #include <vector> +#include "base/bind.h" #include "base/macros.h" #include "base/memory/ptr_util.h" #include "base/memory/ref_counted.h" @@ -422,8 +423,9 @@ // PasswordStore has not completed. PasswordStoreFactory::GetInstance()->SetTestingFactory( browser->profile(), - password_manager::BuildPasswordStore< - content::BrowserContext, password_manager::TestPasswordStore>); + base::BindRepeating( + &password_manager::BuildPasswordStore< + content::BrowserContext, password_manager::TestPasswordStore>)); // Add a tab with a customized ManagePasswordsUIController. Thus, we can // intercept useful UI events.
diff --git a/chrome/browser/password_manager/password_store_signin_notifier_impl_unittest.cc b/chrome/browser/password_manager/password_store_signin_notifier_impl_unittest.cc index c81c1d3..8760c48 100644 --- a/chrome/browser/password_manager/password_store_signin_notifier_impl_unittest.cc +++ b/chrome/browser/password_manager/password_store_signin_notifier_impl_unittest.cc
@@ -4,6 +4,7 @@ #include "chrome/browser/password_manager/password_store_signin_notifier_impl.h" +#include "base/bind.h" #include "chrome/browser/signin/account_tracker_service_factory.h" #include "chrome/browser/signin/fake_signin_manager_builder.h" #include "chrome/browser/signin/signin_manager_factory.h" @@ -22,7 +23,7 @@ PasswordStoreSigninNotifierImplTest() { TestingProfile::Builder builder; builder.AddTestingFactory(SigninManagerFactory::GetInstance(), - BuildFakeSigninManagerBase); + base::BindRepeating(&BuildFakeSigninManagerBase)); testing_profile_.reset(builder.Build().release()); fake_signin_manager_ = static_cast<FakeSigninManagerForTesting*>( SigninManagerFactory::GetForProfile(testing_profile_.get()));
diff --git a/chrome/browser/plugins/plugin_prefs.cc b/chrome/browser/plugins/plugin_prefs.cc index ca4b960..af4dad8 100644 --- a/chrome/browser/plugins/plugin_prefs.cc +++ b/chrome/browser/plugins/plugin_prefs.cc
@@ -72,8 +72,11 @@ scoped_refptr<PluginPrefs> PluginPrefs::GetForTestingProfile( Profile* profile) { return static_cast<PluginPrefs*>( - PluginPrefsFactory::GetInstance()->SetTestingFactoryAndUse( - profile, &PluginPrefsFactory::CreateForTestingProfile).get()); + PluginPrefsFactory::GetInstance() + ->SetTestingFactoryAndUse( + profile, + base::BindRepeating(&PluginPrefsFactory::CreateForTestingProfile)) + .get()); } PluginPrefs::PolicyStatus PluginPrefs::PolicyStatusForPlugin(
diff --git a/chrome/browser/policy/cloud/user_policy_signin_service_unittest.cc b/chrome/browser/policy/cloud/user_policy_signin_service_unittest.cc index 196dfa2..fc1759eab 100644 --- a/chrome/browser/policy/cloud/user_policy_signin_service_unittest.cc +++ b/chrome/browser/policy/cloud/user_policy_signin_service_unittest.cc
@@ -178,13 +178,16 @@ std::unique_ptr<sync_preferences::PrefServiceSyncable>( std::move(prefs))); builder.AddTestingFactory(SigninManagerFactory::GetInstance(), - BuildFakeSigninManagerBase); - builder.AddTestingFactory(ProfileOAuth2TokenServiceFactory::GetInstance(), - BuildFakeProfileOAuth2TokenService); - builder.AddTestingFactory(AccountFetcherServiceFactory::GetInstance(), - FakeAccountFetcherServiceBuilder::BuildForTests); - builder.AddTestingFactory(ChromeSigninClientFactory::GetInstance(), - signin::BuildTestSigninClient); + base::BindRepeating(&BuildFakeSigninManagerBase)); + builder.AddTestingFactory( + ProfileOAuth2TokenServiceFactory::GetInstance(), + base::BindRepeating(&BuildFakeProfileOAuth2TokenService)); + builder.AddTestingFactory( + AccountFetcherServiceFactory::GetInstance(), + base::BindRepeating(&FakeAccountFetcherServiceBuilder::BuildForTests)); + builder.AddTestingFactory( + ChromeSigninClientFactory::GetInstance(), + base::BindRepeating(&signin::BuildTestSigninClient)); profile_ = builder.Build();
diff --git a/chrome/browser/prefs/chrome_pref_service_factory.cc b/chrome/browser/prefs/chrome_pref_service_factory.cc index 062c4fc..d45d690 100644 --- a/chrome/browser/prefs/chrome_pref_service_factory.cc +++ b/chrome/browser/prefs/chrome_pref_service_factory.cc
@@ -334,9 +334,8 @@ SupervisedUserSettingsService* supervised_user_settings, scoped_refptr<PersistentPrefStore> user_pref_store, scoped_refptr<PrefStore> extension_prefs, - bool async) { - policy::BrowserPolicyConnector* policy_connector = - g_browser_process->browser_policy_connector(); + bool async, + policy::BrowserPolicyConnector* policy_connector) { factory->SetManagedPolicies(policy_service, policy_connector); factory->SetRecommendedPolicies(policy_service, policy_connector); @@ -406,14 +405,15 @@ policy::PolicyService* policy_service, scoped_refptr<PrefRegistry> pref_registry, bool async, - std::unique_ptr<PrefValueStore::Delegate> delegate) { + std::unique_ptr<PrefValueStore::Delegate> delegate, + policy::BrowserPolicyConnector* policy_connector) { sync_preferences::PrefServiceSyncableFactory factory; PrepareFactory(&factory, pref_filename, policy_service, nullptr, // supervised_user_settings base::MakeRefCounted<JsonPrefStore>( pref_filename, std::unique_ptr<PrefFilter>()), nullptr, // extension_prefs - async); + async, policy_connector); return factory.Create(std::move(pref_registry), std::move(delegate)); } @@ -444,7 +444,8 @@ std::move(validation_delegate)); PrepareFactory(&factory, profile_path, policy_service, supervised_user_settings, std::move(user_pref_store), - std::move(extension_prefs), async); + std::move(extension_prefs), async, + g_browser_process->browser_policy_connector()); return factory.CreateSyncable(std::move(pref_registry), std::move(delegate)); }
diff --git a/chrome/browser/prefs/chrome_pref_service_factory.h b/chrome/browser/prefs/chrome_pref_service_factory.h index 7dd4cf5..b752929 100644 --- a/chrome/browser/prefs/chrome_pref_service_factory.h +++ b/chrome/browser/prefs/chrome_pref_service_factory.h
@@ -21,6 +21,7 @@ namespace policy { class PolicyService; +class BrowserPolicyConnector; } namespace sync_preferences { @@ -69,7 +70,8 @@ policy::PolicyService* policy_service, scoped_refptr<PrefRegistry> pref_registry, bool async, - std::unique_ptr<PrefValueStore::Delegate> delegate); + std::unique_ptr<PrefValueStore::Delegate> delegate, + policy::BrowserPolicyConnector* policy_connector); std::unique_ptr<sync_preferences::PrefServiceSyncable> CreateProfilePrefs( const base::FilePath& pref_filename,
diff --git a/chrome/browser/profiles/profile_downloader_unittest.cc b/chrome/browser/profiles/profile_downloader_unittest.cc index ece42d13d..33735e4a 100644 --- a/chrome/browser/profiles/profile_downloader_unittest.cc +++ b/chrome/browser/profiles/profile_downloader_unittest.cc
@@ -4,6 +4,7 @@ #include "chrome/browser/profiles/profile_downloader.h" +#include "base/bind.h" #include "base/strings/string_util.h" #include "base/strings/utf_string_conversions.h" #include "chrome/browser/profiles/profile_downloader_delegate.h" @@ -45,10 +46,12 @@ void SetUp() override { TestingProfile::Builder builder; - builder.AddTestingFactory(ProfileOAuth2TokenServiceFactory::GetInstance(), - &BuildFakeProfileOAuth2TokenService); - builder.AddTestingFactory(AccountFetcherServiceFactory::GetInstance(), - FakeAccountFetcherServiceBuilder::BuildForTests); + builder.AddTestingFactory( + ProfileOAuth2TokenServiceFactory::GetInstance(), + base::BindRepeating(&BuildFakeProfileOAuth2TokenService)); + builder.AddTestingFactory( + AccountFetcherServiceFactory::GetInstance(), + base::BindRepeating(&FakeAccountFetcherServiceBuilder::BuildForTests)); profile_ = builder.Build(); account_tracker_service_ = AccountTrackerServiceFactory::GetForProfile(profile_.get());
diff --git a/chrome/browser/profiles/profile_statistics_browsertest.cc b/chrome/browser/profiles/profile_statistics_browsertest.cc index 26288b6..b8efe8d 100644 --- a/chrome/browser/profiles/profile_statistics_browsertest.cc +++ b/chrome/browser/profiles/profile_statistics_browsertest.cc
@@ -167,8 +167,9 @@ // PasswordStore has not completed. PasswordStoreFactory::GetInstance()->SetTestingFactory( browser()->profile(), - password_manager::BuildPasswordStore< - content::BrowserContext, password_manager::TestPasswordStore>); + base::BindRepeating( + &password_manager::BuildPasswordStore< + content::BrowserContext, password_manager::TestPasswordStore>)); } };
diff --git a/chrome/browser/profiles/profile_statistics_unittest.cc b/chrome/browser/profiles/profile_statistics_unittest.cc index cbd48262..5a5cfb6 100644 --- a/chrome/browser/profiles/profile_statistics_unittest.cc +++ b/chrome/browser/profiles/profile_statistics_unittest.cc
@@ -10,6 +10,7 @@ #include <utility> #include <vector> +#include "base/bind.h" #include "base/files/file_path.h" #include "base/run_loop.h" #include "base/task/post_task.h" @@ -58,7 +59,7 @@ bookmarks::BookmarkModel* CreateBookmarkModelWithoutLoad(Profile* profile) { return static_cast<bookmarks::BookmarkModel*>( BookmarkModelFactory::GetInstance()->SetTestingFactoryAndUse( - profile, BuildBookmarkModelWithoutLoad)); + profile, base::BindRepeating(&BuildBookmarkModelWithoutLoad))); } class BookmarkStatHelper { @@ -106,8 +107,9 @@ profile->CreateWebDataService(); PasswordStoreFactory::GetInstance()->SetTestingFactory( profile, - password_manager::BuildPasswordStore< - content::BrowserContext, password_manager::TestPasswordStore>); + base::BindRepeating( + &password_manager::BuildPasswordStore< + content::BrowserContext, password_manager::TestPasswordStore>)); bookmarks::BookmarkModel* bookmark_model = CreateBookmarkModelWithoutLoad(profile);
diff --git a/chrome/browser/resource_coordinator/local_site_characteristics_webcontents_observer_unittest.cc b/chrome/browser/resource_coordinator/local_site_characteristics_webcontents_observer_unittest.cc index d5af72e..4c15d6d 100644 --- a/chrome/browser/resource_coordinator/local_site_characteristics_webcontents_observer_unittest.cc +++ b/chrome/browser/resource_coordinator/local_site_characteristics_webcontents_observer_unittest.cc
@@ -4,6 +4,7 @@ #include "chrome/browser/resource_coordinator/local_site_characteristics_webcontents_observer.h" +#include "base/bind.h" #include "base/macros.h" #include "base/test/simple_test_tick_clock.h" #include "chrome/browser/resource_coordinator/local_site_characteristics_data_store_factory.h" @@ -91,7 +92,7 @@ test_clock().Advance(base::TimeDelta::FromSeconds(1)); // Set the testing factory for the test browser context. LocalSiteCharacteristicsDataStoreFactory::GetInstance()->SetTestingFactory( - browser_context(), &BuildMockDataStoreForContext); + browser_context(), base::BindRepeating(&BuildMockDataStoreForContext)); TabLoadTracker::Get()->StartTracking(web_contents()); LocalSiteCharacteristicsWebContentsObserver::
diff --git a/chrome/browser/resources/chromeos/login/offline_ad_login.html b/chrome/browser/resources/chromeos/login/offline_ad_login.html index 931d0ef..6cec2960c 100644 --- a/chrome/browser/resources/chromeos/login/offline_ad_login.html +++ b/chrome/browser/resources/chromeos/login/offline_ad_login.html
@@ -101,7 +101,7 @@ hidden="[[!isDomainJoin]]" value="[[machineName]]" disabled="[[disabled]]" invalid="[[machineNameInvalid]]" pattern="[[machineNameInputPattern_]]" - label="[[getMachineNameLabel_(locale, selectedConfigOption_)]]" + label="[[i18nDynamic(locale, 'oauthEnrollAdMachineNameInput')]]" on-keydown="onKeydownMachineNameInput_" error-message="[[getMachineNameError_(locale, errorState, selectedConfigOption_)]]"> @@ -114,7 +114,7 @@ label="[[i18nDynamic(locale, 'adAuthLoginUsername')]]" on-keydown="onKeydownUserInput_" error-message="[[i18nDynamic(locale, 'adLoginInvalidUsername')]]"> - <span slot="suffix" hidden="[[domainHidden(userName)]]"> + <span slot="suffix" hidden="[[domainHidden(userRealm, userName)]]"> [[userRealm]] </span> </cr-input>
diff --git a/chrome/browser/resources/chromeos/login/offline_ad_login.js b/chrome/browser/resources/chromeos/login/offline_ad_login.js index 1086933..620deb8f 100644 --- a/chrome/browser/resources/chromeos/login/offline_ad_login.js +++ b/chrome/browser/resources/chromeos/login/offline_ad_login.js
@@ -429,15 +429,6 @@ return errorState != ACTIVE_DIRECTORY_ERROR_STATE.MACHINE_NAME_TOO_LONG; }, - getMachineNameLabel_: function(locale) { - if (this.machineNameInputPattern_) { - return this.i18nDynamic( - locale, 'oauthEnrollAdMachineNameInputRegex', - this.machineNameInputPattern_); - } - return this.i18nDynamic(locale, 'oauthEnrollAdMachineNameInput'); - }, - getMachineNameError_: function(locale, errorState) { if (errorState == ACTIVE_DIRECTORY_ERROR_STATE.MACHINE_NAME_TOO_LONG) return this.i18nDynamic(locale, 'adJoinErrorMachineNameTooLong'); @@ -485,8 +476,8 @@ } }, - domainHidden: function(userName) { - return userName && userName.includes('@'); + domainHidden: function(userRealm, userName) { + return !userRealm || (userName && userName.includes('@')); }, onKeydownAuthPasswordInput_: function(e) {
diff --git a/chrome/browser/resources/chromeos/login/screen_gaia_signin.js b/chrome/browser/resources/chromeos/login/screen_gaia_signin.js index cc6646f..2578171 100644 --- a/chrome/browser/resources/chromeos/login/screen_gaia_signin.js +++ b/chrome/browser/resources/chromeos/login/screen_gaia_signin.js
@@ -1272,8 +1272,6 @@ if ('emailDomain' in params) adAuthUI.userRealm = '@' + params['emailDomain']; - else if ('realm' in params) - adAuthUI.userRealm = '@' + params['realm']; adAuthUI.userName = params['email']; adAuthUI.focus();
diff --git a/chrome/browser/resources/chromeos/multidevice_setup/BUILD.gn b/chrome/browser/resources/chromeos/multidevice_setup/BUILD.gn index 0b624c9..470e0c0 100644 --- a/chrome/browser/resources/chromeos/multidevice_setup/BUILD.gn +++ b/chrome/browser/resources/chromeos/multidevice_setup/BUILD.gn
@@ -14,6 +14,7 @@ js_library("multidevice_setup_post_oobe") { deps = [ ":post_oobe_delegate", + "//ui/webui/resources/cr_components/chromeos/multidevice_setup:multidevice_setup", ] }
diff --git a/chrome/browser/resources/chromeos/multidevice_setup/multidevice_setup_post_oobe.js b/chrome/browser/resources/chromeos/multidevice_setup/multidevice_setup_post_oobe.js index 3af2027..09b2a93 100644 --- a/chrome/browser/resources/chromeos/multidevice_setup/multidevice_setup_post_oobe.js +++ b/chrome/browser/resources/chromeos/multidevice_setup/multidevice_setup_post_oobe.js
@@ -43,6 +43,7 @@ /** @override */ attached: function() { this.delegate_ = new multidevice_setup.PostOobeDelegate(); + this.$$('multidevice-setup').initializeSetupFlow(); }, /** @private */
diff --git a/chrome/browser/safe_browsing/safe_browsing_blocking_page_unittest.cc b/chrome/browser/safe_browsing/safe_browsing_blocking_page_unittest.cc index 38aaab28..3653524 100644 --- a/chrome/browser/safe_browsing/safe_browsing_blocking_page_unittest.cc +++ b/chrome/browser/safe_browsing/safe_browsing_blocking_page_unittest.cc
@@ -4,6 +4,7 @@ #include <list> +#include "base/bind.h" #include "base/run_loop.h" #include "base/task/post_task.h" #include "chrome/browser/profiles/profile.h" @@ -271,7 +272,8 @@ #if BUILDFLAG(ENABLE_EXTENSIONS) test_event_router_ = extensions::CreateAndUseTestEventRouter(profile); extensions::SafeBrowsingPrivateEventRouterFactory::GetInstance() - ->SetTestingFactory(profile, BuildSafeBrowsingPrivateEventRouter); + ->SetTestingFactory( + profile, base::BindRepeating(&BuildSafeBrowsingPrivateEventRouter)); observer_ = std::make_unique<TestExtensionEventObserver>(test_event_router_); #endif
diff --git a/chrome/browser/safe_browsing/settings_reset_prompt/settings_reset_prompt_model_unittest.cc b/chrome/browser/safe_browsing/settings_reset_prompt/settings_reset_prompt_model_unittest.cc index 13d612b..e9e5d19d 100644 --- a/chrome/browser/safe_browsing/settings_reset_prompt/settings_reset_prompt_model_unittest.cc +++ b/chrome/browser/safe_browsing/settings_reset_prompt/settings_reset_prompt_model_unittest.cc
@@ -9,6 +9,7 @@ #include <unordered_set> #include <utility> +#include "base/bind.h" #include "base/callback.h" #include "base/strings/utf_string_conversions.h" #include "base/values.h" @@ -93,7 +94,7 @@ profile_->CreateWebDataService(); TemplateURLServiceFactory::GetInstance()->SetTestingFactory( - profile(), CreateTemplateURLServiceForTesting); + profile(), base::BindRepeating(&CreateTemplateURLServiceForTesting)); SessionStartupPref::SetStartupPref(profile(), startup_pref_);
diff --git a/chrome/browser/search/instant_unittest_base.cc b/chrome/browser/search/instant_unittest_base.cc index 23f2988..9c2df763 100644 --- a/chrome/browser/search/instant_unittest_base.cc +++ b/chrome/browser/search/instant_unittest_base.cc
@@ -6,6 +6,7 @@ #include <string> +#include "base/bind.h" #include "base/strings/utf_string_conversions.h" #include "build/build_config.h" #include "chrome/browser/chrome_notification_types.h" @@ -76,6 +77,7 @@ TestingProfile* InstantUnitTestBase::CreateProfile() { TestingProfile* profile = BrowserWithTestWindowTest::CreateProfile(); TemplateURLServiceFactory::GetInstance()->SetTestingFactoryAndUse( - profile, &TemplateURLServiceFactory::BuildInstanceFor); + profile, + base::BindRepeating(&TemplateURLServiceFactory::BuildInstanceFor)); return profile; }
diff --git a/chrome/browser/search/search_unittest.cc b/chrome/browser/search/search_unittest.cc index 096469a..3fb4b3ca 100644 --- a/chrome/browser/search/search_unittest.cc +++ b/chrome/browser/search/search_unittest.cc
@@ -10,6 +10,7 @@ #include <string> #include <utility> +#include "base/bind.h" #include "base/macros.h" #include "base/strings/utf_string_conversions.h" #include "build/build_config.h" @@ -63,7 +64,8 @@ void SetUp() override { BrowserWithTestWindowTest::SetUp(); TemplateURLServiceFactory::GetInstance()->SetTestingFactoryAndUse( - profile(), &TemplateURLServiceFactory::BuildInstanceFor); + profile(), + base::BindRepeating(&TemplateURLServiceFactory::BuildInstanceFor)); TemplateURLService* template_url_service = TemplateURLServiceFactory::GetForProfile(profile()); search_test_utils::WaitForTemplateURLServiceToLoad(template_url_service);
diff --git a/chrome/browser/search_engines/template_url_service_factory_test_util.cc b/chrome/browser/search_engines/template_url_service_factory_test_util.cc index 5fd6f67..c3a5444 100644 --- a/chrome/browser/search_engines/template_url_service_factory_test_util.cc +++ b/chrome/browser/search_engines/template_url_service_factory_test_util.cc
@@ -4,6 +4,7 @@ #include "chrome/browser/search_engines/template_url_service_factory_test_util.h" +#include "base/bind.h" #include "base/run_loop.h" #include "chrome/browser/search_engines/template_url_service_factory.h" #include "chrome/test/base/testing_profile.h" @@ -17,7 +18,8 @@ profile_->CreateWebDataService(); TemplateURLServiceFactory::GetInstance()->SetTestingFactoryAndUse( - profile_, TemplateURLServiceFactory::BuildInstanceFor); + profile_, + base::BindRepeating(&TemplateURLServiceFactory::BuildInstanceFor)); } TemplateURLServiceFactoryTestUtil::~TemplateURLServiceFactoryTestUtil() {
diff --git a/chrome/browser/signin/signin_tracker_unittest.cc b/chrome/browser/signin/signin_tracker_unittest.cc index cb43b0b..0563336 100644 --- a/chrome/browser/signin/signin_tracker_unittest.cc +++ b/chrome/browser/signin/signin_tracker_unittest.cc
@@ -55,10 +55,11 @@ SigninTrackerTest() {} void SetUp() override { TestingProfile::Builder builder; - builder.AddTestingFactory(ProfileOAuth2TokenServiceFactory::GetInstance(), - BuildFakeProfileOAuth2TokenService); + builder.AddTestingFactory( + ProfileOAuth2TokenServiceFactory::GetInstance(), + base::BindRepeating(&BuildFakeProfileOAuth2TokenService)); builder.AddTestingFactory(SigninManagerFactory::GetInstance(), - BuildFakeSigninManagerBase); + base::BindRepeating(&BuildFakeSigninManagerBase)); profile_ = builder.Build(); fake_oauth2_token_service_ =
diff --git a/chrome/browser/supervised_user/child_accounts/child_account_service_unittest.cc b/chrome/browser/supervised_user/child_accounts/child_account_service_unittest.cc index 6f166ce..0754d09 100644 --- a/chrome/browser/supervised_user/child_accounts/child_account_service_unittest.cc +++ b/chrome/browser/supervised_user/child_accounts/child_account_service_unittest.cc
@@ -4,6 +4,7 @@ #include "chrome/browser/supervised_user/child_accounts/child_account_service.h" +#include "base/bind.h" #include "chrome/browser/signin/chrome_signin_client_factory.h" #include "chrome/browser/signin/fake_gaia_cookie_manager_service_builder.h" #include "chrome/browser/signin/gaia_cookie_manager_service_factory.h" @@ -29,9 +30,9 @@ void SetUp() override { ChromeSigninClientFactory::GetInstance()->SetTestingFactory( - &profile_, &BuildTestSigninClient); + &profile_, base::BindRepeating(&BuildTestSigninClient)); GaiaCookieManagerServiceFactory::GetInstance()->SetTestingFactory( - &profile_, &BuildFakeGaiaCookieManagerService); + &profile_, base::BindRepeating(&BuildFakeGaiaCookieManagerService)); gaia_cookie_manager_service_ = static_cast<FakeGaiaCookieManagerService*>( GaiaCookieManagerServiceFactory::GetForProfile(&profile_)); }
diff --git a/chrome/browser/supervised_user/supervised_user_service_unittest.cc b/chrome/browser/supervised_user/supervised_user_service_unittest.cc index fb2bd32a..4c83e6d 100644 --- a/chrome/browser/supervised_user/supervised_user_service_unittest.cc +++ b/chrome/browser/supervised_user/supervised_user_service_unittest.cc
@@ -9,6 +9,7 @@ #include <memory> #include <utility> +#include "base/bind.h" #include "base/macros.h" #include "base/memory/ptr_util.h" #include "base/path_service.h" @@ -187,8 +188,9 @@ void SetUp() override { TestingProfile::Builder builder; - builder.AddTestingFactory(ProfileOAuth2TokenServiceFactory::GetInstance(), - BuildFakeProfileOAuth2TokenService); + builder.AddTestingFactory( + ProfileOAuth2TokenServiceFactory::GetInstance(), + base::BindRepeating(&BuildFakeProfileOAuth2TokenService)); profile_ = builder.Build(); supervised_user_service_ = SupervisedUserServiceFactory::GetForProfile(profile_.get());
diff --git a/chrome/browser/sync/sync_error_notifier_ash_unittest.cc b/chrome/browser/sync/sync_error_notifier_ash_unittest.cc index c9ad5eb..0fc2816 100644 --- a/chrome/browser/sync/sync_error_notifier_ash_unittest.cc +++ b/chrome/browser/sync/sync_error_notifier_ash_unittest.cc
@@ -8,6 +8,7 @@ #include <memory> +#include "base/bind.h" #include "chrome/browser/browser_process.h" #include "chrome/browser/chromeos/login/users/mock_user_manager.h" #include "chrome/browser/notifications/notification_display_service_tester.h" @@ -73,7 +74,7 @@ FakeLoginUIService* login_ui_service = static_cast<FakeLoginUIService*>( LoginUIServiceFactory::GetInstance()->SetTestingFactoryAndUse( - profile(), BuildMockLoginUIService)); + profile(), base::BindRepeating(&BuildMockLoginUIService))); login_ui_service->SetLoginUI(&login_ui_); error_notifier_ =
diff --git a/chrome/browser/sync/sync_startup_tracker_unittest.cc b/chrome/browser/sync/sync_startup_tracker_unittest.cc index d174ce4d..8166839 100644 --- a/chrome/browser/sync/sync_startup_tracker_unittest.cc +++ b/chrome/browser/sync/sync_startup_tracker_unittest.cc
@@ -6,6 +6,7 @@ #include <memory> +#include "base/bind.h" #include "chrome/browser/sync/profile_sync_service_factory.h" #include "chrome/browser/sync/profile_sync_test_util.h" #include "chrome/test/base/testing_profile.h" @@ -36,7 +37,7 @@ profile_ = std::make_unique<TestingProfile>(); mock_pss_ = static_cast<browser_sync::ProfileSyncServiceMock*>( ProfileSyncServiceFactory::GetInstance()->SetTestingFactoryAndUse( - profile_.get(), BuildMockProfileSyncService)); + profile_.get(), base::BindRepeating(&BuildMockProfileSyncService))); ON_CALL(*mock_pss_, GetAuthError()).WillByDefault(ReturnRef(no_error_)); ON_CALL(*mock_pss_, GetRegisteredDataTypes())
diff --git a/chrome/browser/sync/test/integration/autofill_helper.cc b/chrome/browser/sync/test/integration/autofill_helper.cc index b793ff2..a05de14e 100644 --- a/chrome/browser/sync/test/integration/autofill_helper.cc +++ b/chrome/browser/sync/test/integration/autofill_helper.cc
@@ -22,6 +22,7 @@ #include "components/autofill/core/browser/autofill_profile.h" #include "components/autofill/core/browser/autofill_test_utils.h" #include "components/autofill/core/browser/autofill_type.h" +#include "components/autofill/core/browser/payments/payments_customer_data.h" #include "components/autofill/core/browser/personal_data_manager.h" #include "components/autofill/core/browser/webdata/autofill_entry.h" #include "components/autofill/core/browser/webdata/autofill_table.h" @@ -126,6 +127,14 @@ ->SetServerProfiles(profiles); } +void SetPaymentsCustomerDataOnDBSequence( + AutofillWebDataService* wds, + const autofill::PaymentsCustomerData& customer_data) { + DCHECK(wds->GetDBTaskRunner()->RunsTasksInCurrentSequence()); + AutofillTable::FromWebDatabase(wds->GetDatabase()) + ->SetPaymentsCustomerData(&customer_data); +} + bool ProfilesMatchImpl( int profile_a, const std::vector<AutofillProfile*>& autofill_profiles_a, @@ -319,6 +328,16 @@ WaitForCurrentTasksToComplete(wds->GetDBTaskRunner()); } +void SetPaymentsCustomerData( + int profile, + const autofill::PaymentsCustomerData& customer_data) { + scoped_refptr<AutofillWebDataService> wds = GetProfileWebDataService(profile); + wds->GetDBTaskRunner()->PostTask( + FROM_HERE, base::BindOnce(&SetPaymentsCustomerDataOnDBSequence, + base::Unretained(wds.get()), customer_data)); + WaitForCurrentTasksToComplete(wds->GetDBTaskRunner()); +} + void AddProfile(int profile, const AutofillProfile& autofill_profile) { std::vector<AutofillProfile> autofill_profiles; for (AutofillProfile* profile : GetAllAutoFillProfiles(profile)) {
diff --git a/chrome/browser/sync/test/integration/autofill_helper.h b/chrome/browser/sync/test/integration/autofill_helper.h index ef1d76296..5d76d30 100644 --- a/chrome/browser/sync/test/integration/autofill_helper.h +++ b/chrome/browser/sync/test/integration/autofill_helper.h
@@ -22,6 +22,7 @@ class AutofillType; class AutofillWebDataService; class CreditCard; +struct PaymentsCustomerData; class PersonalDataManager; } // namespace autofill @@ -82,6 +83,10 @@ void SetServerProfiles(int profile, const std::vector<autofill::AutofillProfile>& profiles); +void SetPaymentsCustomerData( + int profile, + const autofill::PaymentsCustomerData& customer_data); + // Adds the autofill profile |autofill_profile| to sync profile |profile|. void AddProfile(int profile, const autofill::AutofillProfile& autofill_profile);
diff --git a/chrome/browser/sync/test/integration/secondary_account_helper.cc b/chrome/browser/sync/test/integration/secondary_account_helper.cc index 25390c0e..2792a3d 100644 --- a/chrome/browser/sync/test/integration/secondary_account_helper.cc +++ b/chrome/browser/sync/test/integration/secondary_account_helper.cc
@@ -31,7 +31,7 @@ void OnWillCreateBrowserContextServices(content::BrowserContext* context) { GaiaCookieManagerServiceFactory::GetInstance()->SetTestingFactory( - context, &BuildFakeGaiaCookieManagerService); + context, base::BindRepeating(&BuildFakeGaiaCookieManagerService)); } } // namespace
diff --git a/chrome/browser/sync/test/integration/single_client_wallet_sync_test.cc b/chrome/browser/sync/test/integration/single_client_wallet_sync_test.cc index cbe9721..5cbe24b1 100644 --- a/chrome/browser/sync/test/integration/single_client_wallet_sync_test.cc +++ b/chrome/browser/sync/test/integration/single_client_wallet_sync_test.cc
@@ -17,6 +17,7 @@ #include "components/autofill/core/browser/autofill_data_util.h" #include "components/autofill/core/browser/credit_card.h" #include "components/autofill/core/browser/field_types.h" +#include "components/autofill/core/browser/payments/payments_customer_data.h" #include "components/autofill/core/browser/personal_data_manager.h" #include "components/autofill/core/browser/personal_data_manager_observer.h" #include "components/autofill/core/common/autofill_features.h" @@ -44,7 +45,7 @@ loop->Quit(); } -// Constands for the credit card. +// Constants for the credit card. const char kDefaultCardID[] = "wallet card ID"; const int kDefaultCardExpMonth = 8; const int kDefaultCardExpYear = 2087; @@ -68,6 +69,9 @@ const char kDefaultDependentLocality[] = "DepLoc"; const char kDefaultLanguageCode[] = "en"; +// Constants for PaymentsCustomerData. +const char kDefaultCustomerID[] = "deadbeef"; + const char kLocalGuidA[] = "EDC609ED-7EEE-4F27-B00C-423242A9C44A"; const char kDifferentBillingAddressId[] = "another address entity ID"; @@ -177,6 +181,18 @@ return std::move(consumer.result()); } +#if !defined(OS_CHROMEOS) +std::unique_ptr<autofill::PaymentsCustomerData> GetPaymentsCustomerData( + scoped_refptr<autofill::AutofillWebDataService> service) { + AutofillWebDataServiceConsumer< + std::unique_ptr<autofill::PaymentsCustomerData>> + consumer; + service->GetPaymentsCustomerData(&consumer); + consumer.Wait(); + return std::move(consumer.result()); +} +#endif + sync_pb::SyncEntity CreateDefaultSyncWalletCard() { sync_pb::SyncEntity entity; entity.set_name(kDefaultCardID); @@ -215,6 +231,28 @@ return result; } +sync_pb::SyncEntity CreateSyncPaymentsCustomerData( + const std::string& customer_id) { + sync_pb::SyncEntity entity; + entity.set_name(customer_id); + entity.set_id_string(customer_id); + entity.set_version(0); // Will be overridden by the fake server. + entity.set_ctime(12345); + entity.set_mtime(12345); + sync_pb::AutofillWalletSpecifics* wallet_specifics = + entity.mutable_specifics()->mutable_autofill_wallet(); + wallet_specifics->set_type(sync_pb::AutofillWalletSpecifics::CUSTOMER_DATA); + + sync_pb::PaymentsCustomerData* customer_data = + wallet_specifics->mutable_customer_data(); + customer_data->set_id(customer_id); + return entity; +} + +sync_pb::SyncEntity CreateDefaultSyncPaymentsCustomerData() { + return CreateSyncPaymentsCustomerData(kDefaultCustomerID); +} + CreditCard GetDefaultCreditCard() { CreditCard card(CreditCard::MASKED_SERVER_CARD, kDefaultCardID); card.SetExpirationMonth(kDefaultCardExpMonth); @@ -371,6 +409,13 @@ pdm->RemoveObserver(&personal_data_observer_); } + void WaitForNumberOfCards(autofill::PersonalDataManager* pdm, + size_t expected_count) { + while (pdm->GetCreditCards().size() != expected_count) { + WaitForOnPersonalDataChanged(/*should_trigger_refresh=*/false, pdm); + } + } + PersonalDataLoadedObserverMock personal_data_observer_; private: @@ -489,20 +534,65 @@ // Wallet data should get cleared from the database when sync is disabled. IN_PROC_BROWSER_TEST_P(SingleClientWalletSyncTest, ClearOnDisableSync) { InitWithDefaultFeatures(); - GetFakeServer()->SetWalletData( - {CreateDefaultSyncWalletAddress(), CreateDefaultSyncWalletCard()}); + GetFakeServer()->SetWalletData({CreateDefaultSyncWalletAddress(), + CreateDefaultSyncWalletCard(), + CreateDefaultSyncPaymentsCustomerData()}); ASSERT_TRUE(SetupSync()); - // Make sure the card is in the DB. + // Make sure the data is in the DB. autofill::PersonalDataManager* pdm = GetPersonalDataManager(0); ASSERT_NE(nullptr, pdm); - std::vector<CreditCard*> cards = pdm->GetCreditCards(); - ASSERT_EQ(1uL, cards.size()); + EXPECT_EQ(1uL, pdm->GetCreditCards().size()); + EXPECT_EQ(kDefaultCustomerID, pdm->GetPaymentsCustomerData()->customer_id); + + // Turn off sync, the data should be gone. + GetSyncService(0)->RequestStop(syncer::SyncService::CLEAR_DATA); + WaitForNumberOfCards(pdm, 0); + + EXPECT_EQ(0uL, pdm->GetCreditCards().size()); + EXPECT_EQ(nullptr, pdm->GetPaymentsCustomerData()); + + // Turn sync on again, the data should come back. + GetSyncService(0)->RequestStart(); + // RequestStop(CLEAR_DATA) also clears the "first setup complete" flag, so + // set it again. + GetSyncService(0)->SetFirstSetupComplete(); + // Wait until Sync restores the card and it arrives at PDM. + WaitForNumberOfCards(pdm, 1); + + EXPECT_EQ(1uL, pdm->GetCreditCards().size()); + EXPECT_EQ(kDefaultCustomerID, pdm->GetPaymentsCustomerData()->customer_id); +} + +// Wallet data should get cleared from the database when sync is (temporarily) +// stopped, e.g. due to the Sync feature toggle in Android settings. +IN_PROC_BROWSER_TEST_P(SingleClientWalletSyncTest, ClearOnStopSync) { + InitWithDefaultFeatures(); + GetFakeServer()->SetWalletData({CreateDefaultSyncWalletAddress(), + CreateDefaultSyncWalletCard(), + CreateDefaultSyncPaymentsCustomerData()}); + ASSERT_TRUE(SetupSync()); + + // Make sure the data is in the DB. + autofill::PersonalDataManager* pdm = GetPersonalDataManager(0); + ASSERT_NE(nullptr, pdm); + EXPECT_EQ(1uL, pdm->GetCreditCards().size()); + EXPECT_EQ(kDefaultCustomerID, pdm->GetPaymentsCustomerData()->customer_id); // Turn off sync, the card should be gone. - ASSERT_TRUE(GetClient(0)->DisableSyncForAllDatatypes()); - cards = pdm->GetCreditCards(); - ASSERT_EQ(0uL, cards.size()); + GetSyncService(0)->RequestStop(syncer::SyncService::KEEP_DATA); + WaitForNumberOfCards(pdm, 0); + + EXPECT_EQ(0uL, pdm->GetCreditCards().size()); + EXPECT_EQ(nullptr, pdm->GetPaymentsCustomerData()); + + // Turn sync on again, the data should come back. + GetSyncService(0)->RequestStart(); + // Wait until Sync restores the card and it arrives at PDM. + WaitForNumberOfCards(pdm, 1); + + EXPECT_EQ(1uL, pdm->GetCreditCards().size()); + EXPECT_EQ(kDefaultCustomerID, pdm->GetPaymentsCustomerData()->customer_id); } // ChromeOS does not sign out, so the test below does not apply. @@ -510,19 +600,23 @@ // Wallet data should get cleared from the database when the user signs out. IN_PROC_BROWSER_TEST_P(SingleClientWalletSyncTest, ClearOnSignOut) { InitWithDefaultFeatures(); - GetFakeServer()->SetWalletData( - {CreateDefaultSyncWalletAddress(), CreateDefaultSyncWalletCard()}); + GetFakeServer()->SetWalletData({CreateDefaultSyncWalletAddress(), + CreateDefaultSyncWalletCard(), + CreateDefaultSyncPaymentsCustomerData()}); ASSERT_TRUE(SetupSync()); - // Make sure the card is in the DB. + // Make sure the data is in the DB. autofill::PersonalDataManager* pdm = GetPersonalDataManager(0); ASSERT_NE(nullptr, pdm); - ASSERT_EQ(1uL, pdm->GetCreditCards().size()); + EXPECT_EQ(1uL, pdm->GetCreditCards().size()); + EXPECT_EQ(kDefaultCustomerID, pdm->GetPaymentsCustomerData()->customer_id); - // Turn off sync, the card should be gone. + // Turn off sync, the data should be gone. GetClient(0)->SignOutPrimaryAccount(); + WaitForNumberOfCards(pdm, 0); - ASSERT_EQ(0uL, pdm->GetCreditCards().size()); + EXPECT_EQ(0uL, pdm->GetCreditCards().size()); + EXPECT_EQ(nullptr, pdm->GetPaymentsCustomerData()); } #endif // !defined(OS_CHROMEOS) @@ -531,15 +625,14 @@ IN_PROC_BROWSER_TEST_P(SingleClientWalletSyncTest, NewSyncDataShouldReplaceExistingData) { InitWithDefaultFeatures(); - sync_pb::SyncEntity first_card = - CreateSyncWalletCard(/*name=*/"card-1", /*last_four=*/"0001"); - sync_pb::SyncEntity first_address = - CreateSyncWalletAddress(/*name=*/"address-1", /*company=*/"Company-1"); - GetFakeServer()->SetWalletData({first_card, first_address}); + GetFakeServer()->SetWalletData( + {CreateSyncWalletCard(/*name=*/"card-1", /*last_four=*/"0001"), + CreateSyncWalletAddress(/*name=*/"address-1", /*company=*/"Company-1"), + CreateDefaultSyncPaymentsCustomerData()}); ASSERT_TRUE(SetupSync()); - // Make sure the card is in the DB. + // Make sure the data is in the DB. autofill::PersonalDataManager* pdm = GetPersonalDataManager(0); ASSERT_NE(nullptr, pdm); std::vector<CreditCard*> cards = pdm->GetCreditCards(); @@ -549,13 +642,13 @@ ASSERT_EQ(1uL, profiles.size()); EXPECT_EQ("Company-1", TruncateUTF8(base::UTF16ToUTF8( profiles[0]->GetRawInfo(autofill::COMPANY_NAME)))); + EXPECT_EQ(kDefaultCustomerID, pdm->GetPaymentsCustomerData()->customer_id); - sync_pb::SyncEntity new_card = - CreateSyncWalletCard(/*name=*/"new-card", /*last_four=*/"0002"); - sync_pb::SyncEntity new_address = - CreateSyncWalletAddress(/*name=*/"new-address", /*company=*/"Company-2"); - - GetFakeServer()->SetWalletData({new_card, new_address}); + // Put some completely new data in the sync server. + GetFakeServer()->SetWalletData( + {CreateSyncWalletCard(/*name=*/"new-card", /*last_four=*/"0002"), + CreateSyncWalletAddress(/*name=*/"new-address", /*company=*/"Company-2"), + CreateSyncPaymentsCustomerData(/*customer_id=*/"newid")}); // Constructing the checker captures the current progress marker. Make sure to // do that before triggering the fetch. @@ -573,6 +666,7 @@ ASSERT_EQ(1uL, profiles.size()); EXPECT_EQ("Company-2", TruncateUTF8(base::UTF16ToUTF8( profiles[0]->GetRawInfo(autofill::COMPANY_NAME)))); + EXPECT_EQ("newid", pdm->GetPaymentsCustomerData()->customer_id); } // Wallet is not using incremental updates. The server either sends a non-empty @@ -580,12 +674,10 @@ // set, or (more often) an empty update. IN_PROC_BROWSER_TEST_P(SingleClientWalletSyncTest, EmptyUpdatesAreIgnored) { InitWithDefaultFeatures(); - sync_pb::SyncEntity first_card = - CreateSyncWalletCard(/*name=*/"card-1", /*last_four=*/"0001"); - sync_pb::SyncEntity first_address = - CreateSyncWalletAddress(/*name=*/"address-1", /*company=*/"Company-1"); - - GetFakeServer()->SetWalletData({first_card, first_address}); + GetFakeServer()->SetWalletData( + {CreateSyncWalletCard(/*name=*/"card-1", /*last_four=*/"0001"), + CreateSyncWalletAddress(/*name=*/"address-1", /*company=*/"Company-1"), + CreateDefaultSyncPaymentsCustomerData()}); ASSERT_TRUE(SetupSync()); // Make sure the card is in the DB. @@ -598,6 +690,7 @@ ASSERT_EQ(1uL, profiles.size()); EXPECT_EQ("Company-1", TruncateUTF8(base::UTF16ToUTF8( profiles[0]->GetRawInfo(autofill::COMPANY_NAME)))); + EXPECT_EQ(kDefaultCustomerID, pdm->GetPaymentsCustomerData()->customer_id); // Do not change anything on the server so that the update forced below is an // empty one. @@ -610,6 +703,9 @@ syncer::ModelTypeSet(syncer::AUTOFILL_WALLET_DATA)); ASSERT_TRUE(checker.Wait()); + // Refresh the pdm so that it gets cards from autofill table. + RefreshAndWaitForOnPersonalDataChanged(pdm); + // Make sure the same data is present on the client. cards = pdm->GetCreditCards(); ASSERT_EQ(1uL, cards.size()); @@ -618,26 +714,30 @@ ASSERT_EQ(1uL, profiles.size()); EXPECT_EQ("Company-1", TruncateUTF8(base::UTF16ToUTF8( profiles[0]->GetRawInfo(autofill::COMPANY_NAME)))); + EXPECT_EQ(kDefaultCustomerID, pdm->GetPaymentsCustomerData()->customer_id); } // Wallet data should get cleared from the database when the wallet sync type // flag is disabled. IN_PROC_BROWSER_TEST_P(SingleClientWalletSyncTest, ClearOnDisableWalletSync) { InitWithDefaultFeatures(); - GetFakeServer()->SetWalletData( - {CreateDefaultSyncWalletAddress(), CreateDefaultSyncWalletCard()}); + GetFakeServer()->SetWalletData({CreateDefaultSyncWalletAddress(), + CreateDefaultSyncWalletCard(), + CreateDefaultSyncPaymentsCustomerData()}); ASSERT_TRUE(SetupSync()); - // Make sure the card is in the DB. + // Make sure the data is in the DB. autofill::PersonalDataManager* pdm = GetPersonalDataManager(0); ASSERT_NE(nullptr, pdm); - std::vector<CreditCard*> cards = pdm->GetCreditCards(); - ASSERT_EQ(1uL, cards.size()); + EXPECT_EQ(1uL, pdm->GetCreditCards().size()); + EXPECT_EQ(kDefaultCustomerID, pdm->GetPaymentsCustomerData()->customer_id); - // Turn off autofill sync, the card should be gone. + // Turn off autofill sync, the data should be gone. ASSERT_TRUE(GetClient(0)->DisableSyncForDatatype(syncer::AUTOFILL)); - cards = pdm->GetCreditCards(); - ASSERT_EQ(0uL, cards.size()); + WaitForOnPersonalDataChanged(/*should_trigger_refresh=*/false, pdm); + + EXPECT_EQ(0uL, pdm->GetCreditCards().size()); + EXPECT_EQ(nullptr, pdm->GetPaymentsCustomerData()); } // Wallet data should get cleared from the database when the wallet autofill @@ -645,22 +745,21 @@ IN_PROC_BROWSER_TEST_P(SingleClientWalletSyncTest, ClearOnDisableWalletAutofill) { InitWithDefaultFeatures(); - GetFakeServer()->SetWalletData( - {CreateDefaultSyncWalletAddress(), CreateDefaultSyncWalletCard()}); + GetFakeServer()->SetWalletData({CreateDefaultSyncWalletAddress(), + CreateDefaultSyncWalletCard(), + CreateDefaultSyncPaymentsCustomerData()}); ASSERT_TRUE(SetupSync()); - // Make sure the card is in the DB. + // Make sure the card and PaymentsCustomerData are in the DB. autofill::PersonalDataManager* pdm = GetPersonalDataManager(0); ASSERT_NE(nullptr, pdm); - std::vector<CreditCard*> cards = pdm->GetCreditCards(); - ASSERT_EQ(1uL, cards.size()); + EXPECT_EQ(1uL, pdm->GetCreditCards().size()); // Turn off the wallet autofill pref, the card should be gone as a side // effect of the wallet data type controller noticing. autofill::prefs::SetPaymentsIntegrationEnabled(GetProfile(0)->GetPrefs(), false); - cards = pdm->GetCreditCards(); - ASSERT_EQ(0uL, cards.size()); + EXPECT_EQ(0uL, pdm->GetCreditCards().size()); } // Wallet data present on the client should be cleared in favor of the new data @@ -683,7 +782,11 @@ std::vector<AutofillProfile> client_profiles = {profile}; autofill_helper::SetServerProfiles(0, client_profiles); - // Refresh the pdm so that it gets cards from autofill table. + // Add PaymentsCustomerData on the client. + autofill_helper::SetPaymentsCustomerData( + 0, autofill::PaymentsCustomerData(/*customer_id=*/kDefaultCustomerID)); + + // Refresh the pdm so that it gets data from autofill table. RefreshAndWaitForOnPersonalDataChanged(pdm); // Make sure the card was added correctly. @@ -697,24 +800,31 @@ EXPECT_EQ("JustATest", TruncateUTF8(base::UTF16ToUTF8( profiles[0]->GetRawInfo(autofill::COMPANY_NAME)))); + // Make sure the customer data was added correctly. + EXPECT_EQ(kDefaultCustomerID, pdm->GetPaymentsCustomerData()->customer_id); + // Add a new card from the server and sync it down. - GetFakeServer()->SetWalletData({CreateDefaultSyncWalletCard()}); + GetFakeServer()->SetWalletData( + {CreateDefaultSyncWalletCard(), CreateDefaultSyncPaymentsCustomerData()}); ASSERT_TRUE(SetupSync()); // The only card present on the client should be the one from the server. cards = pdm->GetCreditCards(); - ASSERT_EQ(1uL, cards.size()); + EXPECT_EQ(1uL, cards.size()); EXPECT_EQ(kDefaultCardID, cards[0]->server_id()); // There should be no profile present. profiles = pdm->GetServerProfiles(); - ASSERT_EQ(0uL, profiles.size()); + EXPECT_EQ(0uL, profiles.size()); + + // The PaymentsCustomerData should still be there. + EXPECT_EQ(kDefaultCustomerID, pdm->GetPaymentsCustomerData()->customer_id); } // Wallet data present on the client should be cleared in favor of the new data // synced down form the server. IN_PROC_BROWSER_TEST_P(SingleClientWalletSyncTest, - NewWalletProfileRemovesExistingProfileAndCard) { + NewWalletDataRemovesExistingData) { InitWithDefaultFeatures(); ASSERT_TRUE(SetupClients()); autofill::PersonalDataManager* pdm = GetPersonalDataManager(0); @@ -731,34 +841,46 @@ std::vector<CreditCard> credit_cards = {credit_card}; autofill_helper::SetServerCreditCards(0, credit_cards); + // Add PaymentsCustomerData on the client. + autofill_helper::SetPaymentsCustomerData( + 0, autofill::PaymentsCustomerData(/*customer_id=*/kDefaultCustomerID)); + // Refresh the pdm so that it gets cards from autofill table. RefreshAndWaitForOnPersonalDataChanged(pdm); // Make sure the profile was added correctly. std::vector<AutofillProfile*> profiles = pdm->GetServerProfiles(); - ASSERT_EQ(1uL, profiles.size()); + EXPECT_EQ(1uL, profiles.size()); EXPECT_EQ("JustATest", TruncateUTF8(base::UTF16ToUTF8( profiles[0]->GetRawInfo(autofill::COMPANY_NAME)))); // Make sure the card was added correctly. std::vector<CreditCard*> cards = pdm->GetCreditCards(); - ASSERT_EQ(1uL, cards.size()); + EXPECT_EQ(1uL, cards.size()); EXPECT_EQ("a123", cards[0]->server_id()); - // Add a new profile from the server and sync it down. - GetFakeServer()->SetWalletData({CreateDefaultSyncWalletAddress()}); + // Make sure the customer data was added correctly. + EXPECT_EQ(kDefaultCustomerID, pdm->GetPaymentsCustomerData()->customer_id); + + // Add a new profile and new customer data from the server and sync them down. + GetFakeServer()->SetWalletData( + {CreateDefaultSyncWalletAddress(), + CreateSyncPaymentsCustomerData(/*customer_id=*/"newid")}); ASSERT_TRUE(SetupSync()); // The only profile present on the client should be the one from the server. profiles = pdm->GetServerProfiles(); - ASSERT_EQ(1uL, profiles.size()); + EXPECT_EQ(1uL, profiles.size()); EXPECT_EQ(kDefaultCompanyName, TruncateUTF8(base::UTF16ToUTF8( profiles[0]->GetRawInfo(autofill::COMPANY_NAME)))); - // There should be not card present. + // There should be no cards present. cards = pdm->GetCreditCards(); - ASSERT_EQ(0uL, cards.size()); + EXPECT_EQ(0uL, cards.size()); + + // Payments customer data should be updated. + EXPECT_EQ("newid", pdm->GetPaymentsCustomerData()->customer_id); } // Tests that a local billing address id set on a card on the client should not @@ -870,10 +992,74 @@ }; // ChromeOS doesn't support changes to the primary account after startup, so -// this test doesn't apply. +// these secondary-account-related tests don't apply. #if !defined(OS_CHROMEOS) IN_PROC_BROWSER_TEST_F(SingleClientWalletSecondaryAccountSyncTest, - SwitchesFromAccountToProfileStorage) { + SwitchesFromAccountToProfileStorageOnSyncOptIn) { + ASSERT_TRUE(SetupClients()) << "SetupClients() failed."; + GetPersonalDataManager(0)->OnSyncServiceInitialized(GetSyncService(0)); + + GetFakeServer()->SetWalletData( + {CreateDefaultSyncWalletCard(), CreateDefaultSyncPaymentsCustomerData()}); + + // Set up Sync in transport mode for a non-primary account. + secondary_account_helper::SignInSecondaryAccount(profile(), "user@email.com"); + ASSERT_TRUE(GetClient(0)->AwaitSyncSetupCompletion( + /*skip_passphrase_verification=*/false)); + ASSERT_EQ(syncer::SyncService::TransportState::ACTIVE, + GetSyncService(0)->GetTransportState()); + ASSERT_FALSE(GetSyncService(0)->IsSyncFeatureEnabled()); + ASSERT_FALSE(GetSyncService(0)->IsSyncFeatureActive()); + ASSERT_TRUE(GetSyncService(0)->GetActiveDataTypes().Has( + syncer::AUTOFILL_WALLET_DATA)); + + // PersonalDataManager should use (ephemeral) account storage. + EXPECT_FALSE(GetPersonalDataManager(0)->IsSyncFeatureEnabled()); + EXPECT_TRUE( + GetPersonalDataManager(0)->IsUsingAccountStorageForServerCardsForTest()); + + auto account_data = GetAccountWebDataService(0); + ASSERT_NE(nullptr, account_data); + auto profile_data = GetProfileWebDataService(0); + ASSERT_NE(nullptr, profile_data); + + // Check that the data is stored in the account storage (ephemeral), but not + // in the profile storage (persisted). + EXPECT_EQ(1U, GetServerCards(account_data).size()); + EXPECT_EQ(0U, GetServerCards(profile_data).size()); + EXPECT_NE(nullptr, GetPaymentsCustomerData(account_data).get()); + EXPECT_EQ(nullptr, GetPaymentsCustomerData(profile_data).get()); + + // Simulate the user opting in to full Sync: Make the account primary, and + // set first-time setup to complete. + secondary_account_helper::MakeAccountPrimary(profile(), "user@email.com"); + GetSyncService(0)->SetFirstSetupComplete(); + + // Wait for Sync to get reconfigured into feature mode. + ASSERT_TRUE(GetClient(0)->AwaitSyncSetupCompletion( + /*skip_passphrase_verification=*/false)); + ASSERT_EQ(syncer::SyncService::TransportState::ACTIVE, + GetSyncService(0)->GetTransportState()); + ASSERT_TRUE(GetSyncService(0)->IsSyncFeatureEnabled()); + ASSERT_TRUE(GetSyncService(0)->IsSyncFeatureActive()); + ASSERT_TRUE(GetSyncService(0)->GetActiveDataTypes().Has( + syncer::AUTOFILL_WALLET_DATA)); + + // PersonalDataManager should have switched to persistent storage. + EXPECT_TRUE(GetPersonalDataManager(0)->IsSyncFeatureEnabled()); + EXPECT_FALSE( + GetPersonalDataManager(0)->IsUsingAccountStorageForServerCardsForTest()); + + // The data should now be in the profile storage (persisted). + EXPECT_EQ(0U, GetServerCards(account_data).size()); + EXPECT_EQ(1U, GetServerCards(profile_data).size()); + EXPECT_EQ(nullptr, GetPaymentsCustomerData(account_data).get()); + EXPECT_NE(nullptr, GetPaymentsCustomerData(profile_data).get()); +} + +IN_PROC_BROWSER_TEST_F( + SingleClientWalletSecondaryAccountSyncTest, + SwitchesFromAccountToProfileStorageOnSyncOptInWithAdvancedSetup) { ASSERT_TRUE(SetupClients()) << "SetupClients() failed."; GetPersonalDataManager(0)->OnSyncServiceInitialized(GetSyncService(0)); @@ -905,9 +1091,33 @@ EXPECT_EQ(1U, GetServerCards(account_data).size()); EXPECT_EQ(0U, GetServerCards(profile_data).size()); - // Simulate the user opting in to full Sync: Make the account primary, and - // set first-time setup to complete. + // Simulate the user opting in to full Sync: First, make the account primary. secondary_account_helper::MakeAccountPrimary(profile(), "user@email.com"); + + // Now start actually configuring Sync. + auto setup_handle = GetSyncService(0)->GetSetupInProgressHandle(); + + // Adding a primary account triggers a restart of the Sync engine, so it + // should now be initializing again. + ASSERT_EQ(syncer::SyncService::TransportState::INITIALIZING, + GetSyncService(0)->GetTransportState()); + + ASSERT_TRUE(GetClient(0)->AwaitEngineInitialization( + /*skip_passphrase_verification=*/false)); + + // Since we're still holding on to the setup-in-progress handle, the data + // types can't be configured yet. + ASSERT_EQ(syncer::SyncService::TransportState::PENDING_DESIRED_CONFIGURATION, + GetSyncService(0)->GetTransportState()); + + GetSyncService(0)->OnUserChoseDatatypes( + /*sync_everything=*/false, syncer::ModelTypeSet(syncer::AUTOFILL)); + + // Once the user finishes the setup, we can actually configure. + setup_handle.reset(); + ASSERT_EQ(syncer::SyncService::TransportState::CONFIGURING, + GetSyncService(0)->GetTransportState()); + GetSyncService(0)->SetFirstSetupComplete(); // Wait for Sync to get reconfigured into feature mode. @@ -931,6 +1141,150 @@ } #endif // !defined(OS_CHROMEOS) +// This tests that switching between Sync-the-feature and +// Sync-standalone-transport properly migrates server credit cards between the +// profile (i.e. persisted) and account (i.e. ephemeral) storage. +// When turning off Sync-the-feature via SyncService::RequestStop, you can +// specify either KEEP_DATA or CLEAR_DATA. For full coverage, we test all +// transitions, and each time verify that the card is in the correct storage: +// 1. Start out in Sync-the-feature mode -> profile storage. +// 2. RequestStop(KEEP_DATA) -> account storage. +// 3. Enable Sync-the-feature again -> profile storage. +// 4. RequestStop(CLEAR_DATA) -> account storage. +// 5. Enable Sync-the-feature again -> profile storage. +IN_PROC_BROWSER_TEST_F(SingleClientWalletSyncTest, + SwitchesBetweenAccountAndProfileStorageOnTogglingSync) { + base::test::ScopedFeatureList features; + features.InitWithFeatures( + /*enabled_features=*/{switches::kSyncStandaloneTransport, + switches::kSyncUSSAutofillWalletData, + autofill::features:: + kAutofillEnableAccountWalletStorage}, + /*disabled_features=*/{}); + + ASSERT_TRUE(SetupClients()) << "SetupClients() failed."; + GetPersonalDataManager(0)->OnSyncServiceInitialized(GetSyncService(0)); + + GetFakeServer()->SetWalletData({CreateDefaultSyncWalletCard()}); + + // STEP 1. Set up Sync in full feature mode. + ASSERT_TRUE(GetClient(0)->SetupSync()); + ASSERT_EQ(syncer::SyncService::TransportState::ACTIVE, + GetSyncService(0)->GetTransportState()); + ASSERT_TRUE(GetSyncService(0)->IsSyncFeatureEnabled()); + ASSERT_TRUE(GetSyncService(0)->IsSyncFeatureActive()); + ASSERT_TRUE(GetSyncService(0)->GetActiveDataTypes().Has( + syncer::AUTOFILL_WALLET_DATA)); + + // PersonalDataManager should use the regular persisted (non-account) storage. + EXPECT_TRUE(GetPersonalDataManager(0)->IsSyncFeatureEnabled()); + EXPECT_FALSE( + GetPersonalDataManager(0)->IsUsingAccountStorageForServerCardsForTest()); + + auto account_data = GetAccountWebDataService(0); + ASSERT_NE(nullptr, account_data); + auto profile_data = GetProfileWebDataService(0); + ASSERT_NE(nullptr, profile_data); + + // Check that the card is stored in the profile storage (persisted), but not + // in the account storage (ephemeral). + EXPECT_EQ(0U, GetServerCards(account_data).size()); + EXPECT_EQ(1U, GetServerCards(profile_data).size()); + + // STEP 2. Turn off Sync-the-feature temporarily (e.g. the Sync feature toggle + // on Android), i.e. leave the Sync data around. + GetSyncService(0)->RequestStop(syncer::SyncService::KEEP_DATA); + + // Wait for Sync to get reconfigured into transport mode. + ASSERT_TRUE(GetClient(0)->AwaitSyncSetupCompletion( + /*skip_passphrase_verification=*/false)); + ASSERT_EQ(syncer::SyncService::TransportState::ACTIVE, + GetSyncService(0)->GetTransportState()); + ASSERT_FALSE(GetSyncService(0)->IsSyncFeatureEnabled()); + ASSERT_FALSE(GetSyncService(0)->IsSyncFeatureActive()); + ASSERT_TRUE(GetSyncService(0)->GetActiveDataTypes().Has( + syncer::AUTOFILL_WALLET_DATA)); + + // PersonalDataManager should have switched to ephemeral storage. + EXPECT_FALSE(GetPersonalDataManager(0)->IsSyncFeatureEnabled()); + EXPECT_TRUE( + GetPersonalDataManager(0)->IsUsingAccountStorageForServerCardsForTest()); + + // The card should now be in the account storage (ephemeral). Note that even + // though we specified KEEP_DATA above, the card is *not* in the profile + // storage (persisted) anymore, because AUTOFILL_WALLET_DATA is special-cased + // to always clear its data when Sync is turned off. + EXPECT_EQ(1U, GetServerCards(account_data).size()); + EXPECT_EQ(0U, GetServerCards(profile_data).size()); + + // STEP 3. Turn Sync-the-feature on again. + GetSyncService(0)->RequestStart(); + + // Wait for Sync to get reconfigured into full feature mode again. + ASSERT_TRUE(GetClient(0)->AwaitSyncSetupCompletion( + /*skip_passphrase_verification=*/false)); + ASSERT_EQ(syncer::SyncService::TransportState::ACTIVE, + GetSyncService(0)->GetTransportState()); + ASSERT_TRUE(GetSyncService(0)->IsSyncFeatureEnabled()); + ASSERT_TRUE(GetSyncService(0)->IsSyncFeatureActive()); + ASSERT_TRUE(GetSyncService(0)->GetActiveDataTypes().Has( + syncer::AUTOFILL_WALLET_DATA)); + + // PersonalDataManager should have switched back to persistent storage. + EXPECT_TRUE(GetPersonalDataManager(0)->IsSyncFeatureEnabled()); + EXPECT_FALSE( + GetPersonalDataManager(0)->IsUsingAccountStorageForServerCardsForTest()); + + // And the card should be in the profile i.e. persistent storage again. + EXPECT_EQ(0U, GetServerCards(account_data).size()); + EXPECT_EQ(1U, GetServerCards(profile_data).size()); + + // STEP 4. Turn off Sync-the-feature again, but this time clear data. + GetSyncService(0)->RequestStop(syncer::SyncService::CLEAR_DATA); + + // Wait for Sync to get reconfigured into transport mode. + ASSERT_TRUE(GetClient(0)->AwaitSyncSetupCompletion( + /*skip_passphrase_verification=*/false)); + ASSERT_EQ(syncer::SyncService::TransportState::ACTIVE, + GetSyncService(0)->GetTransportState()); + ASSERT_FALSE(GetSyncService(0)->IsSyncFeatureEnabled()); + ASSERT_FALSE(GetSyncService(0)->IsSyncFeatureActive()); + ASSERT_TRUE(GetSyncService(0)->GetActiveDataTypes().Has( + syncer::AUTOFILL_WALLET_DATA)); + + // PersonalDataManager should have switched to ephemeral storage. + EXPECT_FALSE(GetPersonalDataManager(0)->IsSyncFeatureEnabled()); + EXPECT_TRUE( + GetPersonalDataManager(0)->IsUsingAccountStorageForServerCardsForTest()); + + // The card should now be in the account storage (ephemeral). + EXPECT_EQ(1U, GetServerCards(account_data).size()); + EXPECT_EQ(0U, GetServerCards(profile_data).size()); + + // STEP 5. Turn Sync-the-feature on again. + GetSyncService(0)->RequestStart(); + GetSyncService(0)->SetFirstSetupComplete(); + + // Wait for Sync to get reconfigured into full feature mode again. + ASSERT_TRUE(GetClient(0)->AwaitSyncSetupCompletion( + /*skip_passphrase_verification=*/false)); + ASSERT_EQ(syncer::SyncService::TransportState::ACTIVE, + GetSyncService(0)->GetTransportState()); + ASSERT_TRUE(GetSyncService(0)->IsSyncFeatureEnabled()); + ASSERT_TRUE(GetSyncService(0)->IsSyncFeatureActive()); + ASSERT_TRUE(GetSyncService(0)->GetActiveDataTypes().Has( + syncer::AUTOFILL_WALLET_DATA)); + + // PersonalDataManager should have switched back to persistent storage. + EXPECT_TRUE(GetPersonalDataManager(0)->IsSyncFeatureEnabled()); + EXPECT_FALSE( + GetPersonalDataManager(0)->IsUsingAccountStorageForServerCardsForTest()); + + // And the card should be in the profile i.e. persistent storage again. + EXPECT_EQ(0U, GetServerCards(account_data).size()); + EXPECT_EQ(1U, GetServerCards(profile_data).size()); +} + INSTANTIATE_TEST_CASE_P(USS, SingleClientWalletSyncTest, ::testing::Values(false, true));
diff --git a/chrome/browser/sync/test/integration/sync_test.cc b/chrome/browser/sync/test/integration/sync_test.cc index af8be4d..328a8ef8 100644 --- a/chrome/browser/sync/test/integration/sync_test.cc +++ b/chrome/browser/sync/test/integration/sync_test.cc
@@ -666,7 +666,8 @@ invalidation::ProfileInvalidationProviderFactory::GetInstance() ->SetTestingFactoryAndUse( GetProfile(index), - BuildFakeServerProfileInvalidationProvider); + base::BindRepeating( + &BuildFakeServerProfileInvalidationProvider)); } else { test_factory = @@ -674,7 +675,8 @@ GetInstance() ->SetTestingFactoryAndUse( GetProfile(index), - BuildFakeServerProfileInvalidationProvider); + base::BindRepeating( + &BuildFakeServerProfileInvalidationProvider)); } invalidation::InvalidationService* invalidation_service = static_cast<invalidation::ProfileInvalidationProvider*>(test_factory) @@ -712,7 +714,11 @@ } void SyncTest::InitializeInvalidations(int index) { - configuration_refresher_ = std::make_unique<ConfigurationRefresher>(); + // Lazily create |configuration_refresher_| the first time we get here (or the + // first time after a previous call to StopConfigurationRefresher). + if (!configuration_refresher_) { + configuration_refresher_ = std::make_unique<ConfigurationRefresher>(); + } switch (server_type_) { case EXTERNAL_LIVE_SERVER:
diff --git a/chrome/browser/sync/test/integration/two_client_polling_sync_test.cc b/chrome/browser/sync/test/integration/two_client_polling_sync_test.cc index f39f62f..6eb0bb5 100644 --- a/chrome/browser/sync/test/integration/two_client_polling_sync_test.cc +++ b/chrome/browser/sync/test/integration/two_client_polling_sync_test.cc
@@ -10,6 +10,7 @@ #include "chrome/browser/sync/test/integration/sessions_helper.h" #include "chrome/browser/sync/test/integration/sync_test.h" #include "chrome/common/webui_url_constants.h" +#include "components/autofill/core/common/autofill_prefs.h" #include "components/browser_sync/profile_sync_service.h" #include "components/sync/base/sync_prefs.h" #include "components/sync/engine/polling_constants.h" @@ -77,18 +78,39 @@ ASSERT_TRUE(SetupSync()) << "SetupSync() failed."; + // Disable syncing of AUTOFILL_WALLET_DATA: That type is special-cased to + // clear its data even with KEEP_DATA, which means we'd always send a regular + // GetUpdates request on starting Sync again, and so we'd have no need for a + // poll. + GetClient(0)->DisableSyncForDatatype(syncer::AUTOFILL); + GetClient(1)->DisableSyncForDatatype(syncer::AUTOFILL); + // TODO(crbug.com/890737): Once AUTOFILL_WALLET_DATA gets properly disabled + // based on the pref, we can just disable that instead of all of AUTOFILL: + // autofill::prefs::SetPaymentsIntegrationEnabled(GetProfile(0)->GetPrefs(), + // false); + // autofill::prefs::SetPaymentsIntegrationEnabled(GetProfile(1)->GetPrefs(), + // false); + // Phase 1. ASSERT_TRUE(CheckInitialState(0)); ASSERT_TRUE(CheckInitialState(1)); ASSERT_TRUE(OpenTab(0, GURL(chrome::kChromeUIHistoryURL))); GetClient(0)->AwaitMutualSyncCycleCompletion(GetClient(1)); + ASSERT_FALSE(GetSyncService(0)->GetActiveDataTypes().Has( + syncer::AUTOFILL_WALLET_DATA)); + ASSERT_FALSE(GetSyncService(1)->GetActiveDataTypes().Has( + syncer::AUTOFILL_WALLET_DATA)); + // Phase 2. // Disconnect client 1 from sync and write another change from client 0. // Disconnnect the remote client from the invalidation service. DisableNotificationsForClient(1); // Make sure no extra sync cycles get triggered by test infrastructure. StopConfigurationRefresher(); + // Note: It's important to specify KEEP_DATA here - if we CLEAR_DATA, then + // we'll do a regular GetUpdates at the next startup, so there'd be no need + // for a poll. GetClient(1)->StopSyncService(syncer::SyncService::KEEP_DATA); ASSERT_TRUE(OpenTab(0, GURL(kURL1)));
diff --git a/chrome/browser/ui/passwords/manage_passwords_bubble_model_unittest.cc b/chrome/browser/ui/passwords/manage_passwords_bubble_model_unittest.cc index 76275238..98b13c55 100644 --- a/chrome/browser/ui/passwords/manage_passwords_bubble_model_unittest.cc +++ b/chrome/browser/ui/passwords/manage_passwords_bubble_model_unittest.cc
@@ -9,6 +9,7 @@ #include <utility> #include <vector> +#include "base/bind.h" #include "base/metrics/histogram_samples.h" #include "base/run_loop.h" #include "base/strings/utf_string_conversions.h" @@ -137,9 +138,10 @@ .WillByDefault(Return(nullptr)); PasswordStoreFactory::GetInstance()->SetTestingFactoryAndUse( profile(), - password_manager::BuildPasswordStore< - content::BrowserContext, - testing::StrictMock<password_manager::MockPasswordStore>>); + base::BindRepeating( + &password_manager::BuildPasswordStore< + content::BrowserContext, + testing::StrictMock<password_manager::MockPasswordStore>>)); pending_password_.origin = GURL(kSiteOrigin); pending_password_.signon_realm = kSiteOrigin; pending_password_.username_value = base::ASCIIToUTF16(kUsername); @@ -551,7 +553,7 @@ TEST_P(ManagePasswordsBubbleModelManageLinkTest, OnManageClicked) { TestSyncService* sync_service = static_cast<TestSyncService*>( ProfileSyncServiceFactory::GetInstance()->SetTestingFactoryAndUse( - profile(), &TestingSyncFactoryFunction)); + profile(), base::BindRepeating(&TestingSyncFactoryFunction))); sync_service->set_synced_types(GetParam()); PretendManagingPasswords();
diff --git a/chrome/browser/ui/passwords/password_manager_presenter_unittest.cc b/chrome/browser/ui/passwords/password_manager_presenter_unittest.cc index ca9cd6d..fafe6e5 100644 --- a/chrome/browser/ui/passwords/password_manager_presenter_unittest.cc +++ b/chrome/browser/ui/passwords/password_manager_presenter_unittest.cc
@@ -43,8 +43,9 @@ void SetUp() override { PasswordStoreFactory::GetInstance()->SetTestingFactory( &profile_, - password_manager::BuildPasswordStore< - content::BrowserContext, password_manager::MockPasswordStore>); + base::BindRepeating( + &password_manager::BuildPasswordStore< + content::BrowserContext, password_manager::MockPasswordStore>)); mock_controller_.reset(new MockPasswordUIView(&profile_)); } void AddPasswordEntry(const GURL& origin,
diff --git a/chrome/browser/ui/startup/startup_browser_creator_triggered_reset_browsertest_win.cc b/chrome/browser/ui/startup/startup_browser_creator_triggered_reset_browsertest_win.cc index 09ac1dd..02d4626 100644 --- a/chrome/browser/ui/startup/startup_browser_creator_triggered_reset_browsertest_win.cc +++ b/chrome/browser/ui/startup/startup_browser_creator_triggered_reset_browsertest_win.cc
@@ -6,6 +6,7 @@ #include <memory> +#include "base/bind.h" #include "base/callback_list.h" #include "base/command_line.h" #include "base/macros.h" @@ -98,7 +99,7 @@ private: void OnWillCreateBrowserContextServices(content::BrowserContext* context) { TriggeredProfileResetterFactory::GetInstance()->SetTestingFactory( - context, &BuildMockTriggeredProfileResetter); + context, base::BindRepeating(&BuildMockTriggeredProfileResetter)); } std::unique_ptr<
diff --git a/chrome/browser/ui/sync/one_click_signin_sync_observer_unittest.cc b/chrome/browser/ui/sync/one_click_signin_sync_observer_unittest.cc index 4ea452e2..73e05ead 100644 --- a/chrome/browser/ui/sync/one_click_signin_sync_observer_unittest.cc +++ b/chrome/browser/ui/sync/one_click_signin_sync_observer_unittest.cc
@@ -115,12 +115,6 @@ DISALLOW_COPY_AND_ASSIGN(TestOneClickSigninSyncObserver); }; -// A trivial factory to build a null service. -std::unique_ptr<KeyedService> BuildNullService( - content::BrowserContext* context) { - return nullptr; -} - } // namespace class OneClickSigninSyncObserverTest : public ChromeRenderViewHostTestHarness { @@ -135,7 +129,8 @@ web_contents_observer_.reset(new MockWebContentsObserver(web_contents())); sync_service_ = static_cast<OneClickTestProfileSyncService*>( ProfileSyncServiceFactory::GetInstance()->SetTestingFactoryAndUse( - profile(), OneClickTestProfileSyncService::Build)); + profile(), + base::BindRepeating(&OneClickTestProfileSyncService::Build))); } void TearDown() override { @@ -179,9 +174,11 @@ // observer immediately loads the continue URL. TEST_F(OneClickSigninSyncObserverTest, NoSyncService_RedirectsImmediately) { // Simulate disabling Sync. + ProfileSyncServiceFactory::GetInstance()->SetTestingFactory( + profile(), BrowserContextKeyedServiceFactory::TestingFactory()); + sync_service_ = static_cast<OneClickTestProfileSyncService*>( - ProfileSyncServiceFactory::GetInstance()->SetTestingFactoryAndUse( - profile(), BuildNullService)); + ProfileSyncServiceFactory::GetInstance()->GetForProfile(profile())); // The observer should immediately redirect to the continue URL. EXPECT_CALL(*web_contents_observer_, DidStartNavigation(_));
diff --git a/chrome/browser/ui/sync/one_click_signin_sync_starter_unittest.cc b/chrome/browser/ui/sync/one_click_signin_sync_starter_unittest.cc index 6008dcc5..bd27421d 100644 --- a/chrome/browser/ui/sync/one_click_signin_sync_starter_unittest.cc +++ b/chrome/browser/ui/sync/one_click_signin_sync_starter_unittest.cc
@@ -4,6 +4,7 @@ #include "chrome/browser/ui/sync/one_click_signin_sync_starter.h" +#include "base/bind.h" #include "base/command_line.h" #include "base/compiler_specific.h" #include "base/macros.h" @@ -65,7 +66,8 @@ TestingProfile::Builder builder; builder.AddTestingFactory( SigninManagerFactory::GetInstance(), - &OneClickSigninSyncStarterTest::BuildSigninManager); + base::BindRepeating( + &OneClickSigninSyncStarterTest::BuildSigninManager)); return builder.Build().release(); }
diff --git a/chrome/browser/ui/sync/sync_promo_ui_unittest.cc b/chrome/browser/ui/sync/sync_promo_ui_unittest.cc index e529df1..5a760d1 100644 --- a/chrome/browser/ui/sync/sync_promo_ui_unittest.cc +++ b/chrome/browser/ui/sync/sync_promo_ui_unittest.cc
@@ -6,6 +6,7 @@ #include <memory> +#include "base/bind.h" #include "base/command_line.h" #include "base/compiler_specific.h" #include "base/macros.h" @@ -27,7 +28,7 @@ testing::Test::SetUp(); TestingProfile::Builder builder; builder.AddTestingFactory(SigninManagerFactory::GetInstance(), - BuildFakeSigninManagerBase); + base::BindRepeating(&BuildFakeSigninManagerBase)); profile_ = builder.Build(); }
diff --git a/chrome/browser/ui/toolbar/media_router_contextual_menu_unittest.cc b/chrome/browser/ui/toolbar/media_router_contextual_menu_unittest.cc index a2c1a97..0016ac8b 100644 --- a/chrome/browser/ui/toolbar/media_router_contextual_menu_unittest.cc +++ b/chrome/browser/ui/toolbar/media_router_contextual_menu_unittest.cc
@@ -86,7 +86,8 @@ MediaRouterActionController::SetAlwaysShowActionPref(profile(), true); media_router::MediaRouterUIServiceFactory::GetInstance()->SetTestingFactory( - profile()->GetOffTheRecordProfile(), &BuildUIService); + profile()->GetOffTheRecordProfile(), + base::BindRepeating(&BuildUIService)); } void TearDown() override {
diff --git a/chrome/browser/ui/views/autofill/save_card_bubble_views_browsertest_base.cc b/chrome/browser/ui/views/autofill/save_card_bubble_views_browsertest_base.cc index 86cfa810..8c30942 100644 --- a/chrome/browser/ui/views/autofill/save_card_bubble_views_browsertest_base.cc +++ b/chrome/browser/ui/views/autofill/save_card_bubble_views_browsertest_base.cc
@@ -9,6 +9,7 @@ #include <string> #include <utility> +#include "base/bind.h" #include "chrome/browser/signin/account_fetcher_service_factory.h" #include "chrome/browser/signin/account_tracker_service_factory.h" #include "chrome/browser/signin/fake_account_fetcher_service_builder.h" @@ -157,9 +158,10 @@ content::BrowserContext* context) { // Replace the signin manager and account fetcher service with fakes. SigninManagerFactory::GetInstance()->SetTestingFactory( - context, &BuildFakeSigninManagerBase); + context, base::BindRepeating(&BuildFakeSigninManagerBase)); AccountFetcherServiceFactory::GetInstance()->SetTestingFactory( - context, &FakeAccountFetcherServiceBuilder::BuildForTests); + context, + base::BindRepeating(&FakeAccountFetcherServiceBuilder::BuildForTests)); } void SaveCardBubbleViewsBrowserTestBase::SignInWithFullName(
diff --git a/chrome/browser/ui/views/bookmarks/bookmark_bar_view_unittest.cc b/chrome/browser/ui/views/bookmarks/bookmark_bar_view_unittest.cc index 648661e..6eeea38 100644 --- a/chrome/browser/ui/views/bookmarks/bookmark_bar_view_unittest.cc +++ b/chrome/browser/ui/views/bookmarks/bookmark_bar_view_unittest.cc
@@ -6,6 +6,7 @@ #include <memory> +#include "base/bind.h" #include "base/macros.h" #include "base/memory/ptr_util.h" #include "base/strings/utf_string_conversions.h" @@ -119,7 +120,8 @@ // TemplateURLService is normally NULL during testing. Instant extended // needs this service so set a custom factory function. TemplateURLServiceFactory::GetInstance()->SetTestingFactory( - profile, &BookmarkBarViewTest::CreateTemplateURLService); + profile, + base::BindRepeating(&BookmarkBarViewTest::CreateTemplateURLService)); return profile; }
diff --git a/chrome/browser/ui/views/frame/OWNERS b/chrome/browser/ui/views/frame/OWNERS index a03d7983..ceae6b94 100644 --- a/chrome/browser/ui/views/frame/OWNERS +++ b/chrome/browser/ui/views/frame/OWNERS
@@ -5,5 +5,6 @@ per-file immersive_mode_controller*=pkotwicz@chromium.org per-file *x11*=thomasanderson@chromium.org per-file desktop_linux_browser_frame_view*=thomasanderson@chromium.org +per-file top_controls_slide_controller*=afakhry@chromium.org # COMPONENT: UI>Browser
diff --git a/chrome/browser/ui/views/frame/top_controls_slide_controller.h b/chrome/browser/ui/views/frame/top_controls_slide_controller.h index dfa72ed..e243e65 100644 --- a/chrome/browser/ui/views/frame/top_controls_slide_controller.h +++ b/chrome/browser/ui/views/frame/top_controls_slide_controller.h
@@ -52,6 +52,9 @@ // changed state. virtual void SetTopControlsGestureScrollInProgress(bool in_progress) = 0; + // Returns true while gesture scrolls are in progress. + virtual bool IsTopControlsGestureScrollInProgress() const = 0; + private: DISALLOW_COPY_AND_ASSIGN(TopControlsSlideController); };
diff --git a/chrome/browser/ui/views/frame/top_controls_slide_controller_chromeos.cc b/chrome/browser/ui/views/frame/top_controls_slide_controller_chromeos.cc index c1b0b08..dfd23d4 100644 --- a/chrome/browser/ui/views/frame/top_controls_slide_controller_chromeos.cc +++ b/chrome/browser/ui/views/frame/top_controls_slide_controller_chromeos.cc
@@ -163,9 +163,9 @@ float shown_ratio() const { return shown_ratio_; } bool shrink_renderer_size() const { return shrink_renderer_size_; } - void SetShownRatio(float ratio, bool sliding_in_progress) { + void SetShownRatio(float ratio, bool sliding_or_scrolling_in_progress) { shown_ratio_ = ratio; - if (!sliding_in_progress) + if (!sliding_or_scrolling_in_progress) UpdateDoBrowserControlsShrinkRendererSize(); } @@ -248,8 +248,8 @@ // Indicates whether the renderer's viewport size should be shrunk by the // height of the browser's top controls. This value should only be updated at - // the end of sliding, and should never change while sliding is in progress. - // https://crbug.com/885223. + // the end of sliding, and should never change while sliding or scrolling are + // in progress. https://crbug.com/885223. bool shrink_renderer_size_ = true; DISALLOW_COPY_AND_ASSIGN(TopControlsSlideTabObserver); @@ -303,7 +303,22 @@ // Make sure the value tracked per tab is always updated even when sliding is // disabled, so that we're always synchronized with the renderer. DCHECK(observed_tabs_.count(contents)); - observed_tabs_[contents]->SetShownRatio(ratio, is_sliding_in_progress_); + + // Note that there are two small windows of intervals between: + // 1- When |is_gesture_scrolling_in_progress_| is set to true (i.e. received + // ET_GESTURE_SCROLL_BEGIN) and when |is_sliding_in_progress_| is set to + // true (i.e. top-chrome actually starts moving), and + // 2- When |is_gesture_scrolling_in_progress_| is set to false (i.e. + // ET_GESTURE_SCROLL_END was received) and when |is_sliding_in_progress_| + // is set to false (i.e. top-chrome stopped moving) which can happen as the + // renderer continues to animate top-chrome towards fully-shown or + // fully-hidden after the user had lifted their fingers while the + // shown_ratio is still a fractional value. + // Even during those two small windows, the + // `DoBrowserControlsShrinkRendererSize` bit should remain unchanged from its + // current value until sliding reaches a steady state. + observed_tabs_[contents]->SetShownRatio( + ratio, is_gesture_scrolling_in_progress_ || is_sliding_in_progress_); if (!IsEnabled()) { // However, if sliding is disabled, we don't update |shown_ratio_|, which is @@ -369,6 +384,11 @@ Refresh(); } +bool TopControlsSlideControllerChromeOS::IsTopControlsGestureScrollInProgress() + const { + return is_gesture_scrolling_in_progress_; +} + void TopControlsSlideControllerChromeOS::OnTabletModeToggled( bool tablet_mode_enabled) { OnEnabledStateChanged(tablet_mode_enabled && !browser_view_->IsFullscreen());
diff --git a/chrome/browser/ui/views/frame/top_controls_slide_controller_chromeos.h b/chrome/browser/ui/views/frame/top_controls_slide_controller_chromeos.h index 0c0b11b..ff1a1262 100644 --- a/chrome/browser/ui/views/frame/top_controls_slide_controller_chromeos.h +++ b/chrome/browser/ui/views/frame/top_controls_slide_controller_chromeos.h
@@ -51,6 +51,7 @@ bool DoBrowserControlsShrinkRendererSize( const content::WebContents* contents) const override; void SetTopControlsGestureScrollInProgress(bool in_progress) override; + bool IsTopControlsGestureScrollInProgress() const override; // TabletModeClientObserver: void OnTabletModeToggled(bool tablet_mode_enabled) override;
diff --git a/chrome/browser/ui/views/frame/top_controls_slide_controller_chromeos_browsertest.cc b/chrome/browser/ui/views/frame/top_controls_slide_controller_chromeos_browsertest.cc index c104d14..51520c6 100644 --- a/chrome/browser/ui/views/frame/top_controls_slide_controller_chromeos_browsertest.cc +++ b/chrome/browser/ui/views/frame/top_controls_slide_controller_chromeos_browsertest.cc
@@ -54,11 +54,24 @@ const gfx::Point& start_point, const gfx::Point& end_point) { DCHECK(generator); - generator->GestureScrollSequence( + generator->GestureScrollSequenceWithCallback( start_point, end_point, generator->CalculateScrollDurationForFlingVelocity( start_point, end_point, 100 /* velocity */, 2 /* steps */), - 2 /* steps */); + 2 /* steps */, + base::BindRepeating([](ui::EventType, const gfx::Vector2dF&) { + // Give the event a chance to propagate to renderer before sending the + // next one. + base::RunLoop().RunUntilIdle(); + })); +} + +// Checks that the translation part of the two given transforms are equal. +void CompareTranslations(const gfx::Transform& t1, const gfx::Transform& t2) { + const gfx::Vector2dF t1_translation = t1.To2dTranslation(); + const gfx::Vector2dF t2_translation = t2.To2dTranslation(); + EXPECT_FLOAT_EQ(t1_translation.x(), t2_translation.x()); + EXPECT_FLOAT_EQ(t1_translation.y(), t2_translation.y()); } // Waits for the first non-empty paint for a given WebContents. To be able to @@ -87,7 +100,8 @@ DISALLOW_COPY_AND_ASSIGN(TabNonEmptyPaintWaiter); }; -// Waits for a given browser top controls shown ratio on a given browser window. +// Waits for a given terminal value (1.f or 0.f) of the browser top controls +// shown ratio on a given browser window. class TopControlsShownRatioWaiter { public: explicit TopControlsShownRatioWaiter( @@ -95,6 +109,10 @@ : controller_(controller) {} void WaitForRatio(float ratio) { + DCHECK(ratio == 1.f || ratio == 0.f) << "Should only be used to wait for " + "terminal values of the shown " + "ratio."; + waiting_for_shown_ratio_ = ratio; if (CheckRatio()) return; @@ -105,7 +123,11 @@ private: bool CheckRatio() { - if (cc::MathUtil::IsWithinEpsilon(controller_->GetShownRatio(), + // To avoid flakes, we also check that gesture scrolling is not in progress + // which means for a terminal value of the shown ratio (that we're waiting + // for) sliding is also not in progress and we reached a steady state. + if (!controller_->IsTopControlsGestureScrollInProgress() && + cc::MathUtil::IsWithinEpsilon(controller_->GetShownRatio(), waiting_for_shown_ratio_)) { if (run_loop_) run_loop_->Quit(); @@ -272,15 +294,76 @@ } } - private: - void CompareTranslations(const gfx::Transform& t1, - const gfx::Transform& t2) const { - const gfx::Vector2dF t1_translation = t1.To2dTranslation(); - const gfx::Vector2dF t2_translation = t2.To2dTranslation(); - EXPECT_FLOAT_EQ(t1_translation.x(), t2_translation.x()); - EXPECT_FLOAT_EQ(t1_translation.y(), t2_translation.y()); + // This is used as a callback of type |ScrollStepCallback| of the function + // EventGenerator::GestureScrollSequenceWithCallback() that will be called at + // the scroll steps of ET_GESTURE_SCROLL_BEGIN, ET_GESTURE_SCROLL_UPDATE, and + // ET_GESTURE_SCROLL_END. + // + // It verifies the state of the browser window when the active page is being + // scrolled by touch gestures in such a way that will result in the top + // controls shown ratio becoming a fractional value (i.e. sliding top-chrome + // is in progress). + // The |expected_shrink_renderer_size| will be checked against the + // `DoBrowserControlsShrinkRendererSize` bit while sliding. + // |out_seen_fractional_shown_ratio| will be set to true if a fractional value + // of the shown_ratio has been seen. + // |event_type| and |delta| are callback parameters of |ScrollStepCallback|. + void CheckIntermediateScrollStep(bool expected_shrink_renderer_size, + bool* out_seen_fractional_shown_ratio, + ui::EventType event_type, + const gfx::Vector2dF& delta) { + // Give the event a chance to propagate to renderer before sending the + // next one. + base::RunLoop().RunUntilIdle(); + + if (event_type != ui::ET_GESTURE_SCROLL_UPDATE) + return; + + const float shown_ratio = top_controls_slide_controller()->GetShownRatio(); + if (shown_ratio == 1.f || shown_ratio == 0.f) { + // Test only intermediate values. + return; + } + + *out_seen_fractional_shown_ratio = true; + + const int top_controls_height = browser_view()->GetTopControlsHeight(); + EXPECT_NE(top_controls_height, 0); + + ui::Layer* root_view_layer = + browser_view()->frame()->GetRootView()->layer(); + + // While sliding is in progress, the root view paints to a layer. + ASSERT_TRUE(root_view_layer); + + // This will be called repeatedly while scrolling is in progress. The + // `DoBrowserControlsShrinkRendererSize` bit should remain the same as the + // expected value. + EXPECT_EQ(expected_shrink_renderer_size, + browser_view()->DoBrowserControlsShrinkRendererSize( + browser_view()->GetActiveWebContents())); + + // Check intermediate transforms. + gfx::Transform expected_transform; + const float y_translation = top_controls_height * (shown_ratio - 1.f); + expected_transform.Translate(0, y_translation); + + ASSERT_TRUE(browser_view() + ->contents_web_view() + ->holder() + ->GetNativeViewContainer()); + ui::Layer* contents_container_layer = browser_view() + ->contents_web_view() + ->holder() + ->GetNativeViewContainer() + ->layer(); + ASSERT_TRUE(contents_container_layer); + CompareTranslations(expected_transform, + contents_container_layer->transform()); + CompareTranslations(expected_transform, root_view_layer->transform()); } + private: base::test::ScopedFeatureList scoped_feature_list_; DISALLOW_COPY_AND_ASSIGN(TopControlsSlideControllerTest); @@ -801,4 +884,77 @@ CheckBrowserLayout(browser_view(), TopChromeShownState::kFullyHidden); } +IN_PROC_BROWSER_TEST_F(TopControlsSlideControllerTest, + TestIntermediateSliding) { + ToggleTabletMode(); + ASSERT_TRUE(GetTabletModeEnabled()); + EXPECT_TRUE(top_controls_slide_controller()->IsEnabled()); + EXPECT_FLOAT_EQ(top_controls_slide_controller()->GetShownRatio(), 1.f); + + // Navigate to our test page that has a long vertical content which we can use + // to test page scrolling. + OpenUrlAtIndex(embedded_test_server()->GetURL("/top_controls_scroll.html"), + 0); + content::WebContents* active_contents = + browser_view()->GetActiveWebContents(); + PageStateUpdateWaiter page_state_update_waiter(active_contents); + page_state_update_waiter.Wait(); + EXPECT_TRUE( + browser_view()->DoBrowserControlsShrinkRendererSize(active_contents)); + + aura::Window* browser_window = browser()->window()->GetNativeWindow(); + ui::test::EventGenerator event_generator(browser_window->GetRootWindow(), + browser_window); + const gfx::Point start_point = event_generator.current_location(); + const gfx::Point end_point = start_point + gfx::Vector2d(0, -100); + + // Large number of ET_GESTURE_SCROLL_UPDATE steps that we can see fractional + // shown ratios while scrolling is in progress. + const int scroll_steps = 1000; + const base::TimeDelta scroll_step_delay = + event_generator.CalculateScrollDurationForFlingVelocity( + start_point, end_point, 1000 /* velocity */, scroll_steps); + + // We need to verify that a fractional value of the shown ratio has been seen, + // otherwise the test is useless, since we want to verify the state while + // sliding in in progress. + bool seen_fractional_shown_ratio = false; + + // We will start scrolling while top-chrome is fully shown, in which case the + // `DoBrowserControlsShrinkRendererSize` bit is true. It should remain true + // while sliding is in progress. + bool expected_shrink_renderer_size = true; + event_generator.GestureScrollSequenceWithCallback( + start_point, end_point, scroll_step_delay, scroll_steps, + base::BindRepeating( + &TopControlsSlideControllerTest::CheckIntermediateScrollStep, + base::Unretained(this), expected_shrink_renderer_size, + &seen_fractional_shown_ratio)); + EXPECT_TRUE(seen_fractional_shown_ratio); + TopControlsShownRatioWaiter waiter(top_controls_slide_controller()); + waiter.WaitForRatio(0.f); + EXPECT_FLOAT_EQ(top_controls_slide_controller()->GetShownRatio(), 0); + CheckBrowserLayout(browser_view(), TopChromeShownState::kFullyHidden); + + // Now that sliding ended, and top-chrome is fully hidden, the + // `DoBrowserControlsShrinkRendererSize` bit should be false ... + EXPECT_FALSE( + browser_view()->DoBrowserControlsShrinkRendererSize(active_contents)); + + // ... and when scrolling in the other direction towards a fully shown + // top-chrome, it should remain false while sliding is in progress. + expected_shrink_renderer_size = false; + seen_fractional_shown_ratio = false; + event_generator.GestureScrollSequenceWithCallback( + end_point, start_point, scroll_step_delay, scroll_steps, + base::BindRepeating( + &TopControlsSlideControllerTest::CheckIntermediateScrollStep, + base::Unretained(this), expected_shrink_renderer_size, + &seen_fractional_shown_ratio)); + EXPECT_TRUE(seen_fractional_shown_ratio); + waiter.WaitForRatio(1.f); + EXPECT_FLOAT_EQ(top_controls_slide_controller()->GetShownRatio(), 1.f); + CheckBrowserLayout(browser_view(), TopChromeShownState::kFullyShown); +} + } // namespace
diff --git a/chrome/browser/ui/views/profiles/profile_chooser_view.cc b/chrome/browser/ui/views/profiles/profile_chooser_view.cc index c2b70576..a744523 100644 --- a/chrome/browser/ui/views/profiles/profile_chooser_view.cc +++ b/chrome/browser/ui/views/profiles/profile_chooser_view.cc
@@ -642,6 +642,8 @@ if (browser_->profile()->IsGuestSession()) { profiles::CloseGuestProfileWindows(); } else { + base::RecordAction( + base::UserMetricsAction("ProfileChooser_ManageClicked")); UserManager::Show(base::FilePath(), profiles::USER_MANAGER_SELECT_PROFILE_NO_ACTION); } @@ -726,7 +728,6 @@ ShowViewFromMode(view_mode_ == profiles::BUBBLE_VIEW_MODE_ACCOUNT_MANAGEMENT ? profiles::BUBBLE_VIEW_MODE_PROFILE_CHOOSER : profiles::BUBBLE_VIEW_MODE_ACCOUNT_MANAGEMENT); - base::RecordAction(base::UserMetricsAction("ProfileChooser_ManageClicked")); } else if (sender == signin_current_profile_button_) { ShowViewFromMode(profiles::BUBBLE_VIEW_MODE_GAIA_SIGNIN); } else if (sender == signin_with_gaia_account_button_) {
diff --git a/chrome/browser/ui/webui/chromeos/login/enrollment_screen_handler.cc b/chrome/browser/ui/webui/chromeos/login/enrollment_screen_handler.cc index e2defdd..7fc1bc3d 100644 --- a/chrome/browser/ui/webui/chromeos/login/enrollment_screen_handler.cc +++ b/chrome/browser/ui/webui/chromeos/login/enrollment_screen_handler.cc
@@ -565,8 +565,6 @@ /* Active Directory strings */ builder->Add("oauthEnrollAdMachineNameInput", IDS_AD_DEVICE_NAME_INPUT_LABEL); - builder->Add("oauthEnrollAdMachineNameInputRegex", - IDS_AD_DEVICE_NAME_REGEX_INPUT_LABEL); builder->Add("oauthEnrollAdDomainJoinWelcomeMessage", IDS_AD_DOMAIN_JOIN_WELCOME_MESSAGE); builder->Add("adAuthLoginUsername", IDS_AD_AUTH_LOGIN_USER);
diff --git a/chrome/browser/ui/webui/print_preview/extension_printer_handler_unittest.cc b/chrome/browser/ui/webui/print_preview/extension_printer_handler_unittest.cc index e1f1803..668ae76e 100644 --- a/chrome/browser/ui/webui/print_preview/extension_printer_handler_unittest.cc +++ b/chrome/browser/ui/webui/print_preview/extension_printer_handler_unittest.cc
@@ -452,7 +452,7 @@ void SetUp() override { extensions::PrinterProviderAPIFactory::GetInstance()->SetTestingFactory( - env_.profile(), &BuildTestingPrinterProviderAPI); + env_.profile(), base::BindRepeating(&BuildTestingPrinterProviderAPI)); extension_printer_handler_ = std::make_unique<ExtensionPrinterHandler>(env_.profile());
diff --git a/chrome/browser/ui/webui/signin/dice_turn_sync_on_helper_unittest.cc b/chrome/browser/ui/webui/signin/dice_turn_sync_on_helper_unittest.cc index d962685..0ab3077 100644 --- a/chrome/browser/ui/webui/signin/dice_turn_sync_on_helper_unittest.cc +++ b/chrome/browser/ui/webui/signin/dice_turn_sync_on_helper_unittest.cc
@@ -189,19 +189,22 @@ TestingProfile::Builder profile_builder; profile_builder.AddTestingFactory( ProfileOAuth2TokenServiceFactory::GetInstance(), - BuildFakeProfileOAuth2TokenService); - profile_builder.AddTestingFactory(SigninManagerFactory::GetInstance(), - BuildFakeSigninManagerBase); - profile_builder.AddTestingFactory(ChromeSigninClientFactory::GetInstance(), - signin::BuildTestSigninClient); - profile_builder.AddTestingFactory(ProfileSyncServiceFactory::GetInstance(), - &BuildMockProfileSyncService); + base::BindRepeating(&BuildFakeProfileOAuth2TokenService)); + profile_builder.AddTestingFactory( + SigninManagerFactory::GetInstance(), + base::BindRepeating(&BuildFakeSigninManagerBase)); + profile_builder.AddTestingFactory( + ChromeSigninClientFactory::GetInstance(), + base::BindRepeating(&signin::BuildTestSigninClient)); + profile_builder.AddTestingFactory( + ProfileSyncServiceFactory::GetInstance(), + base::BindRepeating(&BuildMockProfileSyncService)); profile_builder.AddTestingFactory( policy::UserPolicySigninServiceFactory::GetInstance(), - &FakeUserPolicySigninService::Build); + base::BindRepeating(&FakeUserPolicySigninService::Build)); profile_builder.AddTestingFactory( UnifiedConsentServiceFactory::GetInstance(), - &BuildUnifiedConsentServiceForTesting); + base::BindRepeating(&BuildUnifiedConsentServiceForTesting)); profile_ = profile_builder.Build(); account_tracker_service_ = AccountTrackerServiceFactory::GetForProfile(profile());
diff --git a/chrome/browser/ui/webui/signin/inline_login_ui_browsertest.cc b/chrome/browser/ui/webui/signin/inline_login_ui_browsertest.cc index 2be52a36..e6ead2d 100644 --- a/chrome/browser/ui/webui/signin/inline_login_ui_browsertest.cc +++ b/chrome/browser/ui/webui/signin/inline_login_ui_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/bind.h" #include "base/command_line.h" #include "base/macros.h" #include "base/memory/ref_counted.h" @@ -468,9 +469,9 @@ // creating the browser so that a bunch of classes don't register as // observers and end up needing to unregister when the fake is substituted. SigninManagerFactory::GetInstance()->SetTestingFactory( - context, &BuildFakeSigninManagerBase); + context, base::BindRepeating(&BuildFakeSigninManagerBase)); ProfileOAuth2TokenServiceFactory::GetInstance()->SetTestingFactory( - context, &BuildFakeProfileOAuth2TokenService); + context, base::BindRepeating(&BuildFakeProfileOAuth2TokenService)); } void SetUp() override {
diff --git a/chrome/browser/ui/webui/signin/login_ui_service.cc b/chrome/browser/ui/webui/signin/login_ui_service.cc index f5ca3a7..53b61e31 100644 --- a/chrome/browser/ui/webui/signin/login_ui_service.cc +++ b/chrome/browser/ui/webui/signin/login_ui_service.cc
@@ -81,7 +81,7 @@ UnifiedConsentServiceFactory::GetForProfile(profile_); if (consent_service->ShouldShowConsentBump()) { consent_service->RecordConsentBumpSuppressReason( - unified_consent::ConsentBumpSuppressReason::kSyncPaused); + unified_consent::metrics::ConsentBumpSuppressReason::kSyncPaused); } return; }
diff --git a/chrome/browser/ui/webui/signin/user_manager_ui_browsertest.cc b/chrome/browser/ui/webui/signin/user_manager_ui_browsertest.cc index 3fb05ba..2af1ae5 100644 --- a/chrome/browser/ui/webui/signin/user_manager_ui_browsertest.cc +++ b/chrome/browser/ui/webui/signin/user_manager_ui_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/bind.h" #include "base/command_line.h" #include "base/run_loop.h" #include "base/strings/string_util.h" @@ -164,7 +165,7 @@ entry_->SetSupervisedUserId("supervised_user_id"); MockLoginUIService* service = static_cast<MockLoginUIService*>( LoginUIServiceFactory::GetInstance()->SetTestingFactoryAndUse( - profile_, CreateLoginUIService)); + profile_, base::BindRepeating(&CreateLoginUIService))); EXPECT_CALL(*service, DisplayLoginResult(_, _, _)); LaunchAuthenticatedUser(""); @@ -181,7 +182,7 @@ entry_->SetActiveTimeToNow(); MockLoginUIService* service = static_cast<MockLoginUIService*>( LoginUIServiceFactory::GetInstance()->SetTestingFactoryAndUse( - profile_, CreateLoginUIService)); + profile_, base::BindRepeating(&CreateLoginUIService))); EXPECT_CALL(*service, SetProfileBlockingErrorMessage()); LaunchAuthenticatedUser("");
diff --git a/chrome/browser/usb/usb_policy_allowed_devices.cc b/chrome/browser/usb/usb_policy_allowed_devices.cc new file mode 100644 index 0000000..f7c87e60 --- /dev/null +++ b/chrome/browser/usb/usb_policy_allowed_devices.cc
@@ -0,0 +1,127 @@ +// 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/usb/usb_policy_allowed_devices.h" + +#include "base/values.h" +#include "components/content_settings/core/common/content_settings_pattern.h" +#include "components/content_settings/core/common/pref_names.h" +#include "components/prefs/pref_service.h" +#include "device/usb/public/mojom/device_manager.mojom.h" +#include "url/gurl.h" + +namespace { + +constexpr char kPrefDevicesKey[] = "devices"; +constexpr char kPrefUrlPatternsKey[] = "url_patterns"; +constexpr char kPrefVendorIdKey[] = "vendor_id"; +constexpr char kPrefProductIdKey[] = "product_id"; + +// Find the URL match by checking if the pattern matches the given GURL types +// using ContentSettingsPattern::Matches(). +bool FindMatchInSet(const std::set<content_settings::PatternPair>& pattern_set, + const GURL& requesting_origin, + const GURL& embedding_origin) { + for (const auto& pattern : pattern_set) { + if (pattern.first.Matches(requesting_origin) && + pattern.second.Matches(embedding_origin)) { + return true; + } + } + return false; +} + +} // namespace + +UsbPolicyAllowedDevices::UsbPolicyAllowedDevices(PrefService* pref_service) { + pref_change_registrar_.Init(pref_service); + // Add an observer for |kManagedWebUsbAllowDevicesForUrls| to call + // CreateOrUpdateMap when the value is changed. The lifetime of + // |pref_change_registrar_| is managed by this class, therefore it is safe to + // use base::Unretained here. + pref_change_registrar_.Add( + prefs::kManagedWebUsbAllowDevicesForUrls, + base::BindRepeating(&UsbPolicyAllowedDevices::CreateOrUpdateMap, + base::Unretained(this))); + + CreateOrUpdateMap(); +} + +UsbPolicyAllowedDevices::~UsbPolicyAllowedDevices() {} + +bool UsbPolicyAllowedDevices::IsDeviceAllowed( + const GURL& requesting_origin, + const GURL& embedding_origin, + const device::mojom::UsbDeviceInfo& device_info) { + // Search through each set of URL patterns that match the given device. The + // keys correspond to the following URL pattern sets: + // * (vendor_id, product_id): A set corresponding to the exact device. + // * (vendor_id, -1): A set corresponding to any device with |vendor_id|. + // * (-1, -1): A set corresponding to any device. + const std::pair<int, int> set_keys[] = { + std::make_pair(device_info.vendor_id, device_info.product_id), + std::make_pair(device_info.vendor_id, -1), std::make_pair(-1, -1)}; + + for (const auto& key : set_keys) { + const auto patterns = usb_device_ids_to_url_patterns_.find(key); + if (patterns == usb_device_ids_to_url_patterns_.cend()) + continue; + + if (FindMatchInSet(patterns->second, requesting_origin, embedding_origin)) + return true; + } + return false; +} + +void UsbPolicyAllowedDevices::CreateOrUpdateMap() { + const base::Value* pref_value = pref_change_registrar_.prefs()->Get( + prefs::kManagedWebUsbAllowDevicesForUrls); + usb_device_ids_to_url_patterns_.clear(); + + // A policy has not been assigned. + if (!pref_value) { + return; + } + + // The pref value has already been validated by the policy handler, so it is + // safe to assume that |pref_value| follows the policy template. + for (const auto& item : pref_value->GetList()) { + const base::Value* url_patterns = item.FindKey(kPrefUrlPatternsKey); + std::set<content_settings::PatternPair> parsed_url_set; + + // Parse each URL pattern into a PatternPair and store it in + // |parsed_url_set|. + for (const auto& url_pattern : url_patterns->GetList()) { + content_settings::PatternPair pattern_pair = + content_settings::ParsePatternString(url_pattern.GetString()); + + // Ignore invalid patterns. + if (!pattern_pair.first.IsValid()) + continue; + + parsed_url_set.insert(std::move(pattern_pair)); + } + + // Ignore items with empty parsed URLs. + if (parsed_url_set.empty()) + continue; + + // For each device entry in the map, create or update its respective URL + // pattern set. + const base::Value* devices = item.FindKey(kPrefDevicesKey); + for (const auto& device : devices->GetList()) { + // A missing ID signifies a wildcard for that ID, so a sentinel value of + // -1 is assigned. + const base::Value* vendor_id_value = device.FindKey(kPrefVendorIdKey); + const base::Value* product_id_value = device.FindKey(kPrefProductIdKey); + int vendor_id = vendor_id_value ? vendor_id_value->GetInt() : -1; + int product_id = product_id_value ? product_id_value->GetInt() : -1; + DCHECK(vendor_id != -1 || product_id == -1); + + auto key = std::make_pair(vendor_id, product_id); + usb_device_ids_to_url_patterns_[key].insert(parsed_url_set.begin(), + parsed_url_set.end()); + } + } +}
diff --git a/chrome/browser/usb/usb_policy_allowed_devices.h b/chrome/browser/usb/usb_policy_allowed_devices.h new file mode 100644 index 0000000..2e4b4872 --- /dev/null +++ b/chrome/browser/usb/usb_policy_allowed_devices.h
@@ -0,0 +1,66 @@ +// 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_USB_USB_POLICY_ALLOWED_DEVICES_H_ +#define CHROME_BROWSER_USB_USB_POLICY_ALLOWED_DEVICES_H_ + +#include <map> +#include <memory> +#include <set> +#include <utility> + +#include "components/content_settings/core/browser/content_settings_utils.h" +#include "components/prefs/pref_change_registrar.h" + +namespace device { +namespace mojom { +class UsbDeviceInfo; +} // namespace mojom +} // namespace device + +class GURL; +class PrefService; + +// This class is used to initialize a UsbDeviceIdsToUrlPatternsMap from the +// preference value for the WebUsbAllowDevicesForUrls policy. The map +// provides an efficient method of checking if a particular device is allowed to +// be used by the given requesting and embedding origins. Additionally, this +// class also uses |pref_change_registrar_| to observe for changes to the +// preference value so that the map can be updated accordingly. +class UsbPolicyAllowedDevices { + public: + // A map of device IDs to a set of parsed URLs stored in a + // content_settings::PatternPair. The device IDs correspond to a pair of + // |vendor_id| and |product_id|. The content_settings::PatternPair is simply + // an alias for a pair of content_settings::ContentSettingsPattern objects. + using UsbDeviceIdsToUrlPatternsMap = + std::map<std::pair<int, int>, std::set<content_settings::PatternPair>>; + + // Initializes |pref_change_registrar_| with |pref_service| and adds an + // an observer for the pref path |kManagedWebUsbAllowDevicesForUrls|. + explicit UsbPolicyAllowedDevices(PrefService* pref_service); + ~UsbPolicyAllowedDevices(); + + // Checks if |requesting_origin| (when embedded within |embedding_origin|) is + // allowed to use the device with |device_info|. + bool IsDeviceAllowed(const GURL& requesting_origin, + const GURL& embedding_origin, + const device::mojom::UsbDeviceInfo& device_info); + + const UsbDeviceIdsToUrlPatternsMap& map() const { + return usb_device_ids_to_url_patterns_; + } + + private: + // Creates or updates the |usb_device_ids_to_url_patterns_| map using the + // pref at the path |kManagedWebUsbAllowDevicesForUrls|. The existing map is + // cleared to ensure that previous pref settings are removed. + void CreateOrUpdateMap(); + + // Allow for this class to observe changes to the pref value. + PrefChangeRegistrar pref_change_registrar_; + UsbDeviceIdsToUrlPatternsMap usb_device_ids_to_url_patterns_; +}; + +#endif // CHROME_BROWSER_USB_USB_POLICY_ALLOWED_DEVICES_H_
diff --git a/chrome/browser/usb/usb_policy_allowed_devices_unittest.cc b/chrome/browser/usb/usb_policy_allowed_devices_unittest.cc new file mode 100644 index 0000000..d1ce6f19 --- /dev/null +++ b/chrome/browser/usb/usb_policy_allowed_devices_unittest.cc
@@ -0,0 +1,499 @@ +// 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/usb/usb_policy_allowed_devices.h" + +#include "base/json/json_reader.h" +#include "chrome/test/base/testing_profile.h" +#include "components/content_settings/core/browser/content_settings_utils.h" +#include "components/content_settings/core/common/pref_names.h" +#include "components/prefs/pref_service.h" +#include "content/public/test/test_browser_thread_bundle.h" +#include "device/usb/mock_usb_device.h" +#include "device/usb/mojo/type_converters.h" +#include "device/usb/public/mojom/device.mojom.h" + +namespace { + +class UsbPolicyAllowedDevicesTest : public testing::Test { + public: + UsbPolicyAllowedDevicesTest() {} + ~UsbPolicyAllowedDevicesTest() override {} + + void SetWebUsbAllowDevicesForUrlsPrefValue(const base::Value& value) { + profile_.GetPrefs()->Set(prefs::kManagedWebUsbAllowDevicesForUrls, value); + } + + protected: + Profile* profile() { return &profile_; } + + private: + content::TestBrowserThreadBundle thread_bundle_; + TestingProfile profile_; +}; + +} // namespace + +TEST_F(UsbPolicyAllowedDevicesTest, InitializeWithMissingPrefValue) { + auto usb_policy_allowed_devices = + std::make_unique<UsbPolicyAllowedDevices>(profile()->GetPrefs()); + + EXPECT_TRUE(usb_policy_allowed_devices->map().empty()); +} + +TEST_F(UsbPolicyAllowedDevicesTest, InitializeWithExistingEmptyPrefValue) { + base::Value pref_value(base::Value::Type::LIST); + + SetWebUsbAllowDevicesForUrlsPrefValue(pref_value); + + auto usb_policy_allowed_devices = + std::make_unique<UsbPolicyAllowedDevices>(profile()->GetPrefs()); + + EXPECT_TRUE(usb_policy_allowed_devices->map().empty()); +} + +namespace { + +constexpr char kPolicySetting[] = R"( + [ + { + "devices": [ + { "vendor_id": 1234, "product_id": 5678 }, + { "vendor_id": 4321 } + ], + "url_patterns": [ + "https://[*.]google.com", + "https://crbug.com" + ] + }, { + "devices": [{}], + "url_patterns": ["https://[*.]youtube.com"] + } + ])"; + +constexpr char kPolicySettingWithInvalidUrlPattern[] = R"( + [ + { + "devices": [ + { "vendor_id": 1234, "product_id": 5678 } + ], + "url_patterns": ["https://badpattern.[*]"] + } + ])"; + +constexpr char kPolicySettingWithInvalidUrlPattern2[] = R"( + [ + { + "devices": [ + { "vendor_id": 1234, "product_id": 5678 } + ], + "url_patterns": [ + "https://badpattern.[*]", + "https://[*.]google.com" + ] + } + ])"; + +} // namespace + +TEST_F(UsbPolicyAllowedDevicesTest, InitializeWithExistingPrefValue) { + std::unique_ptr<base::Value> pref_value = + base::JSONReader::Read(kPolicySetting); + + SetWebUsbAllowDevicesForUrlsPrefValue(*pref_value); + + auto usb_policy_allowed_devices = + std::make_unique<UsbPolicyAllowedDevices>(profile()->GetPrefs()); + + const UsbPolicyAllowedDevices::UsbDeviceIdsToUrlPatternsMap& map = + usb_policy_allowed_devices->map(); + EXPECT_EQ(map.size(), 3ul); + + auto device_key = std::make_pair(1234, 5678); + ASSERT_TRUE(base::ContainsKey(map, device_key)); + + const auto& first_url_patterns = map.at(device_key); + EXPECT_TRUE(base::ContainsKey( + first_url_patterns, + content_settings::ParsePatternString("https://[*.]google.com"))); + EXPECT_TRUE(base::ContainsKey( + first_url_patterns, + content_settings::ParsePatternString("https://crbug.com"))); + + device_key = std::make_pair(4321, -1); + ASSERT_TRUE(base::ContainsKey(map, device_key)); + + const auto& second_url_patterns = map.at(device_key); + EXPECT_TRUE(base::ContainsKey( + second_url_patterns, + content_settings::ParsePatternString("https://[*.]google.com"))); + EXPECT_TRUE(base::ContainsKey( + second_url_patterns, + content_settings::ParsePatternString("https://crbug.com"))); + + device_key = std::make_pair(-1, -1); + ASSERT_TRUE(base::ContainsKey(map, device_key)); + + const auto& third_url_patterns = map.at(device_key); + EXPECT_TRUE(base::ContainsKey( + third_url_patterns, + content_settings::ParsePatternString("https://[*.]youtube.com"))); +} + +// Entries without valid URL patterns are ignored. +TEST_F(UsbPolicyAllowedDevicesTest, + InitializeWithExistingPrefValueContainingInvalidUrlPattern) { + std::unique_ptr<base::Value> pref_value = + base::JSONReader::Read(kPolicySettingWithInvalidUrlPattern); + + SetWebUsbAllowDevicesForUrlsPrefValue(*pref_value); + + auto usb_policy_allowed_devices = + std::make_unique<UsbPolicyAllowedDevices>(profile()->GetPrefs()); + + const UsbPolicyAllowedDevices::UsbDeviceIdsToUrlPatternsMap& map = + usb_policy_allowed_devices->map(); + ASSERT_TRUE(map.empty()); +} + +// Invalid URL patterns are ignored on entries also containing valid patterns. +TEST_F(UsbPolicyAllowedDevicesTest, + InitializeWithExistingPrefValueContainingInvalidUrlPattern2) { + std::unique_ptr<base::Value> pref_value = + base::JSONReader::Read(kPolicySettingWithInvalidUrlPattern2); + + SetWebUsbAllowDevicesForUrlsPrefValue(*pref_value); + + auto usb_policy_allowed_devices = + std::make_unique<UsbPolicyAllowedDevices>(profile()->GetPrefs()); + + const UsbPolicyAllowedDevices::UsbDeviceIdsToUrlPatternsMap& map = + usb_policy_allowed_devices->map(); + EXPECT_EQ(map.size(), 1ul); + + auto device_key = std::make_pair(1234, 5678); + ASSERT_TRUE(base::ContainsKey(map, device_key)); + + const auto& url_patterns = map.at(device_key); + EXPECT_TRUE(base::ContainsKey( + url_patterns, + content_settings::ParsePatternString("https://[*.]google.com"))); +} + +TEST_F(UsbPolicyAllowedDevicesTest, + InitializeWithMissingPolicyThenUpdatePolicy) { + auto usb_policy_allowed_devices = + std::make_unique<UsbPolicyAllowedDevices>(profile()->GetPrefs()); + EXPECT_TRUE(usb_policy_allowed_devices->map().empty()); + + // Ensure that the allowed devices can be dynamically updated. + std::unique_ptr<base::Value> pref_value = + base::JSONReader::Read(kPolicySetting); + + SetWebUsbAllowDevicesForUrlsPrefValue(*pref_value); + + const UsbPolicyAllowedDevices::UsbDeviceIdsToUrlPatternsMap& map = + usb_policy_allowed_devices->map(); + EXPECT_EQ(map.size(), 3ul); + + auto device_key = std::make_pair(1234, 5678); + ASSERT_TRUE(base::ContainsKey(map, device_key)); + + const auto& first_url_patterns = map.at(device_key); + EXPECT_TRUE(base::ContainsKey( + first_url_patterns, + content_settings::ParsePatternString("https://[*.]google.com"))); + EXPECT_TRUE(base::ContainsKey( + first_url_patterns, + content_settings::ParsePatternString("https://crbug.com"))); + + device_key = std::make_pair(4321, -1); + ASSERT_TRUE(base::ContainsKey(map, device_key)); + + const auto& second_url_patterns = map.at(device_key); + EXPECT_TRUE(base::ContainsKey( + second_url_patterns, + content_settings::ParsePatternString("https://[*.]google.com"))); + EXPECT_TRUE(base::ContainsKey( + second_url_patterns, + content_settings::ParsePatternString("https://crbug.com"))); + + device_key = std::make_pair(-1, -1); + ASSERT_TRUE(base::ContainsKey(map, device_key)); + + const auto& third_url_patterns = map.at(device_key); + EXPECT_TRUE(base::ContainsKey( + third_url_patterns, + content_settings::ParsePatternString("https://[*.]youtube.com"))); +} + +TEST_F(UsbPolicyAllowedDevicesTest, + InitializeWithExistingPolicyThenRemovePolicy) { + std::unique_ptr<base::Value> pref_value = + base::JSONReader::Read(kPolicySetting); + + SetWebUsbAllowDevicesForUrlsPrefValue(*pref_value); + + auto usb_policy_allowed_devices = + std::make_unique<UsbPolicyAllowedDevices>(profile()->GetPrefs()); + + const UsbPolicyAllowedDevices::UsbDeviceIdsToUrlPatternsMap& map = + usb_policy_allowed_devices->map(); + ASSERT_EQ(map.size(), 3ul); + + auto device_key = std::make_pair(1234, 5678); + ASSERT_TRUE(base::ContainsKey(map, device_key)); + + const auto& first_url_patterns = map.at(device_key); + EXPECT_TRUE(base::ContainsKey( + first_url_patterns, + content_settings::ParsePatternString("https://[*.]google.com"))); + EXPECT_TRUE(base::ContainsKey( + first_url_patterns, + content_settings::ParsePatternString("https://crbug.com"))); + + device_key = std::make_pair(4321, -1); + ASSERT_TRUE(base::ContainsKey(map, device_key)); + + const auto& second_url_patterns = map.at(device_key); + EXPECT_TRUE(base::ContainsKey( + second_url_patterns, + content_settings::ParsePatternString("https://[*.]google.com"))); + EXPECT_TRUE(base::ContainsKey( + second_url_patterns, + content_settings::ParsePatternString("https://crbug.com"))); + + device_key = std::make_pair(-1, -1); + ASSERT_TRUE(base::ContainsKey(map, device_key)); + + const auto& third_url_patterns = map.at(device_key); + EXPECT_TRUE(base::ContainsKey( + third_url_patterns, + content_settings::ParsePatternString("https://[*.]youtube.com"))); + + // Ensure that the allowed devices can be removed dynamically. + pref_value.reset(new base::Value(base::Value::Type::LIST)); + SetWebUsbAllowDevicesForUrlsPrefValue(*pref_value); + + EXPECT_TRUE(usb_policy_allowed_devices->map().empty()); +} + +namespace { + +constexpr char kPolicySettingWithEntriesContainingDuplicateDevices[] = R"( + [ + { + "devices": [{ "vendor_id": 1234, "product_id": 5678 }], + "url_patterns": [ + "https://[*.]google.com", + "https://crbug.com" + ] + }, { + "devices": [{ "vendor_id": 1234, "product_id": 5678 }], + "url_patterns": ["https://[*.]youtube.com"] + } + ])"; + +} // namespace + +TEST_F(UsbPolicyAllowedDevicesTest, + InitializeWithExistingPrefValueContainingDuplicateDevices) { + std::unique_ptr<base::Value> pref_value = base::JSONReader::Read( + kPolicySettingWithEntriesContainingDuplicateDevices); + + SetWebUsbAllowDevicesForUrlsPrefValue(*pref_value); + + auto usb_policy_allowed_devices = + std::make_unique<UsbPolicyAllowedDevices>(profile()->GetPrefs()); + + const UsbPolicyAllowedDevices::UsbDeviceIdsToUrlPatternsMap& map = + usb_policy_allowed_devices->map(); + ASSERT_EQ(map.size(), 1ul); + + auto device_key = std::make_pair(1234, 5678); + ASSERT_TRUE(base::ContainsKey(map, device_key)); + + // Ensure a device has all of the URL patterns allowed to access it. + const auto& url_patterns = map.at(device_key); + EXPECT_TRUE(base::ContainsKey( + url_patterns, + content_settings::ParsePatternString("https://[*.]google.com"))); + EXPECT_TRUE(base::ContainsKey( + url_patterns, content_settings::ParsePatternString("https://crbug.com"))); + EXPECT_TRUE(base::ContainsKey( + url_patterns, + content_settings::ParsePatternString("https://[*.]youtube.com"))); +} + +namespace { + +constexpr char kPolicySettingWithEntriesMatchingMultipleDevices[] = R"( + [ + { + "devices": [{ "vendor_id": 1234, "product_id": 5678 }], + "url_patterns": ["https://[*.]google.com"] + }, { + "devices": [{ "vendor_id": 1234 }], + "url_patterns": ["https://[*.]youtube.com"] + }, { + "devices": [{}], + "url_patterns": ["https://[*.]chromium.org"] + } + ])"; + +} // namespace + +TEST_F(UsbPolicyAllowedDevicesTest, IsDeviceAllowed) { + std::unique_ptr<base::Value> pref_value = + base::JSONReader::Read(kPolicySettingWithEntriesMatchingMultipleDevices); + + SetWebUsbAllowDevicesForUrlsPrefValue(*pref_value); + + auto usb_policy_allowed_devices = + std::make_unique<UsbPolicyAllowedDevices>(profile()->GetPrefs()); + + const GURL origins_for_specific_device[] = {GURL("https://google.com"), + GURL("https://mail.google.com")}; + const GURL origins_for_specific_vendor_devices[] = { + GURL("https://youtube.com"), GURL("https://music.youtube.com")}; + const GURL origins_for_any_device[] = {GURL("https://chromium.org"), + GURL("https://bugs.chromium.org")}; + + scoped_refptr<device::UsbDevice> specific_device = + base::MakeRefCounted<device::MockUsbDevice>(1234, 5678, "Google", "Gizmo", + "123ABC"); + scoped_refptr<device::UsbDevice> vendor_device = + base::MakeRefCounted<device::MockUsbDevice>(1234, 8765, "Google", "Gizmo", + "ABC123"); + scoped_refptr<device::UsbDevice> unrelated_device = + base::MakeRefCounted<device::MockUsbDevice>(4321, 8765, "Chrome", "Gizmo", + "987ZYX"); + + auto specific_device_info = + device::mojom::UsbDeviceInfo::From(*specific_device); + auto vendor_device_info = device::mojom::UsbDeviceInfo::From(*vendor_device); + auto unrelated_device_info = + device::mojom::UsbDeviceInfo::From(*unrelated_device); + + // Check the URLs for the specific device. + for (const GURL& requesting_origin : origins_for_specific_device) { + for (const GURL& embedding_origin : origins_for_specific_device) { + EXPECT_TRUE(usb_policy_allowed_devices->IsDeviceAllowed( + requesting_origin, embedding_origin, *specific_device_info)); + } + } + + // Check the URLs for vendor devices. + for (const GURL& requesting_origin : origins_for_specific_vendor_devices) { + for (const GURL& embedding_origin : origins_for_specific_vendor_devices) { + EXPECT_TRUE(usb_policy_allowed_devices->IsDeviceAllowed( + requesting_origin, embedding_origin, *specific_device_info)); + EXPECT_TRUE(usb_policy_allowed_devices->IsDeviceAllowed( + requesting_origin, embedding_origin, *vendor_device_info)); + } + } + + // Check the URLs for any device. + for (const GURL& requesting_origin : origins_for_any_device) { + for (const GURL& embedding_origin : origins_for_any_device) { + EXPECT_TRUE(usb_policy_allowed_devices->IsDeviceAllowed( + requesting_origin, embedding_origin, *specific_device_info)); + EXPECT_TRUE(usb_policy_allowed_devices->IsDeviceAllowed( + requesting_origin, embedding_origin, *vendor_device_info)); + EXPECT_TRUE(usb_policy_allowed_devices->IsDeviceAllowed( + requesting_origin, embedding_origin, *unrelated_device_info)); + } + } +} + +TEST_F(UsbPolicyAllowedDevicesTest, IsDeviceAllowedForUrlPatternsNotInPref) { + std::unique_ptr<base::Value> pref_value = + base::JSONReader::Read(kPolicySettingWithEntriesMatchingMultipleDevices); + + SetWebUsbAllowDevicesForUrlsPrefValue(*pref_value); + + auto usb_policy_allowed_devices = + std::make_unique<UsbPolicyAllowedDevices>(profile()->GetPrefs()); + + const GURL origins[] = {GURL("https://evil.com"), + GURL("https://very.evil.com"), + GURL("https://chromium.deceptive.org")}; + + scoped_refptr<device::UsbDevice> device = + base::MakeRefCounted<device::MockUsbDevice>(1234, 5678, "Google", "Gizmo", + "123ABC"); + auto device_info = device::mojom::UsbDeviceInfo::From(*device); + for (const GURL& requesting_origin : origins) { + for (const GURL& embedding_origin : origins) { + EXPECT_FALSE(usb_policy_allowed_devices->IsDeviceAllowed( + requesting_origin, embedding_origin, *device_info)); + } + } +} + +TEST_F(UsbPolicyAllowedDevicesTest, IsDeviceAllowedForDeviceNotInPref) { + std::unique_ptr<base::Value> pref_value = + base::JSONReader::Read(kPolicySettingWithEntriesMatchingMultipleDevices); + + SetWebUsbAllowDevicesForUrlsPrefValue(*pref_value); + + auto usb_policy_allowed_devices = + std::make_unique<UsbPolicyAllowedDevices>(profile()->GetPrefs()); + + const GURL origins[] = { + GURL("https://google.com"), GURL("https://mail.google.com"), + GURL("https://youtube.com"), GURL("https://music.youtube.com")}; + + scoped_refptr<device::UsbDevice> device = + base::MakeRefCounted<device::MockUsbDevice>(4321, 8765, "Google", "Gizmo", + "123ABC"); + auto device_info = device::mojom::UsbDeviceInfo::From(*device); + for (const GURL& requesting_origin : origins) { + for (const GURL& embedding_origin : origins) { + EXPECT_FALSE(usb_policy_allowed_devices->IsDeviceAllowed( + requesting_origin, embedding_origin, *device_info)); + } + } +} + +namespace { + +constexpr char kPolicySettingWithUrlPatternContainingEmbeddingOrigin[] = R"( + [ + { + "devices": [{ "vendor_id": 1234, "product_id": 5678 }], + "url_patterns": [ + "https://[*.]requesting.com,https://[*.]embedding.com" + ] + } + ])"; + +} // namespace + +TEST_F(UsbPolicyAllowedDevicesTest, + IsDeviceAllowedForUrlPatternContainingEmbeddingOrigin) { + std::unique_ptr<base::Value> pref_value = base::JSONReader::Read( + kPolicySettingWithUrlPatternContainingEmbeddingOrigin); + + SetWebUsbAllowDevicesForUrlsPrefValue(*pref_value); + + auto usb_policy_allowed_devices = + std::make_unique<UsbPolicyAllowedDevices>(profile()->GetPrefs()); + + const GURL requesting_origin("https://requesting.com"); + const GURL embedding_origin("https://embedding.com"); + + scoped_refptr<device::UsbDevice> device = + base::MakeRefCounted<device::MockUsbDevice>(1234, 5678, "Google", "Gizmo", + "123ABC"); + auto device_info = device::mojom::UsbDeviceInfo::From(*device); + EXPECT_TRUE(usb_policy_allowed_devices->IsDeviceAllowed( + requesting_origin, embedding_origin, *device_info)); + EXPECT_FALSE(usb_policy_allowed_devices->IsDeviceAllowed( + embedding_origin, requesting_origin, *device_info)); + EXPECT_FALSE(usb_policy_allowed_devices->IsDeviceAllowed( + requesting_origin, requesting_origin, *device_info)); + EXPECT_FALSE(usb_policy_allowed_devices->IsDeviceAllowed( + embedding_origin, embedding_origin, *device_info)); +}
diff --git a/chrome/common/trace_event_args_whitelist.cc b/chrome/common/trace_event_args_whitelist.cc index 09c21825..83a7449 100644 --- a/chrome/common/trace_event_args_whitelist.cc +++ b/chrome/common/trace_event_args_whitelist.cc
@@ -34,6 +34,7 @@ {"ipc", "GpuChannelHost::Send", nullptr}, {"ipc", "SyncChannel::Send", nullptr}, {"latencyInfo", "*", kInputLatencyAllowedArgs}, + {"shutdown", "*", nullptr}, {"task_scheduler", "*", nullptr}, {"toplevel", "*", nullptr}, {TRACE_DISABLED_BY_DEFAULT("cpu_profiler"), "StackCpuSampling", nullptr},
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn index 705f682..e446fd6 100644 --- a/chrome/test/BUILD.gn +++ b/chrome/test/BUILD.gn
@@ -3203,6 +3203,7 @@ "../browser/usb/usb_blocklist_unittest.cc", "../browser/usb/usb_chooser_context_unittest.cc", "../browser/usb/usb_chooser_controller_unittest.cc", + "../browser/usb/usb_policy_allowed_devices_unittest.cc", "../browser/usb/web_usb_detector_unittest.cc", "../browser/usb/web_usb_service_impl_unittest.cc", "../browser/webauthn/authenticator_request_dialog_model_unittest.cc",
diff --git a/chrome/test/base/chrome_render_view_host_test_harness.cc b/chrome/test/base/chrome_render_view_host_test_harness.cc index b9de82b..a2c4cc05a 100644 --- a/chrome/test/base/chrome_render_view_host_test_harness.cc +++ b/chrome/test/base/chrome_render_view_host_test_harness.cc
@@ -6,6 +6,7 @@ #include <utility> +#include "base/bind.h" #include "build/build_config.h" #include "chrome/browser/browser_process.h" #include "chrome/browser/signin/account_tracker_service_factory.h" @@ -75,6 +76,6 @@ ChromeRenderViewHostTestHarness::CreateBrowserContext() { TestingProfile::Builder builder; builder.AddTestingFactory(SigninManagerFactory::GetInstance(), - BuildSigninManagerFake); + base::BindRepeating(&BuildSigninManagerFake)); return builder.Build().release(); }
diff --git a/chrome/test/base/testing_profile.cc b/chrome/test/base/testing_profile.cc index 2ffa1ca..83974b2 100644 --- a/chrome/test/base/testing_profile.cc +++ b/chrome/test/base/testing_profile.cc
@@ -459,10 +459,10 @@ this, std::move(extension_prefs)); extensions::ExtensionSystemFactory::GetInstance()->SetTestingFactory( - this, extensions::TestExtensionSystem::Build); + this, base::BindRepeating(&extensions::TestExtensionSystem::Build)); - extensions::EventRouterFactory::GetInstance()->SetTestingFactory(this, - nullptr); + extensions::EventRouterFactory::GetInstance()->SetTestingFactory( + this, BrowserContextKeyedServiceFactory::TestingFactory()); #endif // Prefs for incognito profiles are set in CreateIncognitoPrefService() by @@ -549,18 +549,20 @@ history::HistoryService* history_service = static_cast<history::HistoryService*>( HistoryServiceFactory::GetInstance()->SetTestingFactoryAndUse( - this, BuildHistoryService)); + this, base::BindRepeating(&BuildHistoryService))); if (!history_service->Init( no_db, history::HistoryDatabaseParamsForPath(GetPath()))) { - HistoryServiceFactory::GetInstance()->SetTestingFactory(this, nullptr); + HistoryServiceFactory::GetInstance()->SetTestingFactory( + this, BrowserContextKeyedServiceFactory::TestingFactory()); return false; } // Some tests expect that CreateHistoryService() will also make the // InMemoryURLIndex available. InMemoryURLIndexFactory::GetInstance()->SetTestingFactory( - this, BuildInMemoryURLIndex); + this, base::BindRepeating(&BuildInMemoryURLIndex)); // Disable WebHistoryService by default, since it makes network requests. - WebHistoryServiceFactory::GetInstance()->SetTestingFactory(this, nullptr); + WebHistoryServiceFactory::GetInstance()->SetTestingFactory( + this, BrowserContextKeyedServiceFactory::TestingFactory()); return true; } @@ -571,18 +573,18 @@ } #if BUILDFLAG(ENABLE_OFFLINE_PAGES) offline_pages::OfflinePageModelFactory::GetInstance()->SetTestingFactory( - this, BuildOfflinePageModel); + this, base::BindRepeating(&BuildOfflinePageModel)); #endif ManagedBookmarkServiceFactory::GetInstance()->SetTestingFactory( this, ManagedBookmarkServiceFactory::GetDefaultFactory()); // This creates the BookmarkModel. ignore_result(BookmarkModelFactory::GetInstance()->SetTestingFactoryAndUse( - this, BuildBookmarkModel)); + this, base::BindRepeating(&BuildBookmarkModel))); } void TestingProfile::CreateWebDataService() { WebDataServiceFactory::GetInstance()->SetTestingFactory( - this, BuildWebDataService); + this, base::BindRepeating(&BuildWebDataService)); } void TestingProfile::BlockUntilHistoryIndexIsRefreshed() {
diff --git a/chrome/test/base/testing_profile_manager.cc b/chrome/test/base/testing_profile_manager.cc index 43f0f0ff..df57dbc 100644 --- a/chrome/test/base/testing_profile_manager.cc +++ b/chrome/test/base/testing_profile_manager.cc
@@ -7,6 +7,7 @@ #include <stddef.h> #include <utility> +#include "base/bind.h" #include "base/memory/ref_counted.h" #include "base/strings/utf_string_conversions.h" #include "build/build_config.h"
diff --git a/chrome/test/chromedriver/capabilities.cc b/chrome/test/chromedriver/capabilities.cc index 450c5560..ea6bdf2 100644 --- a/chrome/test/chromedriver/capabilities.cc +++ b/chrome/test/chromedriver/capabilities.cc
@@ -35,7 +35,7 @@ const base::Value& option, Capabilities* capabilities) { if (!option.GetAsBoolean(to_set)) - return Status(kUnknownError, "must be a boolean"); + return Status(kInvalidArgument, "must be a boolean"); return Status(kOk); } @@ -44,9 +44,9 @@ Capabilities* capabilities) { std::string str; if (!option.GetAsString(&str)) - return Status(kUnknownError, "must be a string"); + return Status(kInvalidArgument, "must be a string"); if (str.empty()) - return Status(kUnknownError, "cannot be empty"); + return Status(kInvalidArgument, "cannot be empty"); *to_set = str; return Status(kOk); } @@ -56,9 +56,9 @@ Capabilities* capabilities) { int parsed_int = 0; if (!option.GetAsInteger(&parsed_int)) - return Status(kUnknownError, "must be an integer"); + return Status(kInvalidArgument, "must be an integer"); if (parsed_int <= 0) - return Status(kUnknownError, "must be positive"); + return Status(kInvalidArgument, "must be positive"); *to_set = parsed_int; return Status(kOk); } @@ -68,9 +68,9 @@ Capabilities* capabilities) { int milliseconds = 0; if (!option.GetAsInteger(&milliseconds)) - return Status(kUnknownError, "must be an integer"); + return Status(kInvalidArgument, "must be an integer"); if (milliseconds < 0) - return Status(kUnknownError, "must be positive or zero"); + return Status(kInvalidArgument, "must be positive or zero"); *to_set = base::TimeDelta::FromMilliseconds(milliseconds); return Status(kOk); } @@ -80,7 +80,7 @@ Capabilities* capabilities) { base::FilePath::StringType str; if (!option.GetAsString(&str)) - return Status(kUnknownError, "must be a string"); + return Status(kInvalidArgument, "must be a string"); *to_set = base::FilePath(str); return Status(kOk); } @@ -90,7 +90,7 @@ Capabilities* capabilities) { const base::DictionaryValue* dict = NULL; if (!option.GetAsDictionary(&dict)) - return Status(kUnknownError, "must be a dictionary"); + return Status(kInvalidArgument, "must be a dictionary"); to_set->reset(dict->DeepCopy()); return Status(kOk); } @@ -109,7 +109,7 @@ Status ParseLogPath(const base::Value& option, Capabilities* capabilities) { if (!option.GetAsString(&capabilities->log_path)) - return Status(kUnknownError, "must be a string"); + return Status(kInvalidArgument, "must be a string"); return Status(kOk); } @@ -119,9 +119,8 @@ Status status = FindMobileDevice(device_name, &device); if (status.IsError()) { - return Status(kUnknownError, - "'" + device_name + "' must be a valid device", - status); + return Status(kInvalidArgument, + "'" + device_name + "' must be a valid device", status); } capabilities->device_metrics = std::move(device->device_metrics); @@ -136,16 +135,16 @@ Capabilities* capabilities) { const base::DictionaryValue* mobile_emulation; if (!option.GetAsDictionary(&mobile_emulation)) - return Status(kUnknownError, "'mobileEmulation' must be a dictionary"); + return Status(kInvalidArgument, "'mobileEmulation' must be a dictionary"); if (mobile_emulation->HasKey("deviceName")) { // Cannot use any other options with deviceName. if (mobile_emulation->size() > 1) - return Status(kUnknownError, "'deviceName' must be used alone"); + return Status(kInvalidArgument, "'deviceName' must be used alone"); std::string device_name; if (!mobile_emulation->GetString("deviceName", &device_name)) - return Status(kUnknownError, "'deviceName' must be a string"); + return Status(kInvalidArgument, "'deviceName' must be a string"); return ParseDeviceName(device_name, capabilities); } @@ -153,7 +152,7 @@ if (mobile_emulation->HasKey("deviceMetrics")) { const base::DictionaryValue* metrics; if (!mobile_emulation->GetDictionary("deviceMetrics", &metrics)) - return Status(kUnknownError, "'deviceMetrics' must be a dictionary"); + return Status(kInvalidArgument, "'deviceMetrics' must be a dictionary"); int width = 0; int height = 0; @@ -162,20 +161,20 @@ bool mobile = true; if (metrics->HasKey("width") && !metrics->GetInteger("width", &width)) - return Status(kUnknownError, "'width' must be an integer"); + return Status(kInvalidArgument, "'width' must be an integer"); if (metrics->HasKey("height") && !metrics->GetInteger("height", &height)) - return Status(kUnknownError, "'height' must be an integer"); + return Status(kInvalidArgument, "'height' must be an integer"); if (metrics->HasKey("pixelRatio") && !metrics->GetDouble("pixelRatio", &device_scale_factor)) - return Status(kUnknownError, "'pixelRatio' must be a double"); + return Status(kInvalidArgument, "'pixelRatio' must be a double"); if (metrics->HasKey("touch") && !metrics->GetBoolean("touch", &touch)) - return Status(kUnknownError, "'touch' must be a boolean"); + return Status(kInvalidArgument, "'touch' must be a boolean"); if (metrics->HasKey("mobile") && !metrics->GetBoolean("mobile", &mobile)) - return Status(kUnknownError, "'mobile' must be a boolean"); + return Status(kInvalidArgument, "'mobile' must be a boolean"); DeviceMetrics* device_metrics = new DeviceMetrics(width, height, device_scale_factor, touch, mobile); @@ -186,7 +185,7 @@ if (mobile_emulation->HasKey("userAgent")) { std::string user_agent; if (!mobile_emulation->GetString("userAgent", &user_agent)) - return Status(kUnknownError, "'userAgent' must be a string"); + return Status(kInvalidArgument, "'userAgent' must be a string"); capabilities->switches.SetSwitch("user-agent", user_agent); } @@ -247,11 +246,11 @@ Capabilities* capabilities) { const base::ListValue* switches_list = NULL; if (!option.GetAsList(&switches_list)) - return Status(kUnknownError, "must be a list"); + return Status(kInvalidArgument, "must be a list"); for (size_t i = 0; i < switches_list->GetSize(); ++i) { std::string arg_string; if (!switches_list->GetString(i, &arg_string)) - return Status(kUnknownError, "each argument must be a string"); + return Status(kInvalidArgument, "each argument must be a string"); capabilities->switches.SetUnparsedSwitch(arg_string); } return Status(kOk); @@ -260,11 +259,11 @@ Status ParseExtensions(const base::Value& option, Capabilities* capabilities) { const base::ListValue* extensions = NULL; if (!option.GetAsList(&extensions)) - return Status(kUnknownError, "must be a list"); + return Status(kInvalidArgument, "must be a list"); for (size_t i = 0; i < extensions->GetSize(); ++i) { std::string extension; if (!extensions->GetString(i, &extension)) { - return Status(kUnknownError, + return Status(kInvalidArgument, "each extension must be a base64 encoded string"); } capabilities->extensions.push_back(extension); @@ -371,11 +370,11 @@ Capabilities* capabilities) { const base::ListValue* switches = NULL; if (!option.GetAsList(&switches)) - return Status(kUnknownError, "must be a list"); + return Status(kInvalidArgument, "must be a list"); for (size_t i = 0; i < switches->GetSize(); ++i) { std::string switch_name; if (!switches->GetString(i, &switch_name)) { - return Status(kUnknownError, + return Status(kInvalidArgument, "each switch to be removed must be a string"); } capabilities->exclude_switches.insert(switch_name); @@ -387,17 +386,17 @@ Capabilities* capabilities) { std::string server_addr; if (!option.GetAsString(&server_addr)) - return Status(kUnknownError, "must be 'host:port'"); + return Status(kInvalidArgument, "must be 'host:port'"); std::vector<std::string> values = base::SplitString( server_addr, ":", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL); if (values.size() != 2) - return Status(kUnknownError, "must be 'host:port'"); + return Status(kInvalidArgument, "must be 'host:port'"); int port = 0; base::StringToInt(values[1], &port); if (port <= 0) - return Status(kUnknownError, "port must be > 0"); + return Status(kInvalidArgument, "port must be > 0"); capabilities->debugger_address = NetAddress(values[0], port); return Status(kOk); @@ -407,7 +406,7 @@ Capabilities* capabilities) { const base::DictionaryValue* logging_prefs = NULL; if (!option.GetAsDictionary(&logging_prefs)) - return Status(kUnknownError, "must be a dictionary"); + return Status(kInvalidArgument, "must be a dictionary"); for (base::DictionaryValue::Iterator pref(*logging_prefs); !pref.IsAtEnd(); pref.Advance()) { @@ -416,7 +415,8 @@ std::string level_name; if (!pref.value().GetAsString(&level_name) || !WebDriverLog::NameToLevel(level_name, &level)) { - return Status(kUnknownError, "invalid log level for '" + type + "' log"); + return Status(kInvalidArgument, + "invalid log level for '" + type + "' log"); } capabilities->logging_prefs.insert(std::make_pair(type, level)); } @@ -429,7 +429,7 @@ Capabilities* capabilities) { bool desired_value; if (!option.GetAsBoolean(&desired_value)) - return Status(kUnknownError, "must be a boolean"); + return Status(kInvalidArgument, "must be a boolean"); if (desired_value) *to_set = PerfLoggingPrefs::InspectorDomainStatus::kExplicitlyEnabled; else @@ -441,7 +441,7 @@ Capabilities* capabilities) { const base::DictionaryValue* perf_logging_prefs = NULL; if (!option.GetAsDictionary(&perf_logging_prefs)) - return Status(kUnknownError, "must be a dictionary"); + return Status(kInvalidArgument, "must be a dictionary"); std::map<std::string, Parser> parser_map; parser_map["bufferUsageReportingInterval"] = base::Bind(&ParseInterval, @@ -456,11 +456,11 @@ for (base::DictionaryValue::Iterator it(*perf_logging_prefs); !it.IsAtEnd(); it.Advance()) { if (parser_map.find(it.key()) == parser_map.end()) - return Status(kUnknownError, "unrecognized performance logging " - "option: " + it.key()); + return Status(kInvalidArgument, + "unrecognized performance logging option: " + it.key()); Status status = parser_map[it.key()].Run(it.value(), capabilities); if (status.IsError()) - return Status(kUnknownError, "cannot parse " + it.key(), status); + return Status(kInvalidArgument, "cannot parse " + it.key(), status); } return Status(kOk); } @@ -469,9 +469,9 @@ Capabilities* capabilities) { const base::ListValue* devtools_events_logging_prefs = nullptr; if (!option.GetAsList(&devtools_events_logging_prefs)) - return Status(kUnknownError, "must be a list"); + return Status(kInvalidArgument, "must be a list"); if (devtools_events_logging_prefs->empty()) - return Status(kUnknownError, "list must contain values"); + return Status(kInvalidArgument, "list must contain values"); capabilities->devtools_events_logging_prefs.reset( devtools_events_logging_prefs->DeepCopy()); return Status(kOk); @@ -480,12 +480,12 @@ Status ParseWindowTypes(const base::Value& option, Capabilities* capabilities) { const base::ListValue* window_types = NULL; if (!option.GetAsList(&window_types)) - return Status(kUnknownError, "must be a list"); + return Status(kInvalidArgument, "must be a list"); std::set<WebViewInfo::Type> window_types_tmp; for (size_t i = 0; i < window_types->GetSize(); ++i) { std::string window_type; if (!window_types->GetString(i, &window_type)) { - return Status(kUnknownError, "each window type must be a string"); + return Status(kInvalidArgument, "each window type must be a string"); } WebViewInfo::Type type; Status status = ParseType(window_type, &type); @@ -502,7 +502,7 @@ Capabilities* capabilities) { const base::DictionaryValue* chrome_options = NULL; if (!capability.GetAsDictionary(&chrome_options)) - return Status(kUnknownError, "must be a dictionary"); + return Status(kInvalidArgument, "must be a dictionary"); bool is_android = chrome_options->HasKey("androidPackage"); bool is_remote = chrome_options->HasKey("debuggerAddress"); @@ -567,12 +567,12 @@ for (base::DictionaryValue::Iterator it(*chrome_options); !it.IsAtEnd(); it.Advance()) { if (parser_map.find(it.key()) == parser_map.end()) { - return Status(kUnknownError, + return Status(kInvalidArgument, "unrecognized chrome option: " + it.key()); } Status status = parser_map[it.key()].Run(it.value(), capabilities); if (status.IsError()) - return Status(kUnknownError, "cannot parse " + it.key(), status); + return Status(kInvalidArgument, "cannot parse " + it.key(), status); } return Status(kOk); } @@ -758,8 +758,8 @@ if (desired_caps.Get(it->first, &capability)) { Status status = it->second.Run(*capability, this); if (status.IsError()) { - return Status( - kUnknownError, "cannot parse capability: " + it->first, status); + return Status(kInvalidArgument, "cannot parse capability: " + it->first, + status); } } } @@ -771,7 +771,8 @@ if ((desired_caps.GetDictionary("goog:chromeOptions", &chrome_options) || desired_caps.GetDictionary("chromeOptions", &chrome_options)) && chrome_options->HasKey("perfLoggingPrefs")) { - return Status(kUnknownError, "perfLoggingPrefs specified, " + return Status(kInvalidArgument, + "perfLoggingPrefs specified, " "but performance logging was not enabled"); } } @@ -783,7 +784,8 @@ if ((desired_caps.GetDictionary("goog:chromeOptions", &chrome_options) || desired_caps.GetDictionary("chromeOptions", &chrome_options)) && chrome_options->HasKey("devToolsEventsToLog")) { - return Status(kUnknownError, "devToolsEventsToLog specified, " + return Status(kInvalidArgument, + "devToolsEventsToLog specified, " "but devtools events logging was not enabled"); } }
diff --git a/chrome/test/chromedriver/session_commands.cc b/chrome/test/chromedriver/session_commands.cc index caf3179..25c0f2fe 100644 --- a/chrome/test/chromedriver/session_commands.cc +++ b/chrome/test/chromedriver/session_commands.cc
@@ -13,6 +13,7 @@ #include "base/logging.h" // For CHECK macros. #include "base/memory/ref_counted.h" #include "base/strings/string_util.h" +#include "base/strings/stringprintf.h" #include "base/synchronization/lock.h" #include "base/synchronization/waitable_event.h" #include "base/threading/thread_task_runner_handle.h" @@ -217,39 +218,14 @@ session->driver_log.reset( new WebDriverLog(WebDriverLog::kDriverType, Log::kAll)); const base::DictionaryValue* desired_caps; - const base::DictionaryValue empty_dict; base::DictionaryValue merged_caps; session->w3c_compliant = GetW3CSetting(params); if (session->w3c_compliant) { - if (!params.GetDictionary("capabilities.alwaysMatch", &desired_caps)) - desired_caps = &empty_dict; - - // TODO(johnchen): Handle capabilities.firstMatch. Currently, we're just - // merging, not validating or matching as per the spec. - const base::ListValue* first_match_list; - std::unique_ptr<base::ListValue> tmp_list; - if (!(params.GetList("capabilities.firstMatch", &first_match_list))) { - // if no firstMatch, make first_match_list a list with an empty dictionary - tmp_list = std::unique_ptr<base::ListValue>(new base::ListValue()); - std::unique_ptr<base::DictionaryValue> inner(new base::DictionaryValue()); - tmp_list->Append(std::move(inner)); - first_match_list = tmp_list.get(); - } - for (size_t i = 0; i < first_match_list->GetSize(); ++i) { - const base::DictionaryValue* first_match; - if (!first_match_list->GetDictionary(i, &first_match)) { - continue; - } - if (!MergeCapabilities(desired_caps, first_match, &merged_caps)) { - return Status(kSessionNotCreated, "Invalid capabilities"); - } - if (MatchCapabilities(&merged_caps)) { - // If a match is found, we want to use these matched setcapabilities. - desired_caps = &merged_caps; - break; - } - } + Status status = ProcessCapabilities(params, &merged_caps); + if (status.IsError()) + return status; + desired_caps = &merged_caps; } else if (!params.GetDictionary("desiredCapabilities", &desired_caps)) { return Status(kSessionNotCreated, "Missing or invalid capabilities"); @@ -347,9 +323,9 @@ return true; } -bool MatchCapabilities(base::DictionaryValue* capabilities) { - // attempt to match the capabilities requested to the actual capabilities - // reject if they don't match +bool MatchCapabilities(const base::DictionaryValue* capabilities) { + // Attempt to match the capabilities requested to the actual capabilities. + // Reject if they don't match. if (capabilities->HasKey("browserName")) { std::string name; capabilities->GetString("browserName", &name); @@ -360,6 +336,106 @@ return true; } +// Implementation of "process capabilities", as defined in W3C spec at +// https://www.w3.org/TR/webdriver/#processing-capabilities. Step numbers in +// the comments correspond to the step numbers in the spec. +Status ProcessCapabilities(const base::DictionaryValue& params, + base::DictionaryValue* result_capabilities) { + // 1. Get the property "capabilities" from parameters. + const base::DictionaryValue* capabilities_request; + if (!params.GetDictionary("capabilities", &capabilities_request)) + return Status(kInvalidArgument, "'capabilities' must be a JSON object"); + + // 2. Get the property "alwaysMatch" from capabilities request. + const base::DictionaryValue empty_object; + const base::DictionaryValue* required_capabilities; + const base::Value* required_capabilities_value = + capabilities_request->FindKey("alwaysMatch"); + if (required_capabilities_value == nullptr) { + required_capabilities = &empty_object; + } else if (required_capabilities_value->GetAsDictionary( + &required_capabilities)) { + Capabilities cap; + Status status = cap.Parse(*required_capabilities); + if (status.IsError()) + return status; + } else { + return Status(kInvalidArgument, "'alwaysMatch' must be a JSON object"); + } + + // 3. Get the property "firstMatch" from capabilities request. + base::ListValue default_list; + const base::ListValue* all_first_match_capabilities; + const base::Value* all_first_match_capabilities_value = + capabilities_request->FindKey("firstMatch"); + if (all_first_match_capabilities_value == nullptr) { + default_list.Append(std::make_unique<base::DictionaryValue>()); + all_first_match_capabilities = &default_list; + } else if (all_first_match_capabilities_value->GetAsList( + &all_first_match_capabilities)) { + if (all_first_match_capabilities->GetSize() < 1) + return Status(kInvalidArgument, + "'firstMatch' must contain at least one entry"); + } else { + return Status(kInvalidArgument, "'firstMatch' must be a JSON list"); + } + + // 4. Let validated first match capabilities be an empty JSON List. + std::vector<const base::DictionaryValue*> validated_first_match_capabilities; + + // 5. Validate all first match capabilities. + for (size_t i = 0; i < all_first_match_capabilities->GetSize(); ++i) { + const base::DictionaryValue* first_match; + if (!all_first_match_capabilities->GetDictionary(i, &first_match)) { + return Status(kInvalidArgument, + base::StringPrintf( + "entry %zu of 'firstMatch' must be a JSON object", i)); + } + Capabilities cap; + Status status = cap.Parse(*first_match); + if (status.IsError()) + return Status( + kInvalidArgument, + base::StringPrintf("entry %zu of 'firstMatch' is invalid", i), + status); + validated_first_match_capabilities.push_back(first_match); + } + + // 6. Let merged capabilities be an empty List. + std::vector<base::DictionaryValue> merged_capabilities; + + // 7. Merge capabilities. + for (size_t i = 0; i < validated_first_match_capabilities.size(); ++i) { + const base::DictionaryValue* first_match_capabilities = + validated_first_match_capabilities[i]; + base::DictionaryValue merged; + if (!MergeCapabilities(required_capabilities, first_match_capabilities, + &merged)) { + return Status( + kInvalidArgument, + base::StringPrintf( + "unable to merge 'alwaysMatch' with entry %zu of 'firstMatch'", + i)); + } + merged_capabilities.emplace_back(); + merged_capabilities.back().Swap(&merged); + } + + // 8. Match capabilities. + for (auto& capabilities : merged_capabilities) { + if (MatchCapabilities(&capabilities)) { + capabilities.Swap(result_capabilities); + return Status(kOk); + } + } + + // 9. The spec says "return success with data null", but then the caller is + // instructed to return error when the data is null. Since we don't have a + // convenient way to return data null, we will take a shortcut and return an + // error directly. + return Status(kSessionNotCreated, "No matching capabilities found"); +} + Status ExecuteInitSession(const InitSessionParams& bound_params, Session* session, const base::DictionaryValue& params,
diff --git a/chrome/test/chromedriver/session_commands.h b/chrome/test/chromedriver/session_commands.h index 9bb9e5d..3527937 100644 --- a/chrome/test/chromedriver/session_commands.h +++ b/chrome/test/chromedriver/session_commands.h
@@ -38,7 +38,10 @@ const base::DictionaryValue* first_match, base::DictionaryValue* merged); -bool MatchCapabilities(base::DictionaryValue* capabilities); +bool MatchCapabilities(const base::DictionaryValue* capabilities); + +Status ProcessCapabilities(const base::DictionaryValue& params, + base::DictionaryValue* result_capabilities); std::string WebViewIdToWindowHandle(const std::string& web_view_id);
diff --git a/chrome/test/chromedriver/session_commands_unittest.cc b/chrome/test/chromedriver/session_commands_unittest.cc index 94351d7..21a3656 100644 --- a/chrome/test/chromedriver/session_commands_unittest.cc +++ b/chrome/test/chromedriver/session_commands_unittest.cc
@@ -11,6 +11,7 @@ #include "base/callback.h" #include "base/files/file_path.h" #include "base/files/file_util.h" +#include "base/json/json_reader.h" #include "base/run_loop.h" #include "base/threading/thread.h" #include "base/values.h" @@ -100,6 +101,199 @@ ASSERT_EQ(primary, merged); } +TEST(SessionCommandsTest, ProcessCapabilities_Empty) { + // "capabilities" is required + base::DictionaryValue params; + base::DictionaryValue result; + Status status = ProcessCapabilities(params, &result); + ASSERT_EQ(kInvalidArgument, status.code()); + + // "capabilities" must be a JSON object + params.SetList("capabilities", std::make_unique<base::ListValue>()); + status = ProcessCapabilities(params, &result); + ASSERT_EQ(kInvalidArgument, status.code()); + + // Empty "capabilities" is OK + params.SetDictionary("capabilities", + std::make_unique<base::DictionaryValue>()); + status = ProcessCapabilities(params, &result); + ASSERT_EQ(kOk, status.code()) << status.message(); + ASSERT_TRUE(result.empty()); +} + +TEST(SessionCommandsTest, ProcessCapabilities_AlwaysMatch) { + base::DictionaryValue params; + base::DictionaryValue result; + + // "alwaysMatch" must be a JSON object + params.SetList("capabilities.alwaysMatch", + std::make_unique<base::ListValue>()); + Status status = ProcessCapabilities(params, &result); + ASSERT_EQ(kInvalidArgument, status.code()); + + // Empty "alwaysMatch" is OK + params.SetDictionary("capabilities.alwaysMatch", + std::make_unique<base::DictionaryValue>()); + status = ProcessCapabilities(params, &result); + ASSERT_EQ(kOk, status.code()) << status.message(); + ASSERT_TRUE(result.empty()); + + // Invalid "alwaysMatch" + params.SetInteger("capabilities.alwaysMatch.browserName", 10); + status = ProcessCapabilities(params, &result); + ASSERT_EQ(kInvalidArgument, status.code()); + + // Valid "alwaysMatch" + params.SetString("capabilities.alwaysMatch.browserName", "chrome"); + status = ProcessCapabilities(params, &result); + ASSERT_EQ(kOk, status.code()) << status.message(); + ASSERT_EQ(result.size(), 1u); + std::string result_string; + ASSERT_TRUE(result.GetString("browserName", &result_string)); + ASSERT_EQ(result_string, "chrome"); +} + +TEST(SessionCommandsTest, ProcessCapabilities_FirstMatch) { + base::DictionaryValue params; + base::DictionaryValue result; + + // "firstMatch" must be a JSON list + params.SetDictionary("capabilities.firstMatch", + std::make_unique<base::DictionaryValue>()); + Status status = ProcessCapabilities(params, &result); + ASSERT_EQ(kInvalidArgument, status.code()); + + // "firstMatch" must have at least one entry + params.SetList("capabilities.firstMatch", + std::make_unique<base::ListValue>()); + status = ProcessCapabilities(params, &result); + ASSERT_EQ(kInvalidArgument, status.code()); + + // Each entry must be a JSON object + base::ListValue* list_ptr; + ASSERT_TRUE(params.GetList("capabilities.firstMatch", &list_ptr)); + list_ptr->Set(0, std::make_unique<base::ListValue>()); + status = ProcessCapabilities(params, &result); + ASSERT_EQ(kInvalidArgument, status.code()); + + // Empty JSON object allowed as an entry + list_ptr->Set(0, std::make_unique<base::DictionaryValue>()); + status = ProcessCapabilities(params, &result); + ASSERT_EQ(kOk, status.code()) << status.message(); + ASSERT_TRUE(result.empty()); + + // Invalid entry + base::DictionaryValue* entry_ptr; + ASSERT_TRUE(list_ptr->GetDictionary(0, &entry_ptr)); + entry_ptr->SetString("pageLoadStrategy", "invalid"); + status = ProcessCapabilities(params, &result); + ASSERT_EQ(kInvalidArgument, status.code()); + + // Valid entry + entry_ptr->SetString("pageLoadStrategy", "eager"); + status = ProcessCapabilities(params, &result); + ASSERT_EQ(kOk, status.code()) << status.message(); + ASSERT_EQ(result.size(), 1u); + std::string result_string; + ASSERT_TRUE(result.GetString("pageLoadStrategy", &result_string)); + ASSERT_EQ(result_string, "eager"); + + // Multiple entries, the first one should be selected. + list_ptr->Set(1, std::make_unique<base::DictionaryValue>()); + ASSERT_TRUE(list_ptr->GetDictionary(1, &entry_ptr)); + entry_ptr->SetString("pageLoadStrategy", "normal"); + entry_ptr->SetString("browserName", "chrome"); + status = ProcessCapabilities(params, &result); + ASSERT_EQ(kOk, status.code()) << status.message(); + ASSERT_EQ(result.size(), 1u); + ASSERT_TRUE(result.GetString("pageLoadStrategy", &result_string)); + ASSERT_EQ(result_string, "eager"); +} + +namespace { + +Status ProcessCapabilitiesJson(const std::string& paramsJson, + base::DictionaryValue* result_capabilities) { + std::unique_ptr<base::Value> params = base::JSONReader::Read(paramsJson); + if (!params || !params->is_dict()) + return Status(kUnknownError); + return ProcessCapabilities( + *static_cast<const base::DictionaryValue*>(params.get()), + result_capabilities); +} + +} // namespace + +TEST(SessionCommandsTest, ProcessCapabilities_Merge) { + base::DictionaryValue result; + Status status(kOk); + + // Disallow setting same capability in alwaysMatch and firstMatch + status = ProcessCapabilitiesJson( + R"({ + "capabilities": { + "alwaysMatch": { "pageLoadStrategy": "normal" }, + "firstMatch": [ + { "unhandledPromptBehavior": "accept" }, + { "pageLoadStrategy": "normal" } + ] + } + })", + &result); + ASSERT_EQ(kInvalidArgument, status.code()); + + // No conflicts between alwaysMatch and firstMatch, select first firstMatch + status = ProcessCapabilitiesJson( + R"({ + "capabilities": { + "alwaysMatch": { "timeouts": { } }, + "firstMatch": [ + { "unhandledPromptBehavior": "accept" }, + { "pageLoadStrategy": "normal" } + ] + } + })", + &result); + ASSERT_EQ(kOk, status.code()) << status.message(); + ASSERT_EQ(result.size(), 2u); + ASSERT_TRUE(result.HasKey("timeouts")); + ASSERT_TRUE(result.HasKey("unhandledPromptBehavior")); + ASSERT_FALSE(result.HasKey("pageLoadStrategy")); + + // Selection by browserName + status = ProcessCapabilitiesJson( + R"({ + "capabilities": { + "alwaysMatch": { "timeouts": { } }, + "firstMatch": [ + { "browserName": "firefox", "unhandledPromptBehavior": "accept" }, + { "browserName": "chrome", "pageLoadStrategy": "normal" } + ] + } + })", + &result); + ASSERT_EQ(kOk, status.code()) << status.message(); + ASSERT_EQ(result.size(), 3u); + ASSERT_TRUE(result.HasKey("timeouts")); + ASSERT_EQ(result.FindKey("browserName")->GetString(), "chrome"); + ASSERT_FALSE(result.HasKey("unhandledPromptBehavior")); + ASSERT_TRUE(result.HasKey("pageLoadStrategy")); + + // No acceptable firstMatch + status = ProcessCapabilitiesJson( + R"({ + "capabilities": { + "alwaysMatch": { "timeouts": { } }, + "firstMatch": [ + { "browserName": "firefox", "unhandledPromptBehavior": "accept" }, + { "browserName": "edge", "pageLoadStrategy": "normal" } + ] + } + })", + &result); + ASSERT_EQ(kSessionNotCreated, status.code()); +} + TEST(SessionCommandsTest, FileUpload) { Session session("id"); base::DictionaryValue params;
diff --git a/chrome/test/chromedriver/test/run_py_tests.py b/chrome/test/chromedriver/test/run_py_tests.py index 1da5c0c..4cdf7e7 100755 --- a/chrome/test/chromedriver/test/run_py_tests.py +++ b/chrome/test/chromedriver/test/run_py_tests.py
@@ -2477,7 +2477,7 @@ self.assertTrue('hello' in driver.GetPageSource()) def testUnsupportedPageLoadStrategyRaisesException(self): - self.assertRaises(chromedriver.UnknownError, + self.assertRaises(chromedriver.InvalidArgument, self.CreateDriver, page_load_strategy="unsupported") def testNetworkConnectionDisabledByDefault(self):
diff --git a/chrome/test/data/webui/multidevice_setup/integration_test.js b/chrome/test/data/webui/multidevice_setup/integration_test.js index 46409f25..6ba3c9abb 100644 --- a/chrome/test/data/webui/multidevice_setup/integration_test.js +++ b/chrome/test/data/webui/multidevice_setup/integration_test.js
@@ -45,6 +45,20 @@ } } + /** @implements {multidevice_setup.MojoInterfaceProvider} */ + class FakeMojoInterfaceProviderImpl { + /** @param {!FakeMojoService} fakeMojoService */ + constructor(fakeMojoService) { + /** @private {!FakeMojoService} */ + this.fakeMojoService_ = fakeMojoService; + } + + /** @override */ + getInterfacePtr() { + return this.fakeMojoService_; + } + } + function registerIntegrationTests() { suite('MultiDeviceSetup', () => { /** @@ -65,6 +79,9 @@ */ let backwardButton; + /** @type {!FakeMojoService} */ + let fakeMojoService; + const PASSWORD = 'password-page'; const SUCCESS = 'setup-succeeded-page'; const START = 'start-setup-page'; @@ -72,7 +89,9 @@ setup(() => { multiDeviceSetupElement = document.createElement('multidevice-setup'); multiDeviceSetupElement.delegate = new FakeDelegate(); - multiDeviceSetupElement.multideviceSetup_ = new FakeMojoService(); + fakeMojoService = new FakeMojoService(); + multiDeviceSetupElement.mojoInterfaceProvider_ = + new FakeMojoInterfaceProviderImpl(fakeMojoService); document.body.appendChild(multiDeviceSetupElement); forwardButton = multiDeviceSetupElement.$$('button-bar').$$('#forward');
diff --git a/chrome/test/data/webui/print_preview/destination_search_test.js b/chrome/test/data/webui/print_preview/destination_search_test.js index 24610514..39736c9 100644 --- a/chrome/test/data/webui/print_preview/destination_search_test.js +++ b/chrome/test/data/webui/print_preview/destination_search_test.js
@@ -204,7 +204,7 @@ assertEquals(printerId, destinationStore.selectedDestination.id); }); - // Tests that if policies are set correctly if they are presenst + // Tests that if policies are set correctly if they are present // for a destination. ChromeOS only. test(assert(TestNames.ReceiveSuccessfulSetupWithPolicies), function() { const destId = '00112233DEADBEEF'; @@ -212,7 +212,10 @@ printerId: destId, capabilities: print_preview_test_utils.getCddTemplate(destId).capabilities, - policies: {allowedColorModes: print_preview.ColorMode.GRAY}, + policies: { + allowedColorModes: print_preview.ColorMode.GRAY, + allowedDuplexModes: print_preview.DuplexModeRestriction.DUPLEX, + }, success: true, }; nativeLayer.setSetupPrinterResponse(response); @@ -227,6 +230,9 @@ assertEquals( print_preview.ColorMode.GRAY, selectedDestination.policies.allowedColorModes); + assertEquals( + print_preview.DuplexModeRestriction.DUPLEX, + selectedDestination.policies.allowedDuplexModes); }); }); });
diff --git a/chromecast/app/cast_main_delegate.cc b/chromecast/app/cast_main_delegate.cc index f31b0ed..3353e3d 100644 --- a/chromecast/app/cast_main_delegate.cc +++ b/chromecast/app/cast_main_delegate.cc
@@ -186,6 +186,13 @@ } #endif // defined(OS_LINUX) +bool CastMainDelegate::ShouldCreateFeatureList() { + // TODO(https://crbug.com/887459): Move the creation of FeatureList from + // CastBrowserMainParts::PreCreateThreads() to + // CastMainDelegate::PostEarlyInitialization(). + return false; +} + void CastMainDelegate::InitializeResourceBundle() { base::FilePath pak_file; CHECK(base::PathService::Get(FILE_CAST_PAK, &pak_file));
diff --git a/chromecast/app/cast_main_delegate.h b/chromecast/app/cast_main_delegate.h index 0101796..9df2910 100644 --- a/chromecast/app/cast_main_delegate.h +++ b/chromecast/app/cast_main_delegate.h
@@ -40,6 +40,7 @@ #if defined(OS_LINUX) void ZygoteForked() override; #endif // defined(OS_LINUX) + bool ShouldCreateFeatureList() override; content::ContentBrowserClient* CreateContentBrowserClient() override; content::ContentRendererClient* CreateContentRendererClient() override; content::ContentUtilityClient* CreateContentUtilityClient() override;
diff --git a/chromecast/browser/cast_browser_main_parts.cc b/chromecast/browser/cast_browser_main_parts.cc index 6dfe341..95da9925 100644 --- a/chromecast/browser/cast_browser_main_parts.cc +++ b/chromecast/browser/cast_browser_main_parts.cc
@@ -395,10 +395,6 @@ return cast_browser_process_->browser_context(); } -bool CastBrowserMainParts::ShouldContentCreateFeatureList() { - return false; -} - void CastBrowserMainParts::PreMainMessageLoopStart() { // GroupedHistograms needs to be initialized before any threads are created // to prevent race conditions between calls to Preregister and those threads
diff --git a/chromecast/browser/cast_browser_main_parts.h b/chromecast/browser/cast_browser_main_parts.h index e48a944..005373b 100644 --- a/chromecast/browser/cast_browser_main_parts.h +++ b/chromecast/browser/cast_browser_main_parts.h
@@ -80,7 +80,6 @@ content::BrowserContext* browser_context(); // content::BrowserMainParts implementation: - bool ShouldContentCreateFeatureList() override; void PreMainMessageLoopStart() override; void PostMainMessageLoopStart() override; void ToolkitInitialized() override;
diff --git a/components/autofill/core/browser/autofill_wallet_data_type_controller.cc b/components/autofill/core/browser/autofill_wallet_data_type_controller.cc index a717a83..24ad447 100644 --- a/components/autofill/core/browser/autofill_wallet_data_type_controller.cc +++ b/components/autofill/core/browser/autofill_wallet_data_type_controller.cc
@@ -71,23 +71,29 @@ void AutofillWalletDataTypeController::StopModels() { DCHECK(CalledOnValidThread()); - // This function is called when shutting down (nothing is changing), when - // sync is disabled completely, or when wallet sync is disabled. In the - // cases where wallet sync or sync in general is disabled, clear wallet cards - // and addresses copied from the server. This is different than other sync - // cases since this type of data reflects what's on the server rather than - // syncing local data between clients, so this extra step is required. - syncer::SyncService* service = sync_client_->GetSyncService(); + // This controller is used by two data types, we need to clear the data only + // once. (In particular, if AUTOFILL_WALLET_DATA is on USS (and thus doesn't + // use this controller), we *don't* want any ClearAllServerData call). + if (type() == syncer::AUTOFILL_WALLET_DATA) { + // This function is called when shutting down (nothing is changing), when + // sync is disabled completely, or when wallet sync is disabled. In the + // cases where wallet sync or sync in general is disabled, clear wallet + // cards and addresses copied from the server. This is different than other + // sync cases since this type of data reflects what's on the server rather + // than syncing local data between clients, so this extra step is required. + syncer::SyncService* service = sync_client_->GetSyncService(); - // CanSyncFeatureStart indicates if sync is currently enabled at all. The - // preferred data type indicates if wallet sync data/metadata is enabled, and - // currently_enabled_ indicates if the other prefs are enabled. All of these - // have to be enabled to sync wallet data/metadata. - if (!service->CanSyncFeatureStart() || - !service->GetPreferredDataTypes().Has(type()) || !currently_enabled_) { - autofill::PersonalDataManager* pdm = sync_client_->GetPersonalDataManager(); - if (pdm) - pdm->ClearAllServerData(); + // CanSyncFeatureStart indicates if sync is currently enabled at all. The + // preferred data type indicates if wallet sync data is enabled, and + // currently_enabled_ indicates if the other prefs are enabled. All of these + // have to be enabled to sync wallet data. + if (!service->CanSyncFeatureStart() || + !service->GetPreferredDataTypes().Has(type()) || !currently_enabled_) { + autofill::PersonalDataManager* pdm = + sync_client_->GetPersonalDataManager(); + if (pdm) + pdm->ClearAllServerData(); + } } }
diff --git a/components/autofill/core/browser/personal_data_manager.cc b/components/autofill/core/browser/personal_data_manager.cc index f1e4770..8f8ad97 100644 --- a/components/autofill/core/browser/personal_data_manager.cc +++ b/components/autofill/core/browser/personal_data_manager.cc
@@ -1064,6 +1064,7 @@ // clear so that tests can synchronously verify that this data was cleared. server_credit_cards_.clear(); server_profiles_.clear(); + payments_customer_data_.reset(); } void PersonalDataManager::ClearAllLocalData() {
diff --git a/components/autofill/core/browser/webdata/autofill_table.cc b/components/autofill/core/browser/webdata/autofill_table.cc index c3258ef8..44662ea6 100644 --- a/components/autofill/core/browser/webdata/autofill_table.cc +++ b/components/autofill/core/browser/webdata/autofill_table.cc
@@ -1501,6 +1501,11 @@ address_metadata.Run(); changed |= db_->GetLastChangeCount() > 0; + sql::Statement customer_data( + db_->GetUniqueStatement("DELETE FROM payments_customer_data")); + customer_data.Run(); + changed |= db_->GetLastChangeCount() > 0; + transaction.Commit(); return changed; }
diff --git a/components/autofill/core/browser/webdata/autofill_wallet_sync_bridge.cc b/components/autofill/core/browser/webdata/autofill_wallet_sync_bridge.cc index ccb89687..17ca126 100644 --- a/components/autofill/core/browser/webdata/autofill_wallet_sync_bridge.cc +++ b/components/autofill/core/browser/webdata/autofill_wallet_sync_bridge.cc
@@ -270,7 +270,7 @@ // In both cases, we need to update wallet cards and payments customer data. wallet_data_changed |= SetWalletCards(std::move(wallet_cards)); - wallet_data_changed |= SetPaymentsCustormerData(std::move(customer_data)); + wallet_data_changed |= SetPaymentsCustomerData(std::move(customer_data)); if (web_data_backend_ && wallet_data_changed) web_data_backend_->NotifyOfMultipleAutofillChanges(); @@ -343,7 +343,7 @@ return false; } -bool AutofillWalletSyncBridge::SetPaymentsCustormerData( +bool AutofillWalletSyncBridge::SetPaymentsCustomerData( std::vector<PaymentsCustomerData> customer_data) { // In the common case, the database won't have changed. Committing an update // to the database will require at least one DB page write and will schedule
diff --git a/components/autofill/core/browser/webdata/autofill_wallet_sync_bridge.h b/components/autofill/core/browser/webdata/autofill_wallet_sync_bridge.h index 13854694..7df84335 100644 --- a/components/autofill/core/browser/webdata/autofill_wallet_sync_bridge.h +++ b/components/autofill/core/browser/webdata/autofill_wallet_sync_bridge.h
@@ -98,8 +98,7 @@ // Sets |customer_data| to this client and returns whether any change has been // applied (i.e., whether |customer_data| was different from local data). - bool SetPaymentsCustormerData( - std::vector<PaymentsCustomerData> customer_data); + bool SetPaymentsCustomerData(std::vector<PaymentsCustomerData> customer_data); // Computes a "diff" (items added, items removed) of two vectors of items, // which should be either CreditCard or AutofillProfile. This is used for
diff --git a/components/autofill_assistant/browser/BUILD.gn b/components/autofill_assistant/browser/BUILD.gn index 50cdd5d..ad5d9997 100644 --- a/components/autofill_assistant/browser/BUILD.gn +++ b/components/autofill_assistant/browser/BUILD.gn
@@ -32,6 +32,8 @@ "actions/stop_action.h", "actions/tell_action.cc", "actions/tell_action.h", + "actions/unsupported_action.cc", + "actions/unsupported_action.h", "actions/upload_dom_action.cc", "actions/upload_dom_action.h", "actions/wait_for_dom_action.cc",
diff --git a/components/autofill_assistant/browser/actions/action.cc b/components/autofill_assistant/browser/actions/action.cc index 16a01f1..f9f74ed 100644 --- a/components/autofill_assistant/browser/actions/action.cc +++ b/components/autofill_assistant/browser/actions/action.cc
@@ -10,12 +10,10 @@ Action::~Action() {} -void Action::UpdateProcessedAction(bool status) { +void Action::UpdateProcessedAction(ProcessedActionStatusProto status) { // Safety check in case process action is run twice. *processed_action_proto_->mutable_action() = proto_; - processed_action_proto_->set_status( - status ? ProcessedActionStatusProto::ACTION_APPLIED - : ProcessedActionStatusProto::OTHER_ACTION_STATUS); + processed_action_proto_->set_status(status); } } // namespace autofill_assistant
diff --git a/components/autofill_assistant/browser/actions/action.h b/components/autofill_assistant/browser/actions/action.h index e0060b3..b3c684b 100644 --- a/components/autofill_assistant/browser/actions/action.h +++ b/components/autofill_assistant/browser/actions/action.h
@@ -31,7 +31,7 @@ protected: explicit Action(const ActionProto& proto); - void UpdateProcessedAction(bool status); + void UpdateProcessedAction(ProcessedActionStatusProto status); const ActionProto proto_;
diff --git a/components/autofill_assistant/browser/actions/autofill_action.cc b/components/autofill_assistant/browser/actions/autofill_action.cc index beaa3414..1e9e25c 100644 --- a/components/autofill_assistant/browser/actions/autofill_action.cc +++ b/components/autofill_assistant/browser/actions/autofill_action.cc
@@ -88,7 +88,7 @@ } // namespace AutofillAction::AutofillAction(const ActionProto& proto) - : Action(proto), pending_set_field_value_(0), weak_ptr_factory_(this) { + : Action(proto), weak_ptr_factory_(this) { if (proto.has_use_address()) { is_autofill_card_ = false; prompt_ = proto.use_address().prompt(); @@ -99,6 +99,8 @@ } fill_form_message_ = proto.use_address().strings().fill_form(); check_form_message_ = proto.use_address().strings().check_form(); + required_fields_value_status_.resize( + proto_.use_address().required_fields_size(), UNKNOWN); } else { DCHECK(proto.has_use_card()); is_autofill_card_ = true; @@ -164,7 +166,7 @@ } void AutofillAction::EndAction(bool successful) { - UpdateProcessedAction(successful); + UpdateProcessedAction(successful ? ACTION_APPLIED : OTHER_ACTION_STATUS); std::move(process_action_callback_).Run(std::move(processed_action_proto_)); } @@ -223,8 +225,7 @@ if (!card) { // TODO(crbug.com/806868): The failure might because of cancel, then ask to // choose a card again. - UpdateProcessedAction(false); - std::move(process_action_callback_).Run(std::move(processed_action_proto_)); + EndAction(false); return; } @@ -262,99 +263,153 @@ return; } - int required_fields_size = proto_.use_address().required_fields_size(); - required_fields_value_status_.clear(); - required_fields_value_status_.resize(required_fields_size, UNKNOWN); - for (int i = 0; i < required_fields_size; i++) { - const auto& required_address_field = - proto_.use_address().required_fields(i); - DCHECK(required_address_field.has_address_field()); - DCHECK(!required_address_field.element().selectors().empty()); - std::vector<std::string> selectors; - for (const auto& selector : required_address_field.element().selectors()) { - selectors.emplace_back(selector); - } - delegate->GetFieldValue( - selectors, base::BindOnce(&AutofillAction::OnGetRequiredFieldValue, - weak_ptr_factory_.GetWeakPtr(), guid, - delegate, allow_fallback, i)); - } + CheckRequiredFieldsSequentially(guid, delegate, allow_fallback, 0); } -void AutofillAction::OnGetRequiredFieldValue( +void AutofillAction::CheckRequiredFieldsSequentially( const std::string& guid, ActionDelegate* delegate, bool allow_fallback, - int index, - const std::string& value) { - DCHECK(!is_autofill_card_); - required_fields_value_status_[index] = value.empty() ? EMPTY : NOT_EMPTY; - - // Wait for the value of all required fields. - for (const auto& status : required_fields_value_status_) { - if (status == UNKNOWN) { - return; - } + int required_fields_index) { + DCHECK_GE(required_fields_index, 0); + if (required_fields_index >= proto_.use_address().required_fields_size()) { + DCHECK_EQ(required_fields_index, + proto_.use_address().required_fields_size()); + OnCheckRequiredFieldsDone(guid, delegate, allow_fallback); + return; } - const autofill::AutofillProfile* profile = - delegate->GetPersonalDataManager()->GetProfileByGUID(guid); - DCHECK(profile); + const auto& required_address_field = + proto_.use_address().required_fields(required_fields_index); + DCHECK(required_address_field.has_address_field()); + DCHECK(!required_address_field.element().selectors().empty()); + std::vector<std::string> selectors; + for (const auto& selector : required_address_field.element().selectors()) { + selectors.emplace_back(selector); + } + delegate->GetFieldValue( + selectors, base::BindOnce(&AutofillAction::OnGetRequiredFieldValue, + weak_ptr_factory_.GetWeakPtr(), guid, delegate, + allow_fallback, required_fields_index)); +} +void AutofillAction::OnGetRequiredFieldValue(const std::string& guid, + ActionDelegate* delegate, + bool allow_fallback, + int required_fields_index, + const std::string& value) { + DCHECK(!is_autofill_card_); + required_fields_value_status_[required_fields_index] = + value.empty() ? EMPTY : NOT_EMPTY; + CheckRequiredFieldsSequentially(guid, delegate, allow_fallback, + ++required_fields_index); +} + +void AutofillAction::OnCheckRequiredFieldsDone(const std::string& guid, + ActionDelegate* delegate, + bool allow_fallback) { // We process all fields with an empty value in order to perform the fallback // on all those fields, if any. bool validation_successful = true; - std::vector<std::vector<std::string>> failed_selectors; - std::vector<std::string> fallback_values; - for (size_t i = 0; i < required_fields_value_status_.size(); i++) { - if (required_fields_value_status_[i] == EMPTY) { - if (!allow_fallback) { - // Validation failed and we don't want to try the fallback, so we stop - // the script. - delegate->StopCurrentScript(check_form_message_); - EndAction(/* successful= */ true); - return; - } - + for (FieldValueStatus status : required_fields_value_status_) { + if (status == EMPTY) { validation_successful = false; - std::string fallback_value = base::UTF16ToUTF8(GetAddressFieldValue( - profile, proto_.use_address().required_fields(i).address_field())); - if (fallback_value.empty()) { - // If there is no fallback value, we skip this failed field. - continue; - } - - fallback_values.emplace_back(fallback_value); - failed_selectors.emplace_back(std::vector<std::string>()); - for (const auto& selector : - proto_.use_address().required_fields(i).element().selectors()) { - failed_selectors.back().emplace_back(selector); - } + break; } } - DCHECK_EQ(failed_selectors.size(), fallback_values.size()); - if (validation_successful) { EndAction(/* successful= */ true); return; } - if (fallback_values.empty()) { - // One or more required fields is empty but there is no fallback value, so - // we stop the script. + if (!allow_fallback) { + // Validation failed and we don't want to try the fallback, so we stop + // the script. delegate->StopCurrentScript(check_form_message_); EndAction(/* successful= */ true); return; } - pending_set_field_value_ = failed_selectors.size(); - for (size_t i = 0; i < failed_selectors.size(); i++) { - delegate->SetFieldValue( - failed_selectors[i], fallback_values[i], - base::BindOnce(&AutofillAction::OnSetFieldValue, - weak_ptr_factory_.GetWeakPtr(), guid, delegate)); + // If there are any fallbacks for the empty fields, set them, otherwise fail + // immediately. + bool has_fallbacks = false; + auto* profile = delegate->GetPersonalDataManager()->GetProfileByGUID(guid); + DCHECK(profile); + for (int i = 0; i < proto_.use_address().required_fields_size(); i++) { + if (required_fields_value_status_[i] == EMPTY && + !GetAddressFieldValue( + profile, proto_.use_address().required_fields(i).address_field()) + .empty()) { + has_fallbacks = true; + break; + } } + if (!has_fallbacks) { + delegate->StopCurrentScript(check_form_message_); + EndAction(/* successful= */ true); + return; + } + + // Set the fallback values and check again. + SetFallbackFieldValuesSequentially(guid, delegate, 0); +} + +void AutofillAction::SetFallbackFieldValuesSequentially( + const std::string& guid, + ActionDelegate* delegate, + int required_fields_index) { + DCHECK_GE(required_fields_index, 0); + + // Skip non-empty fields. + const auto& required_fields = proto_.use_address().required_fields(); + while (required_fields_index < required_fields.size() && + required_fields_value_status_[required_fields_index] != EMPTY) { + required_fields_index++; + } + + // If there are no more fields to set, check the required fields again, + // but this time we don't want to try the fallback in case of failure. + if (required_fields_index >= required_fields.size()) { + DCHECK_EQ(required_fields_index, required_fields.size()); + + CheckRequiredFields(guid, delegate, /* allow_fallback */ false); + return; + } + + // Set the next field to its fallback value. + std::string fallback_value = base::UTF16ToUTF8(GetAddressFieldValue( + delegate->GetPersonalDataManager()->GetProfileByGUID(guid), + required_fields.Get(required_fields_index).address_field())); + if (fallback_value.empty()) { + // If there is no fallback value, we skip this failed field. + SetFallbackFieldValuesSequentially(guid, delegate, ++required_fields_index); + return; + } + + std::vector<std::string> selectors; + for (const auto& selector : + required_fields.Get(required_fields_index).element().selectors()) { + selectors.emplace_back(selector); + } + delegate->SetFieldValue( + selectors, fallback_value, + base::BindOnce(&AutofillAction::OnSetFallbackFieldValue, + weak_ptr_factory_.GetWeakPtr(), guid, delegate, + required_fields_index)); +} + +void AutofillAction::OnSetFallbackFieldValue(const std::string& guid, + ActionDelegate* delegate, + int required_fields_index, + bool successful) { + if (!successful) { + // Fallback failed: we stop the script without checking the fields. + delegate->StopCurrentScript(check_form_message_); + EndAction(/* successful= */ true); + return; + } + SetFallbackFieldValuesSequentially(guid, delegate, ++required_fields_index); } base::string16 AutofillAction::GetAddressFieldValue( @@ -394,30 +449,4 @@ return base::string16(); } } - -void AutofillAction::OnSetFieldValue(const std::string& guid, - ActionDelegate* delegate, - bool successful) { - DCHECK_LT(0u, pending_set_field_value_); - pending_set_field_value_--; - - // Fail early if filling a field failed and we haven't returned anything yet. - // We can ignore the other SetFieldValue callbacks given that an action is - // processed only once. - if (!successful) { - // Fallback failed: we stop the script without checking the fields. - if (process_action_callback_) { - delegate->StopCurrentScript(check_form_message_); - EndAction(/* successful= */ true); - } - return; - } - - if (!pending_set_field_value_ && process_action_callback_) { - // We check the required fields again, but this time we don't want to try - // the fallback in case if failure. - CheckRequiredFields(guid, delegate, /* allow_fallback */ false); - } -} - } // namespace autofill_assistant
diff --git a/components/autofill_assistant/browser/actions/autofill_action.h b/components/autofill_assistant/browser/actions/autofill_action.h index cd140caa..cd64846d 100644 --- a/components/autofill_assistant/browser/actions/autofill_action.h +++ b/components/autofill_assistant/browser/actions/autofill_action.h
@@ -5,14 +5,14 @@ #ifndef COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_ACTIONS_AUTOFILL_ACTION_H_ #define COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_ACTIONS_AUTOFILL_ACTION_H_ -#include "components/autofill_assistant/browser/actions/action.h" - +#include <memory> #include <string> #include <vector> #include "base/callback.h" #include "base/macros.h" #include "base/memory/weak_ptr.h" +#include "components/autofill_assistant/browser/actions/action.h" namespace autofill { class AutofillProfile; @@ -33,6 +33,8 @@ private: enum FieldValueStatus { UNKNOWN, EMPTY, NOT_EMPTY }; + void EndAction(bool successful); + // Called when the user selected the data. void OnDataSelected(ActionDelegate* delegate, const std::string& guid); @@ -59,26 +61,43 @@ ActionDelegate* delegate, bool allow_fallback); - // Called when we get the value of the required fields. + // Triggers the check for a specific field. + void CheckRequiredFieldsSequentially(const std::string& guid, + ActionDelegate* delegate, + bool allow_fallback, + int required_fields_index); + + // Process the result of all field checks and continue the flow with + // OnCheckRequiredFieldsDone. void OnGetRequiredFieldValue(const std::string& guid, ActionDelegate* delegate, bool allow_fallback, - int index, + int required_fields_index, const std::string& value); + // Called when all required fields have been checked. + void OnCheckRequiredFieldsDone(const std::string& guid, + ActionDelegate* delegate, + bool allow_fallback); + // Get the value of |address_field| associated to profile |profile|. Return // empty string if there is no data available. base::string16 GetAddressFieldValue( const autofill::AutofillProfile* profile, const UseAddressProto::RequiredField::AddressField& address_field); + // Sets fallback field values for empty fields from + // |required_fields_value_status_|. + void SetFallbackFieldValuesSequentially(const std::string& guid, + ActionDelegate* delegate, + int required_fields_index); + // Called after trying to set form values without Autofill in case of fallback // after failed validation. - void OnSetFieldValue(const std::string& guid, - ActionDelegate* delegate, - bool successful); - - void EndAction(bool successful); + void OnSetFallbackFieldValue(const std::string& guid, + ActionDelegate* delegate, + int required_fields_index, + bool successful); // Usage of the autofilled address. Ignored if autofilling a card. std::string name_; @@ -90,7 +109,7 @@ // True if autofilling a card, otherwise we are autofilling an address. bool is_autofill_card_; std::vector<FieldValueStatus> required_fields_value_status_; - size_t pending_set_field_value_; + ProcessActionCallback process_action_callback_; base::WeakPtrFactory<AutofillAction> weak_ptr_factory_;
diff --git a/components/autofill_assistant/browser/actions/autofill_action_unittest.cc b/components/autofill_assistant/browser/actions/autofill_action_unittest.cc index b308227..155a0a1 100644 --- a/components/autofill_assistant/browser/actions/autofill_action_unittest.cc +++ b/components/autofill_assistant/browser/actions/autofill_action_unittest.cc
@@ -4,6 +4,8 @@ #include "components/autofill_assistant/browser/actions/autofill_action.h" +#include <utility> + #include "base/bind.h" #include "base/guid.h" #include "components/autofill/core/browser/autofill_profile.h" @@ -21,6 +23,7 @@ using ::testing::_; using ::testing::ElementsAre; using ::testing::InSequence; +using ::testing::Not; using ::testing::Return; using ::testing::StrNe; @@ -109,8 +112,8 @@ const char* const kAddressName = "billing"; const char* const kFakeSelector = "#selector"; const char* const kSelectionPrompt = "prompt"; - const char* const kFirstName = "Foo"; - const char* const kLastName = "Bar"; + const char* const kFirstName = "FirstName"; + const char* const kLastName = "LastName"; const char* const kEmail = "foobar@gmail.com"; const char* const kFillForm = "fill_form"; const char* const kCheckForm = "check_form"; @@ -125,6 +128,14 @@ return action; } + void AddRequiredField(ActionProto* action, + UseAddressProto::RequiredField::AddressField type, + std::string selector) { + auto* required_field = action->mutable_use_address()->add_required_fields(); + required_field->set_address_field(type); + required_field->mutable_element()->add_selectors(selector); + } + ActionProto CreateUseCardAction() { ActionProto action; UseCreditCardProto* use_card = action.mutable_use_card(); @@ -218,17 +229,12 @@ InSequence seq; ActionProto action_proto = CreateUseAddressAction(); - std::vector<UseAddressProto::RequiredField::AddressField> address_fields = { - UseAddressProto::RequiredField::FIRST_NAME, - UseAddressProto::RequiredField::LAST_NAME, - UseAddressProto::RequiredField::EMAIL}; - - for (size_t i = 0; i < address_fields.size(); i++) { - auto* required_field = - action_proto.mutable_use_address()->add_required_fields(); - required_field->set_address_field(address_fields[i]); - required_field->mutable_element()->add_selectors(kFakeSelector); - } + AddRequiredField(&action_proto, UseAddressProto::RequiredField::FIRST_NAME, + "#first_name"); + AddRequiredField(&action_proto, UseAddressProto::RequiredField::LAST_NAME, + "#last_name"); + AddRequiredField(&action_proto, UseAddressProto::RequiredField::EMAIL, + "#email"); // Return a fake selected address. EXPECT_CALL(mock_client_memory_, selected_address(kAddressName)) @@ -242,14 +248,15 @@ // Validation fails when getting FIRST_NAME. EXPECT_CALL(mock_action_delegate_, - OnGetFieldValue(ElementsAre(kFakeSelector), _)) - .Times(address_fields.size()) - .WillOnce(RunOnceCallback<1>("")) + OnGetFieldValue(ElementsAre("#first_name"), _)) + .WillOnce(RunOnceCallback<1>("")); + EXPECT_CALL(mock_action_delegate_, + OnGetFieldValue(Not(ElementsAre("#first_name")), _)) .WillRepeatedly(RunOnceCallback<1>("not empty")); // Fallback fails. EXPECT_CALL(mock_action_delegate_, - OnSetFieldValue(ElementsAre(kFakeSelector), kFirstName, _)) + OnSetFieldValue(ElementsAre("#first_name"), kFirstName, _)) .WillOnce(RunOnceCallback<2>(false)); ExpectActionToStopScript(action_proto, kCheckForm); @@ -259,17 +266,12 @@ InSequence seq; ActionProto action_proto = CreateUseAddressAction(); - std::vector<UseAddressProto::RequiredField::AddressField> address_fields = { - UseAddressProto::RequiredField::FIRST_NAME, - UseAddressProto::RequiredField::LAST_NAME, - UseAddressProto::RequiredField::EMAIL}; - - for (size_t i = 0; i < address_fields.size(); i++) { - auto* required_field = - action_proto.mutable_use_address()->add_required_fields(); - required_field->set_address_field(address_fields[i]); - required_field->mutable_element()->add_selectors(kFakeSelector); - } + AddRequiredField(&action_proto, UseAddressProto::RequiredField::FIRST_NAME, + "#first_name"); + AddRequiredField(&action_proto, UseAddressProto::RequiredField::LAST_NAME, + "#last_name"); + AddRequiredField(&action_proto, UseAddressProto::RequiredField::EMAIL, + "#email"); // Return a fake selected address. EXPECT_CALL(mock_client_memory_, selected_address(kAddressName)) @@ -281,24 +283,26 @@ OnFillAddressForm(autofill_profile_guid_, ElementsAre(kFakeSelector), _)) .WillOnce(RunOnceCallback<2>(true)); - // Validation fails when getting FIRST_NAME. - EXPECT_CALL(mock_action_delegate_, - OnGetFieldValue(ElementsAre(kFakeSelector), _)) - .Times(address_fields.size()) - .WillOnce(RunOnceCallback<1>("")) - .WillRepeatedly(RunOnceCallback<1>("not empty")); + { + InSequence seq; - // Fallback succeeds. - EXPECT_CALL(mock_action_delegate_, - OnSetFieldValue(ElementsAre(kFakeSelector), kFirstName, _)) - .WillOnce(RunOnceCallback<2>(true)); + // Validation fails when getting FIRST_NAME. + EXPECT_CALL(mock_action_delegate_, + OnGetFieldValue(ElementsAre("#first_name"), _)) + .WillOnce(RunOnceCallback<1>("")); + EXPECT_CALL(mock_action_delegate_, + OnGetFieldValue(Not(ElementsAre("#first_name")), _)) + .WillRepeatedly(RunOnceCallback<1>("not empty")); - // Second validation succeeds. - EXPECT_CALL(mock_action_delegate_, - OnGetFieldValue(ElementsAre(kFakeSelector), _)) - .Times(address_fields.size()) - .WillRepeatedly(RunOnceCallback<1>("not empty")); + // Fallback succeeds. + EXPECT_CALL(mock_action_delegate_, + OnSetFieldValue(ElementsAre("#first_name"), kFirstName, _)) + .WillOnce(RunOnceCallback<2>(true)); + // Second validation succeeds. + EXPECT_CALL(mock_action_delegate_, OnGetFieldValue(_, _)) + .WillRepeatedly(RunOnceCallback<1>("not empty")); + } EXPECT_TRUE(ProcessAction(action_proto)); }
diff --git a/components/autofill_assistant/browser/actions/click_action.cc b/components/autofill_assistant/browser/actions/click_action.cc index 109f0d461..a220187 100644 --- a/components/autofill_assistant/browser/actions/click_action.cc +++ b/components/autofill_assistant/browser/actions/click_action.cc
@@ -34,7 +34,9 @@ } void ClickAction::OnClick(ProcessActionCallback callback, bool status) { - UpdateProcessedAction(status); + // TODO(crbug.com/806868): Distinguish element not found from other error and + // report them as ELEMENT_RESOLUTION_FAILED. + UpdateProcessedAction(status ? ACTION_APPLIED : OTHER_ACTION_STATUS); std::move(callback).Run(std::move(processed_action_proto_)); }
diff --git a/components/autofill_assistant/browser/actions/focus_element_action.cc b/components/autofill_assistant/browser/actions/focus_element_action.cc index 1a3f0bd..c83160c9 100644 --- a/components/autofill_assistant/browser/actions/focus_element_action.cc +++ b/components/autofill_assistant/browser/actions/focus_element_action.cc
@@ -39,7 +39,9 @@ void FocusElementAction::OnFocusElement(ProcessActionCallback callback, bool status) { - UpdateProcessedAction(status); + // TODO(crbug.com/806868): Distinguish element not found from other error and + // report them as ELEMENT_RESOLUTION_FAILED. + UpdateProcessedAction(status ? ACTION_APPLIED : OTHER_ACTION_STATUS); std::move(callback).Run(std::move(processed_action_proto_)); }
diff --git a/components/autofill_assistant/browser/actions/navigate_action.cc b/components/autofill_assistant/browser/actions/navigate_action.cc index 67e2c08..78b677be 100644 --- a/components/autofill_assistant/browser/actions/navigate_action.cc +++ b/components/autofill_assistant/browser/actions/navigate_action.cc
@@ -24,7 +24,7 @@ GURL url(proto_.navigate().url()); delegate->LoadURL(url); processed_action_proto_ = std::make_unique<ProcessedActionProto>(); - UpdateProcessedAction(/* status= */ true); + UpdateProcessedAction(ACTION_APPLIED); std::move(callback).Run(std::move(processed_action_proto_)); }
diff --git a/components/autofill_assistant/browser/actions/reset_action.cc b/components/autofill_assistant/browser/actions/reset_action.cc index ea3b81f..2a83e54 100644 --- a/components/autofill_assistant/browser/actions/reset_action.cc +++ b/components/autofill_assistant/browser/actions/reset_action.cc
@@ -22,7 +22,7 @@ ProcessActionCallback callback) { delegate->Restart(); processed_action_proto_ = std::make_unique<ProcessedActionProto>(); - UpdateProcessedAction(true); + UpdateProcessedAction(ACTION_APPLIED); std::move(callback).Run(std::move(processed_action_proto_)); }
diff --git a/components/autofill_assistant/browser/actions/select_option_action.cc b/components/autofill_assistant/browser/actions/select_option_action.cc index c95d5a1..b8e4493 100644 --- a/components/autofill_assistant/browser/actions/select_option_action.cc +++ b/components/autofill_assistant/browser/actions/select_option_action.cc
@@ -40,7 +40,9 @@ void SelectOptionAction::OnSelectOption(ProcessActionCallback callback, bool status) { - UpdateProcessedAction(status); + // TODO(crbug.com/806868): Distinguish element not found from other error and + // report them as ELEMENT_RESOLUTION_FAILED. + UpdateProcessedAction(status ? ACTION_APPLIED : OTHER_ACTION_STATUS); std::move(callback).Run(std::move(processed_action_proto_)); }
diff --git a/components/autofill_assistant/browser/actions/stop_action.cc b/components/autofill_assistant/browser/actions/stop_action.cc index fba77a7..1a670eb 100644 --- a/components/autofill_assistant/browser/actions/stop_action.cc +++ b/components/autofill_assistant/browser/actions/stop_action.cc
@@ -22,7 +22,7 @@ ProcessActionCallback callback) { delegate->Shutdown(); processed_action_proto_ = std::make_unique<ProcessedActionProto>(); - UpdateProcessedAction(true); + UpdateProcessedAction(ACTION_APPLIED); std::move(callback).Run(std::move(processed_action_proto_)); }
diff --git a/components/autofill_assistant/browser/actions/tell_action.cc b/components/autofill_assistant/browser/actions/tell_action.cc index ecd2127..fd97359f 100644 --- a/components/autofill_assistant/browser/actions/tell_action.cc +++ b/components/autofill_assistant/browser/actions/tell_action.cc
@@ -22,7 +22,7 @@ processed_action_proto_ = std::make_unique<ProcessedActionProto>(); // tell.message in the proto is localized. delegate->ShowStatusMessage(proto_.tell().message()); - UpdateProcessedAction(true); + UpdateProcessedAction(ACTION_APPLIED); std::move(callback).Run(std::move(processed_action_proto_)); }
diff --git a/components/autofill_assistant/browser/actions/unsupported_action.cc b/components/autofill_assistant/browser/actions/unsupported_action.cc new file mode 100644 index 0000000..4f806e1 --- /dev/null +++ b/components/autofill_assistant/browser/actions/unsupported_action.cc
@@ -0,0 +1,27 @@ +// 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/autofill_assistant/browser/actions/unsupported_action.h" + +#include <memory> + +#include "base/bind.h" +#include "base/callback.h" + +namespace autofill_assistant { + +UnsupportedAction::UnsupportedAction(const ActionProto& proto) + : Action(proto) {} + +UnsupportedAction::~UnsupportedAction() {} + +void UnsupportedAction::ProcessAction(ActionDelegate* delegate, + ProcessActionCallback callback) { + processed_action_proto_ = std::make_unique<ProcessedActionProto>(); + // TODO(crbug.com/806868): Add 'unsupported action' status to the protocol. + UpdateProcessedAction(UNKNOWN_ACTION_STATUS); + std::move(callback).Run(std::move(processed_action_proto_)); +} + +} // namespace autofill_assistant
diff --git a/components/autofill_assistant/browser/actions/unsupported_action.h b/components/autofill_assistant/browser/actions/unsupported_action.h new file mode 100644 index 0000000..956b648 --- /dev/null +++ b/components/autofill_assistant/browser/actions/unsupported_action.h
@@ -0,0 +1,29 @@ +// 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_AUTOFILL_ASSISTANT_BROWSER_ACTIONS_UNSUPPORTED_ACTION_H_ +#define COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_ACTIONS_UNSUPPORTED_ACTION_H_ + +#include "base/macros.h" +#include "components/autofill_assistant/browser/actions/action.h" + +namespace autofill_assistant { +// An unsupported action that always fails. +class UnsupportedAction : public Action { + public: + explicit UnsupportedAction(const ActionProto& proto); + ~UnsupportedAction() override; + + // Overrides Action: + void ProcessAction(ActionDelegate* delegate, + ProcessActionCallback callback) override; + + private: + void OnUnsupported(ProcessActionCallback callback, bool status); + + DISALLOW_COPY_AND_ASSIGN(UnsupportedAction); +}; + +} // namespace autofill_assistant +#endif // COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_ACTIONS_UNSUPPORTED_ACTION_H_
diff --git a/components/autofill_assistant/browser/actions/upload_dom_action.cc b/components/autofill_assistant/browser/actions/upload_dom_action.cc index 682eac8..1b20311 100644 --- a/components/autofill_assistant/browser/actions/upload_dom_action.cc +++ b/components/autofill_assistant/browser/actions/upload_dom_action.cc
@@ -38,7 +38,9 @@ void UploadDomAction::OnBuildNodeTree(ProcessActionCallback callback, bool status) { - UpdateProcessedAction(status); + // TODO(crbug.com/806868): Distinguish element not found from other error and + // report them as ELEMENT_RESOLUTION_FAILED. + UpdateProcessedAction(status ? ACTION_APPLIED : OTHER_ACTION_STATUS); std::move(callback).Run(std::move(processed_action_proto_)); }
diff --git a/components/autofill_assistant/browser/actions/wait_for_dom_action.cc b/components/autofill_assistant/browser/actions/wait_for_dom_action.cc index be7dd36..5c9ab23 100644 --- a/components/autofill_assistant/browser/actions/wait_for_dom_action.cc +++ b/components/autofill_assistant/browser/actions/wait_for_dom_action.cc
@@ -34,7 +34,7 @@ // Fail the action if selectors is empty. if (proto_.wait_for_dom().selectors().empty()) { - UpdateProcessedAction(false); + UpdateProcessedAction(OTHER_ACTION_STATUS); DLOG(ERROR) << "Empty selector, failing action."; std::move(callback).Run(std::move(processed_action_proto_)); return; @@ -68,13 +68,13 @@ ProcessActionCallback callback, bool result) { if (result) { - UpdateProcessedAction(true); + UpdateProcessedAction(ACTION_APPLIED); std::move(callback).Run(std::move(processed_action_proto_)); return; } if (rounds == 0) { - UpdateProcessedAction(false); + UpdateProcessedAction(ELEMENT_RESOLUTION_FAILED); std::move(callback).Run(std::move(processed_action_proto_)); return; }
diff --git a/components/autofill_assistant/browser/devtools/devtools_client.cc b/components/autofill_assistant/browser/devtools/devtools_client.cc index 42ca72d8..cf6fadc 100644 --- a/components/autofill_assistant/browser/devtools/devtools_client.cc +++ b/components/autofill_assistant/browser/devtools/devtools_client.cc
@@ -108,7 +108,7 @@ ? DispatchMessageReply(std::move(message), *message_dict) : DispatchEvent(std::move(message), *message_dict); if (!success) - DLOG(ERROR) << "Unhandled protocol message: " << json_message; + DVLOG(2) << "Unhandled protocol message: " << json_message; } bool DevtoolsClient::DispatchMessageReply( @@ -192,7 +192,7 @@ EventHandlerMap::const_iterator it = event_handlers_.find(method); if (it == event_handlers_.end()) { if (method != "Inspector.targetCrashed") - LOG(ERROR) << "Unknown event: " << method; + DVLOG(2) << "Unknown event: " << method; return false; } if (!it->second.is_null()) {
diff --git a/components/autofill_assistant/browser/protocol_utils.cc b/components/autofill_assistant/browser/protocol_utils.cc index 5184f25..730e30b 100644 --- a/components/autofill_assistant/browser/protocol_utils.cc +++ b/components/autofill_assistant/browser/protocol_utils.cc
@@ -15,6 +15,7 @@ #include "components/autofill_assistant/browser/actions/select_option_action.h" #include "components/autofill_assistant/browser/actions/stop_action.h" #include "components/autofill_assistant/browser/actions/tell_action.h" +#include "components/autofill_assistant/browser/actions/unsupported_action.h" #include "components/autofill_assistant/browser/actions/upload_dom_action.h" #include "components/autofill_assistant/browser/actions/wait_for_dom_action.h" #include "components/autofill_assistant/browser/service.pb.h" @@ -193,6 +194,7 @@ case ActionProto::ActionInfoCase::ACTION_INFO_NOT_SET: { DLOG(ERROR) << "Unknown or unsupported action with action_case=" << action.action_info_case(); + actions->emplace_back(std::make_unique<UnsupportedAction>(action)); break; } }
diff --git a/components/autofill_assistant/browser/script_executor_unittest.cc b/components/autofill_assistant/browser/script_executor_unittest.cc index fd008540..07539a1 100644 --- a/components/autofill_assistant/browser/script_executor_unittest.cc +++ b/components/autofill_assistant/browser/script_executor_unittest.cc
@@ -162,6 +162,26 @@ EXPECT_EQ(1u, processed_actions2_capture.size()); } +TEST_F(ScriptExecutorTest, UnsupportedAction) { + ActionsResponseProto actions_response; + actions_response.set_server_payload("payload"); + actions_response.add_actions(); // action definition missing + + EXPECT_CALL(mock_service_, OnGetActions(_, _, _)) + .WillOnce(RunOnceCallback<2>(true, Serialize(actions_response))); + + std::vector<ProcessedActionProto> processed_actions_capture; + EXPECT_CALL(mock_service_, OnGetNextActions(_, _, _)) + .WillOnce(DoAll(SaveArg<1>(&processed_actions_capture), + RunOnceCallback<2>(true, ""))); + EXPECT_CALL(executor_callback_, + Run(Field(&ScriptExecutor::Result::success, true))); + executor_->Run(executor_callback_.Get()); + + ASSERT_EQ(1u, processed_actions_capture.size()); + EXPECT_EQ(UNKNOWN_ACTION_STATUS, processed_actions_capture[0].status()); +} + TEST_F(ScriptExecutorTest, StopAfterEnd) { ActionsResponseProto actions_response; actions_response.set_server_payload("payload");
diff --git a/components/autofill_assistant/browser/web_controller.h b/components/autofill_assistant/browser/web_controller.h index c975563..9ba20fa 100644 --- a/components/autofill_assistant/browser/web_controller.h +++ b/components/autofill_assistant/browser/web_controller.h
@@ -35,6 +35,14 @@ class NodeProto; // Controller to interact with the web pages. +// +// WARNING: Accessing or modifying page elements must be run in sequence: wait +// until the result of the first operation has been given to the callback before +// starting a new operation. +// +// TODO(crbug.com/806868): Figure out the reason for this limitation and fix it. +// Also, consider structuring the WebController to make it easier to run +// multiple operations, whether in sequence or in parallel. class WebController { public: // Create web controller for a given |web_contents|.
diff --git a/components/language/android/BUILD.gn b/components/language/android/BUILD.gn index b5a1f19e..e92bf7a 100644 --- a/components/language/android/BUILD.gn +++ b/components/language/android/BUILD.gn
@@ -7,6 +7,7 @@ generate_jni("jni_headers") { sources = [ + "java/src/org/chromium/components/language/AndroidLanguageMetricsBridge.java", "java/src/org/chromium/components/language/GeoLanguageProviderBridge.java", ] jni_package = "components/language" @@ -14,6 +15,7 @@ source_set("language_bridge") { sources = [ + "android_language_metrics_bridge.cc", "geo_language_provider_bridge.cc", ] deps = [ @@ -25,6 +27,7 @@ android_library("language_bridge_java") { java_files = [ + "java/src/org/chromium/components/language/AndroidLanguageMetricsBridge.java", "java/src/org/chromium/components/language/GeoLanguageProviderBridge.java", ]
diff --git a/components/language/android/android_language_metrics_bridge.cc b/components/language/android/android_language_metrics_bridge.cc new file mode 100644 index 0000000..745c6437 --- /dev/null +++ b/components/language/android/android_language_metrics_bridge.cc
@@ -0,0 +1,27 @@ +// 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 "base/metrics/histogram_functions.h" +#include "base/metrics/metrics_hashes.h" +#include "jni/AndroidLanguageMetricsBridge_jni.h" + +const char kTranslateExplicitLanguageAskLanguageAdded[] = + "Translate.ExplicitLanguageAsk.LanguageAdded"; +const char kTranslateExplicitLanguageAskLanguageRemoved[] = + "Translate.ExplicitLanguageAsk.LanguageRemoved"; + +// Called when a user adds or removes a language from the list of languages they +// can read using the Explicit Language Ask prompt at 2nd run. +static void +JNI_AndroidLanguageMetricsBridge_ReportExplicitLanguageAskStateChanged( + JNIEnv* env, + const base::android::JavaParamRef<jclass>& jcaller, + const base::android::JavaParamRef<jstring>& language, + const jboolean added) { + base::UmaHistogramSparse( + added ? kTranslateExplicitLanguageAskLanguageAdded + : kTranslateExplicitLanguageAskLanguageRemoved, + base::HashMetricName(base::android::ConvertJavaStringToUTF8(language))); +}
diff --git a/components/language/android/java/src/org/chromium/components/language/AndroidLanguageMetricsBridge.java b/components/language/android/java/src/org/chromium/components/language/AndroidLanguageMetricsBridge.java new file mode 100644 index 0000000..da83a63 --- /dev/null +++ b/components/language/android/java/src/org/chromium/components/language/AndroidLanguageMetricsBridge.java
@@ -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. + +package org.chromium.components.language; + +/** + * A bridge to language metrics functions that require access to native code. + */ +public class AndroidLanguageMetricsBridge { + /** + * Called when a user adds or removes a language from the list of languages they + * can read using the Explicit Language Ask prompt at 2nd run. + * @param language The language code that was added or removed from the list. + * @param added True if the language was added, false if it was removed. + */ + public static void reportExplicitLanguageAskStateChanged(String language, boolean added) { + nativeReportExplicitLanguageAskStateChanged(language, added); + } + + private static native void nativeReportExplicitLanguageAskStateChanged( + String language, boolean added); +}
diff --git a/components/language/core/browser/BUILD.gn b/components/language/core/browser/BUILD.gn index f0c1586..02acc883 100644 --- a/components/language/core/browser/BUILD.gn +++ b/components/language/core/browser/BUILD.gn
@@ -12,6 +12,8 @@ "language_model.h", "language_model_manager.cc", "language_model_manager.h", + "locale_util.cc", + "locale_util.h", "pref_names.cc", "pref_names.h", "url_language_histogram.cc", @@ -23,6 +25,7 @@ "//components/keyed_service/core", "//components/pref_registry", "//components/prefs", + "//ui/base", ] }
diff --git a/components/language/core/browser/DEPS b/components/language/core/browser/DEPS index f0bf3d9..c8264406 100644 --- a/components/language/core/browser/DEPS +++ b/components/language/core/browser/DEPS
@@ -1,3 +1,4 @@ include_rules = [ "+components/keyed_service/core", + "+ui/base/l10n", ]
diff --git a/components/language/core/browser/locale_util.cc b/components/language/core/browser/locale_util.cc new file mode 100644 index 0000000..a0f66d6a --- /dev/null +++ b/components/language/core/browser/locale_util.cc
@@ -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. + +#include "components/language/core/browser/locale_util.h" + +#include "components/language/core/browser/pref_names.h" +#include "components/prefs/pref_service.h" +#include "ui/base/l10n/l10n_util.h" + +namespace language { + +std::string GetApplicationLocale(PrefService* local_state) { + if (!local_state->HasPrefPath(prefs::kApplicationLocale)) + return std::string(); + std::string locale = local_state->GetString(prefs::kApplicationLocale); + return l10n_util::GetApplicationLocale(locale); +} + +} // namespace language
diff --git a/components/language/core/browser/locale_util.h b/components/language/core/browser/locale_util.h new file mode 100644 index 0000000..a234303 --- /dev/null +++ b/components/language/core/browser/locale_util.h
@@ -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. + +#ifndef COMPONENTS_LANGUAGE_CORE_BROWSER_LOCALE_UTIL_H_ +#define COMPONENTS_LANGUAGE_CORE_BROWSER_LOCALE_UTIL_H_ + +#include <string> + +class PrefService; + +namespace language { + +// Returns the current application locale (e.g. "en-US"). +std::string GetApplicationLocale(PrefService* local_state); + +} // namespace language + +#endif // COMPONENTS_LANGUAGE_CORE_BROWSER_LOCALE_UTIL_H_
diff --git a/components/password_manager/core/browser/form_parsing/form_parser.cc b/components/password_manager/core/browser/form_parsing/form_parser.cc index 9c7f868..d0cd6d50 100644 --- a/components/password_manager/core/browser/form_parsing/form_parser.cc +++ b/components/password_manager/core/browser/form_parsing/form_parser.cc
@@ -272,7 +272,7 @@ // |first_relevant_password|. std::vector<const FormFieldData*> GetRelevantPasswords( const std::vector<ProcessedField>& processed_fields, - FormParsingMode mode, + FormDataParser::Mode mode, Interactability best_interactability, std::vector<ProcessedField>::const_iterator* first_relevant_password) { DCHECK(first_relevant_password); @@ -280,7 +280,7 @@ std::vector<const FormFieldData*> result; result.reserve(processed_fields.size()); - const bool consider_only_non_empty = mode == FormParsingMode::SAVING; + const bool consider_only_non_empty = mode == FormDataParser::Mode::kSaving; for (auto it = processed_fields.begin(); it != processed_fields.end(); ++it) { const ProcessedField& processed_field = *it; @@ -384,12 +384,12 @@ const FormFieldData* FindUsernameFieldBaseHeuristics( const std::vector<ProcessedField>& processed_fields, const std::vector<ProcessedField>::const_iterator& first_relevant_password, - FormParsingMode mode, + FormDataParser::Mode mode, Interactability best_interactability) { DCHECK(first_relevant_password != processed_fields.end()); // For saving filter out empty fields. - const bool consider_only_non_empty = mode == FormParsingMode::SAVING; + const bool consider_only_non_empty = mode == FormDataParser::Mode::kSaving; // Search through the text input fields preceding |first_relevant_password| // and find the closest one focusable and the closest one in general. @@ -435,7 +435,7 @@ // kinds of analysis. void ParseUsingBaseHeuristics( const std::vector<ProcessedField>& processed_fields, - FormParsingMode mode, + FormDataParser::Mode mode, SignificantFields* found_fields, Interactability* username_max) { // If there is both the username and the minimal set of fields to build a @@ -633,7 +633,7 @@ // |form_predictions| has |may_use_prefilled_placeholder| == true for the // username field. bool GetMayUsePrefilledPlaceholder( - const FormPredictions* form_predictions, + const base::Optional<FormPredictions>& form_predictions, const SignificantFields& significant_fields) { if (!form_predictions || !significant_fields.username) return false; @@ -658,7 +658,7 @@ const SignificantFields& significant_fields, autofill::ValueElementVector all_possible_passwords, autofill::ValueElementVector all_possible_usernames, - const FormPredictions* form_predictions) { + const base::Optional<FormPredictions>& form_predictions) { if (!significant_fields.HasPasswords()) return nullptr; @@ -686,10 +686,13 @@ } // namespace -std::unique_ptr<PasswordForm> ParseFormData( +FormDataParser::FormDataParser() = default; + +FormDataParser::~FormDataParser() = default; + +std::unique_ptr<PasswordForm> FormDataParser::Parse( const autofill::FormData& form_data, - const FormPredictions* form_predictions, - FormParsingMode mode) { + Mode mode) { autofill::ValueElementVector all_possible_passwords; autofill::ValueElementVector all_possible_usernames; std::vector<ProcessedField> processed_fields = ProcessFields( @@ -703,9 +706,8 @@ UsernameDetectionMethod::kNoUsernameDetected; // (1) First, try to parse with server predictions. - if (form_predictions) { - significant_fields = - ParseUsingPredictions(processed_fields, *form_predictions); + if (predictions_) { + significant_fields = ParseUsingPredictions(processed_fields, *predictions_); if (significant_fields && significant_fields->username) { username_detection_method = UsernameDetectionMethod::kServerSidePrediction; @@ -747,7 +749,7 @@ const FormFieldData* username_field_by_context = FindUsernameInPredictions( form_data.username_predictions, processed_fields, username_max); if (username_field_by_context && - !(mode == FormParsingMode::SAVING && + !(mode == FormDataParser::Mode::kSaving && username_field_by_context->value.empty())) { significant_fields->username = username_field_by_context; if (username_detection_method == @@ -764,9 +766,9 @@ username_detection_method, UsernameDetectionMethod::kCount); - return AssemblePasswordForm( - form_data, *significant_fields, std::move(all_possible_passwords), - std::move(all_possible_usernames), form_predictions); + return AssemblePasswordForm(form_data, *significant_fields, + std::move(all_possible_passwords), + std::move(all_possible_usernames), predictions_); } std::string GetSignonRealm(const GURL& url) {
diff --git a/components/password_manager/core/browser/form_parsing/form_parser.h b/components/password_manager/core/browser/form_parsing/form_parser.h index 39699b2d..6a997133 100644 --- a/components/password_manager/core/browser/form_parsing/form_parser.h +++ b/components/password_manager/core/browser/form_parsing/form_parser.h
@@ -6,8 +6,11 @@ #define COMPONENTS_PASSWORD_MANAGER_CORE_BROWSER_FORM_PARSING_FORM_PARSER_H_ #include <memory> +#include <utility> #include <vector> +#include "base/macros.h" +#include "base/optional.h" #include "components/password_manager/core/browser/form_parsing/password_field_prediction.h" #include "url/gurl.h" @@ -18,29 +21,51 @@ namespace password_manager { -enum class FormParsingMode { FILLING, SAVING }; +// This class takes care of parsing FormData into PasswordForm and managing +// related metadata. +class FormDataParser { + public: + // Denotes the intended use of the result (for filling forms vs. saving + // captured credentials). This influences whether empty fields are ignored. + enum class Mode { kFilling, kSaving }; -// This needs to be in sync with the histogram enumeration -// UsernameDetectionMethod, because the values are reported in the -// "PasswordManager.UsernameDetectionMethod" histogram. Don't remove or shift -// existing values in the enum, only append and mark as obsolete as needed. -enum class UsernameDetectionMethod { - kNoUsernameDetected = 0, - kBaseHeuristic = 1, - kHtmlBasedClassifier = 2, - kAutocompleteAttribute = 3, - kServerSidePrediction = 4, - kCount + // This needs to be in sync with the histogram enumeration + // UsernameDetectionMethod, because the values are reported in the + // "PasswordManager.UsernameDetectionMethod" histogram. Don't remove or shift + // existing values in the enum, only append and mark as obsolete as needed. + enum class UsernameDetectionMethod { + kNoUsernameDetected = 0, + kBaseHeuristic = 1, + kHtmlBasedClassifier = 2, + kAutocompleteAttribute = 3, + kServerSidePrediction = 4, + kCount + }; + + FormDataParser(); + + ~FormDataParser(); + + void set_predictions(FormPredictions predictions) { + predictions_ = std::move(predictions); + } + + const base::Optional<FormPredictions>& predictions() { return predictions_; } + + // Parse DOM information |form_data| into Password Manager's form + // representation PasswordForm. Return nullptr when parsing is unsuccessful. + std::unique_ptr<autofill::PasswordForm> Parse( + const autofill::FormData& form_data, + Mode mode); + + private: + // Predictions are an optional source of server-side information about field + // types. + base::Optional<FormPredictions> predictions_; + + DISALLOW_COPY_AND_ASSIGN(FormDataParser); }; -// Parse DOM information |form_data| into Password Manager's form representation -// PasswordForm. |form_predictions| are an optional source of server-side -// predictions about field types. Return nullptr when parsing is unsuccessful. -std::unique_ptr<autofill::PasswordForm> ParseFormData( - const autofill::FormData& form_data, - const FormPredictions* form_predictions, - FormParsingMode mode); - // Returns the value of PasswordForm::signon_realm for an HTML form with the // origin |url|. std::string GetSignonRealm(const GURL& url);
diff --git a/components/password_manager/core/browser/form_parsing/form_parser_unittest.cc b/components/password_manager/core/browser/form_parsing/form_parser_unittest.cc index a1d251c..c53f605 100644 --- a/components/password_manager/core/browser/form_parsing/form_parser_unittest.cc +++ b/components/password_manager/core/browser/form_parsing/form_parser_unittest.cc
@@ -8,6 +8,7 @@ #include <algorithm> #include <set> +#include <utility> #include "base/strings/string16.h" #include "base/strings/string_number_conversions.h" @@ -31,14 +32,16 @@ namespace { +using UsernameDetectionMethod = FormDataParser::UsernameDetectionMethod; + // Use this value in FieldDataDescription.value to get an arbitrary unique value // generated in GetFormDataAndExpectation(). constexpr char kNonimportantValue[] = "non-important unique"; // Use this in FieldDataDescription below to mark the expected username and -// password fields. The *_FILLING variants apply to FormParsingMode::FILLING -// only, the *_SAVING variants to FormParsingMode::SAVING only, the suffix-less -// variants to both. +// password fields. The *_FILLING variants apply to +// FormDataParser::Mode::kFilling only, the *_SAVING variants to +// FormDataParser::Mode::kSaving only, the suffix-less variants to both. enum class ElementRole { NONE, USERNAME_FILLING, @@ -303,17 +306,19 @@ ParseResultIds save_result; const FormData form_data = GetFormDataAndExpectation( test_case.fields, &predictions, &fill_result, &save_result); - for (auto mode : {FormParsingMode::FILLING, FormParsingMode::SAVING}) { + FormDataParser parser; + parser.set_predictions(std::move(predictions)); + for (auto mode : + {FormDataParser::Mode::kFilling, FormDataParser::Mode::kSaving}) { SCOPED_TRACE( testing::Message("Test description: ") << test_case.description_for_logging << ", parsing mode = " - << (mode == FormParsingMode::FILLING ? "Filling" : "Saving")); + << (mode == FormDataParser::Mode::kFilling ? "Filling" : "Saving")); - std::unique_ptr<PasswordForm> parsed_form = - ParseFormData(form_data, &predictions, mode); + std::unique_ptr<PasswordForm> parsed_form = parser.Parse(form_data, mode); const ParseResultIds& expected_ids = - mode == FormParsingMode::FILLING ? fill_result : save_result; + mode == FormDataParser::Mode::kFilling ? fill_result : save_result; if (expected_ids.IsEmpty()) { EXPECT_FALSE(parsed_form) << "Expected no parsed results";
diff --git a/components/password_manager/core/browser/form_parsing/fuzzer/form_parser_generic_fuzzer.cc b/components/password_manager/core/browser/form_parsing/fuzzer/form_parser_generic_fuzzer.cc index eb97633..81dc4fb 100644 --- a/components/password_manager/core/browser/form_parsing/fuzzer/form_parser_generic_fuzzer.cc +++ b/components/password_manager/core/browser/form_parsing/fuzzer/form_parser_generic_fuzzer.cc
@@ -27,12 +27,14 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { DataAccessor accessor(data, size); - FormParsingMode mode = accessor.ConsumeBit() ? FormParsingMode::FILLING - : FormParsingMode::SAVING; + FormDataParser::Mode mode = accessor.ConsumeBit() + ? FormDataParser::Mode::kFilling + : FormDataParser::Mode::kSaving; autofill::FormData form_data = GenerateWithDataAccessor(&accessor); + FormDataParser parser; std::unique_ptr<autofill::PasswordForm> result = - ParseFormData(form_data, nullptr, mode); + parser.Parse(form_data, mode); if (result) { // Create a copy of the result -- running the copy-constructor might // discover some invalid data in |result|.
diff --git a/components/password_manager/core/browser/form_parsing/fuzzer/form_parser_proto_generic_fuzzer.cc b/components/password_manager/core/browser/form_parsing/fuzzer/form_parser_proto_generic_fuzzer.cc index b02e04b..7d2508a 100644 --- a/components/password_manager/core/browser/form_parsing/fuzzer/form_parser_proto_generic_fuzzer.cc +++ b/components/password_manager/core/browser/form_parsing/fuzzer/form_parser_proto_generic_fuzzer.cc
@@ -27,12 +27,14 @@ IcuEnvironment* env = new IcuEnvironment(); DEFINE_BINARY_PROTO_FUZZER(const ::form_data_fuzzer::Form& form_proto) { - FormParsingMode mode = form_proto.is_mode_filling() ? FormParsingMode::FILLING - : FormParsingMode::SAVING; + FormDataParser::Mode mode = form_proto.is_mode_filling() + ? FormDataParser::Mode::kFilling + : FormDataParser::Mode::kSaving; autofill::FormData form_data = GenerateWithProto(form_proto); + FormDataParser parser; std::unique_ptr<autofill::PasswordForm> result = - ParseFormData(form_data, nullptr, mode); + parser.Parse(form_data, mode); if (result) { // Create a copy of the result -- running the copy-constructor might // discover some invalid data in |result|.
diff --git a/components/password_manager/core/browser/new_password_form_manager.cc b/components/password_manager/core/browser/new_password_form_manager.cc index 7b87df9..e7b4e95 100644 --- a/components/password_manager/core/browser/new_password_form_manager.cc +++ b/components/password_manager/core/browser/new_password_form_manager.cc
@@ -12,7 +12,6 @@ #include "components/password_manager/core/browser/android_affiliation/affiliation_utils.h" #include "components/password_manager/core/browser/browser_save_password_progress_logger.h" #include "components/password_manager/core/browser/form_fetcher_impl.h" -#include "components/password_manager/core/browser/form_parsing/form_parser.h" #include "components/password_manager/core/browser/form_saver.h" #include "components/password_manager/core/browser/password_form_filling.h" #include "components/password_manager/core/browser/password_manager_client.h" @@ -39,26 +38,6 @@ constexpr TimeDelta kMaxFillingDelayForServerPredictions = TimeDelta::FromMilliseconds(500); -// Helper function for calling form parsing and logging results if logging is -// active. -std::unique_ptr<PasswordForm> ParseFormAndMakeLogging( - PasswordManagerClient* client, - const FormData& form, - const base::Optional<FormPredictions>& predictions, - FormParsingMode mode) { - std::unique_ptr<PasswordForm> password_form = - ParseFormData(form, predictions ? &predictions.value() : nullptr, mode); - - if (password_manager_util::IsLoggingActive(client)) { - BrowserSavePasswordProgressLogger logger(client->GetLogManager()); - logger.LogFormData(Logger::STRING_FORM_PARSING_INPUT, form); - if (password_form) - logger.LogPasswordForm(Logger::STRING_FORM_PARSING_OUTPUT, - *password_form); - } - return password_form; -} - ValueElementPair PasswordToSave(const PasswordForm& form) { if (form.new_password_element.empty() || form.new_password_value.empty()) return {form.password_value, form.password_element}; @@ -150,8 +129,7 @@ // TODO(https://crbug.com/831123): remove it when NewPasswordFormManager will // be production ready. if (password_manager_util::IsLoggingActive(client_)) - ParseFormAndMakeLogging(client_, observed_form_, predictions_, - FormParsingMode::FILLING); + ParseFormAndMakeLogging(observed_form_, FormDataParser::Mode::kFilling); } NewPasswordFormManager::~NewPasswordFormManager() = default; @@ -375,7 +353,8 @@ result->has_generated_password_ = has_generated_password_; result->user_action_ = user_action_; result->votes_uploader_ = votes_uploader_; - result->predictions_ = predictions_; + if (parser_.predictions()) + result->parser_.set_predictions(*parser_.predictions()); return result; } @@ -405,7 +384,7 @@ autofills_left_ = kMaxTimesAutofill; - if (predictions_ || !wait_for_server_predictions_for_filling_) { + if (parser_.predictions() || !wait_for_server_predictions_for_filling_) { ReportTimeBetweenStoreAndServerUMA(); Fill(); } else { @@ -424,8 +403,8 @@ return false; submitted_form_ = submitted_form; is_submitted_ = true; - parsed_submitted_form_ = ParseFormAndMakeLogging( - client_, submitted_form_, predictions_, FormParsingMode::SAVING); + parsed_submitted_form_ = + ParseFormAndMakeLogging(submitted_form_, FormDataParser::Mode::kSaving); CreatePendingCredentials(); return true; } @@ -438,7 +417,7 @@ if (form_predictions->form_signature() != observed_form_signature) continue; ReportTimeBetweenStoreAndServerUMA(); - predictions_ = ConvertToFormPredictions(*form_predictions); + parser_.set_predictions(ConvertToFormPredictions(*form_predictions)); Fill(); break; } @@ -453,8 +432,7 @@ // filling and saving mode might be different so it is better not to cache // parse result, but to parse each time again. std::unique_ptr<PasswordForm> observed_password_form = - ParseFormAndMakeLogging(client_, observed_form_, predictions_, - FormParsingMode::FILLING); + ParseFormAndMakeLogging(observed_form_, FormDataParser::Mode::kFilling); if (!observed_password_form) return; @@ -737,8 +715,8 @@ SetUserAction(UserAction::kOverrideUsernameAndPassword); // TODO(https://crbug.com/831123): Replace parsing of the observed form with // usage of already parsed submitted form. - std::unique_ptr<PasswordForm> parsed_observed_form = ParseFormAndMakeLogging( - client_, observed_form_, predictions_, FormParsingMode::FILLING); + std::unique_ptr<PasswordForm> parsed_observed_form = + ParseFormAndMakeLogging(observed_form_, FormDataParser::Mode::kFilling); if (!parsed_observed_form) return; pending_credentials_ = *parsed_observed_form; @@ -817,4 +795,19 @@ return credentials_to_update; } +std::unique_ptr<PasswordForm> NewPasswordFormManager::ParseFormAndMakeLogging( + const FormData& form, + FormDataParser::Mode mode) { + std::unique_ptr<PasswordForm> password_form = parser_.Parse(form, mode); + + if (password_manager_util::IsLoggingActive(client_)) { + BrowserSavePasswordProgressLogger logger(client_->GetLogManager()); + logger.LogFormData(Logger::STRING_FORM_PARSING_INPUT, form); + if (password_form) + logger.LogPasswordForm(Logger::STRING_FORM_PARSING_OUTPUT, + *password_form); + } + return password_form; +} + } // namespace password_manager
diff --git a/components/password_manager/core/browser/new_password_form_manager.h b/components/password_manager/core/browser/new_password_form_manager.h index 9409dc5..da80add9 100644 --- a/components/password_manager/core/browser/new_password_form_manager.h +++ b/components/password_manager/core/browser/new_password_form_manager.h
@@ -11,11 +11,11 @@ #include "base/macros.h" #include "base/memory/scoped_refptr.h" #include "base/memory/weak_ptr.h" -#include "base/optional.h" #include "base/strings/utf_string_conversions.h" #include "base/time/time.h" #include "components/autofill/core/common/form_data.h" #include "components/password_manager/core/browser/form_fetcher.h" +#include "components/password_manager/core/browser/form_parsing/form_parser.h" #include "components/password_manager/core/browser/form_parsing/password_field_prediction.h" #include "components/password_manager/core/browser/password_form_manager_for_ui.h" #include "components/password_manager/core/browser/password_form_metrics_recorder.h" @@ -203,6 +203,12 @@ // credentials. std::vector<autofill::PasswordForm> FindOtherCredentialsToUpdate(); + // Helper function for calling form parsing and logging results if logging is + // active. + std::unique_ptr<autofill::PasswordForm> ParseFormAndMakeLogging( + const autofill::FormData& form, + FormDataParser::Mode mode); + // The client which implements embedder-specific PasswordManager operations. PasswordManagerClient* client_; @@ -289,8 +295,6 @@ // form. UserAction user_action_ = UserAction::kNone; - base::Optional<FormPredictions> predictions_; - // If Chrome has already autofilled a few times, it is probable that autofill // is triggered by programmatic changes in the page. We set a maximum number // of times that Chrome will autofill to avoid being stuck in an infinite @@ -308,6 +312,9 @@ // Time when stored credentials are received from the store. Used for metrics. base::TimeTicks received_stored_credentials_time_; + // Used to transform FormData into PasswordForms. + FormDataParser parser_; + base::WeakPtrFactory<NewPasswordFormManager> weak_ptr_factory_; DISALLOW_COPY_AND_ASSIGN(NewPasswordFormManager);
diff --git a/components/password_manager/core/browser/new_password_form_manager_unittest.cc b/components/password_manager/core/browser/new_password_form_manager_unittest.cc index 27669e1..7facc82c 100644 --- a/components/password_manager/core/browser/new_password_form_manager_unittest.cc +++ b/components/password_manager/core/browser/new_password_form_manager_unittest.cc
@@ -97,10 +97,6 @@ DISALLOW_COPY_AND_ASSIGN(MockFormSaver); }; -std::string GetSignonRealm(GURL origin) { - return origin.GetOrigin().spec(); -} - } // namespace // TODO(https://crbug.com/831123): Test sending metrics.
diff --git a/components/signin/core/browser/fake_profile_oauth2_token_service.cc b/components/signin/core/browser/fake_profile_oauth2_token_service.cc index 6df96dc..3696b80 100644 --- a/components/signin/core/browser/fake_profile_oauth2_token_service.cc +++ b/components/signin/core/browser/fake_profile_oauth2_token_service.cc
@@ -71,6 +71,14 @@ access_token, expiration, std::string() /* id_token */)); } +void FakeProfileOAuth2TokenService::IssueTokenForScope( + const ScopeSet& scope, + const OAuth2AccessTokenConsumer::TokenResponse& token_response) { + DCHECK(!auto_post_fetch_response_on_message_loop_); + CompleteRequests("", false, scope, GoogleServiceAuthError::AuthErrorNone(), + token_response); +} + void FakeProfileOAuth2TokenService::IssueErrorForScope( const ScopeSet& scope, const GoogleServiceAuthError& error) { @@ -96,6 +104,13 @@ access_token, expiration, std::string() /* id_token */)); } +void FakeProfileOAuth2TokenService::IssueTokenForAllPendingRequests( + const OAuth2AccessTokenConsumer::TokenResponse& token_response) { + DCHECK(!auto_post_fetch_response_on_message_loop_); + CompleteRequests("", true, ScopeSet(), + GoogleServiceAuthError::AuthErrorNone(), token_response); +} + void FakeProfileOAuth2TokenService::UpdateAuthErrorForTesting( const std::string& account_id, const GoogleServiceAuthError& error) {
diff --git a/components/signin/core/browser/fake_profile_oauth2_token_service.h b/components/signin/core/browser/fake_profile_oauth2_token_service.h index ec9dcf6..f7cc8448 100644 --- a/components/signin/core/browser/fake_profile_oauth2_token_service.h +++ b/components/signin/core/browser/fake_profile_oauth2_token_service.h
@@ -75,12 +75,19 @@ const std::string& access_token, const base::Time& expiration); + void IssueTokenForScope( + const ScopeSet& scopes, + const OAuth2AccessTokenConsumer::TokenResponse& token_response); + void IssueErrorForScope(const ScopeSet& scopes, const GoogleServiceAuthError& error); void IssueTokenForAllPendingRequests(const std::string& access_token, const base::Time& expiration); + void IssueTokenForAllPendingRequests( + const OAuth2AccessTokenConsumer::TokenResponse& token_response); + void IssueErrorForAllPendingRequests(const GoogleServiceAuthError& error); void set_auto_post_fetch_response_on_message_loop(bool auto_post_response) {
diff --git a/components/signin/core/browser/gaia_cookie_manager_service_unittest.cc b/components/signin/core/browser/gaia_cookie_manager_service_unittest.cc index 0b3be2b..4d3f5e9 100644 --- a/components/signin/core/browser/gaia_cookie_manager_service_unittest.cc +++ b/components/signin/core/browser/gaia_cookie_manager_service_unittest.cc
@@ -474,6 +474,7 @@ std::string data = R"()]}' { + "status": "OK", "cookies":[ { "name":"SID", @@ -488,8 +489,10 @@ ] } )"; - ASSERT_TRUE(OAuthMultiloginResult::CreateOAuthMultiloginResultFromString( - data, &result)); + ASSERT_EQ(OAuthMultiloginResult::CreateOAuthMultiloginResultFromString( + data, &result) + .state(), + GoogleServiceAuthError::State::NONE); testing::InSequence mock_sequence; EXPECT_CALL(helper, StartFetchingAccessToken(account_id1)).Times(1); @@ -552,6 +555,7 @@ std::string data = R"()]}' { + "status": "OK", "cookies":[ { "name":"SID", @@ -586,8 +590,10 @@ ] } )"; - ASSERT_TRUE(OAuthMultiloginResult::CreateOAuthMultiloginResultFromString( - data, &result)); + ASSERT_EQ(OAuthMultiloginResult::CreateOAuthMultiloginResultFromString( + data, &result) + .state(), + GoogleServiceAuthError::State::NONE); testing::InSequence mock_sequence; EXPECT_CALL(helper, StartFetchingAccessToken(account_id1)).Times(1);
diff --git a/components/sync/BUILD.gn b/components/sync/BUILD.gn index 1ed14318..fcdefffa 100644 --- a/components/sync/BUILD.gn +++ b/components/sync/BUILD.gn
@@ -215,6 +215,7 @@ "engine/polling_constants.h", "engine/sequenced_model_worker.cc", "engine/sequenced_model_worker.h", + "engine/shutdown_reason.cc", "engine/shutdown_reason.h", "engine/sync_auth_provider.h", "engine/sync_backend_registrar.cc",
diff --git a/components/sync/driver/about_sync_util.cc b/components/sync/driver/about_sync_util.cc index 07d27b4..d954b8b 100644 --- a/components/sync/driver/about_sync_util.cc +++ b/components/sync/driver/about_sync_util.cc
@@ -313,6 +313,8 @@ section_summary->AddStringStat("Disable Reasons"); Stat<bool>* feature_enabled = section_summary->AddBoolStat("Sync Feature Enabled"); + Stat<bool>* setup_in_progress = + section_summary->AddBoolStat("Setup In Progress"); Section* section_version = section_list.AddSection("Version Info"); Stat<std::string>* client_version = @@ -326,14 +328,15 @@ Stat<std::string>* invalidator_id = section_identity->AddStringStat("Invalidator Client ID"); Stat<std::string>* username = section_identity->AddStringStat("Username"); + Stat<bool>* user_is_primary = section_identity->AddBoolStat("Is Primary"); Section* section_credentials = section_list.AddSection("Credentials"); Stat<std::string>* request_token_time = section_credentials->AddStringStat("Requested Token"); Stat<std::string>* receive_token_time = section_credentials->AddStringStat("Received Token"); - Stat<std::string>* token_request_status = - section_credentials->AddStringStat("Token Request Status"); + Stat<std::string>* last_token_request_result = + section_credentials->AddStringStat("Last Token Request Result"); Stat<std::string>* next_token_request = section_credentials->AddStringStat("Next Token Request"); @@ -444,6 +447,7 @@ transport_state->Set(GetTransportStateString(service->GetTransportState())); disable_reasons->Set(GetDisableReasonsString(service->GetDisableReasons())); feature_enabled->Set(service->IsSyncFeatureEnabled()); + setup_in_progress->Set(service->IsSetupInProgress()); SyncStatus full_status; bool is_status_valid = service->QueryDetailedSyncStatus(&full_status); @@ -460,12 +464,13 @@ if (is_status_valid && !full_status.invalidator_client_id.empty()) invalidator_id->Set(full_status.invalidator_client_id); username->Set(service->GetAuthenticatedAccountInfo().email); + user_is_primary->Set(service->IsAuthenticatedAccountPrimary()); // Credentials. request_token_time->Set(GetTimeStr(token_status.token_request_time, "n/a")); receive_token_time->Set(GetTimeStr(token_status.token_receive_time, "n/a")); std::string err = token_status.last_get_token_error.error_message(); - token_request_status->Set(err.empty() ? "OK" : err); + last_token_request_result->Set(err.empty() ? "OK" : err); next_token_request->Set( GetTimeStr(token_status.next_token_request_time, "not scheduled"));
diff --git a/components/sync/driver/data_type_manager_impl.cc b/components/sync/driver/data_type_manager_impl.cc index 17d54b6..d93ddfa 100644 --- a/components/sync/driver/data_type_manager_impl.cc +++ b/components/sync/driver/data_type_manager_impl.cc
@@ -303,7 +303,7 @@ // If we're performing a "catch up", first stop the model types to ensure the // call to Initialize triggers model association. if (catch_up_in_progress_) - model_association_manager_.Stop(KEEP_METADATA); + model_association_manager_.Stop(STOP_SYNC); download_started_ = false; model_association_manager_.Initialize( /*desired_types=*/last_enabled_types_, @@ -794,21 +794,9 @@ // Invalidate weak pointer to drop download callbacks. weak_ptr_factory_.InvalidateWeakPtrs(); - // Leave metadata If we do not disable sync completely. - SyncStopMetadataFate metadata_fate = KEEP_METADATA; - switch (reason) { - case STOP_SYNC: - break; - case DISABLE_SYNC: - metadata_fate = CLEAR_METADATA; - break; - case BROWSER_SHUTDOWN: - break; - } - // Stop all data types. This may trigger association callback but the // callback will do nothing because state is set to STOPPING above. - model_association_manager_.Stop(metadata_fate); + model_association_manager_.Stop(reason); // Individual data type controllers might still be STOPPING, but we don't // reflect that in |state_| because, for all practical matters, the manager is
diff --git a/components/sync/driver/model_association_manager.cc b/components/sync/driver/model_association_manager.cc index 99bb800..7691ddc 100644 --- a/components/sync/driver/model_association_manager.cc +++ b/components/sync/driver/model_association_manager.cc
@@ -16,6 +16,7 @@ #include "base/metrics/histogram_macros.h" #include "base/trace_event/trace_event.h" #include "components/sync/base/model_type.h" +#include "components/sync/base/sync_stop_metadata_fate.h" #include "components/sync/model/sync_merge_result.h" namespace syncer { @@ -110,6 +111,9 @@ // |desired_types| must be a subset of |preferred_types|. DCHECK(preferred_types.HasAll(desired_types)); + bool storage_option_changed = + configure_context_.storage_option != context.storage_option; + configure_context_ = context; // Only keep types that have controllers. @@ -126,18 +130,23 @@ notified_about_ready_for_configure_ = false; DVLOG(1) << "ModelAssociationManager: Stopping disabled types."; - std::map<DataTypeController*, SyncStopMetadataFate> types_to_stop; + std::map<DataTypeController*, ShutdownReason> types_to_stop; for (const auto& type_and_dtc : *controllers_) { DataTypeController* dtc = type_and_dtc.second.get(); - // We stop a datatype if it's not desired. Independently of being desired, - // if the datatype is already STOPPING, we also wait for it to stop, to make + // We generally stop all data types which are not desired. When the storage + // option changes, we need to restart all data types so that they can + // re-wire to the correct storage. + bool should_stop = + !desired_types_.Has(dtc->type()) || storage_option_changed; + // If the datatype is already STOPPING, we also wait for it to stop, to make // sure it's ready to start again (if appropriate). - if ((dtc->state() != DataTypeController::NOT_RUNNING && - !desired_types_.Has(dtc->type())) || + if ((should_stop && dtc->state() != DataTypeController::NOT_RUNNING) || dtc->state() == DataTypeController::STOPPING) { - const SyncStopMetadataFate metadata_fate = - preferred_types.Has(dtc->type()) ? KEEP_METADATA : CLEAR_METADATA; - types_to_stop[dtc] = metadata_fate; + // Note: STOP_SYNC means we'll keep the Sync data around; DISABLE_SYNC + // means we'll clear it. + const ShutdownReason reason = + preferred_types.Has(dtc->type()) ? STOP_SYNC : DISABLE_SYNC; + types_to_stop[dtc] = reason; } } @@ -149,18 +158,18 @@ base::BindOnce(&ModelAssociationManager::LoadEnabledTypes, weak_ptr_factory_.GetWeakPtr())); - for (const auto& dtc_and_metadata_fate : types_to_stop) { - DataTypeController* dtc = dtc_and_metadata_fate.first; - const SyncStopMetadataFate metadata_fate = dtc_and_metadata_fate.second; - DVLOG(1) << "ModelAssociationManager: stop " << dtc->name() << " with " - << SyncStopMetadataFateToString(metadata_fate); - StopDatatype(SyncError(), metadata_fate, dtc, barrier_closure); + for (const auto& dtc_and_reason : types_to_stop) { + DataTypeController* dtc = dtc_and_reason.first; + const ShutdownReason reason = dtc_and_reason.second; + DVLOG(1) << "ModelAssociationManager: stop " << dtc->name() << " due to " + << ShutdownReasonToString(reason); + StopDatatype(SyncError(), reason, dtc, barrier_closure); } } void ModelAssociationManager::StopDatatype( const SyncError& error, - SyncStopMetadataFate metadata_fate, + ShutdownReason shutdown_reason, DataTypeController* dtc, DataTypeController::StopCallback callback) { loaded_types_.Remove(dtc->type()); @@ -170,6 +179,25 @@ DCHECK(error.IsSet() || (dtc->state() != DataTypeController::NOT_RUNNING)); delegate_->OnSingleDataTypeWillStop(dtc->type(), error); + + // Leave metadata if we do not disable sync completely. + SyncStopMetadataFate metadata_fate = KEEP_METADATA; + switch (shutdown_reason) { + case STOP_SYNC: + // Special case: For AUTOFILL_WALLET_DATA, we want to clear all data even + // when Sync is stopped temporarily. + // TODO(crbug.com/890361): Consider moving this decision into the + // individual controller + if (dtc->type() == AUTOFILL_WALLET_DATA) { + metadata_fate = CLEAR_METADATA; + } + break; + case DISABLE_SYNC: + metadata_fate = CLEAR_METADATA; + break; + case BROWSER_SHUTDOWN: + break; + } dtc->Stop(metadata_fate, std::move(callback)); } @@ -254,7 +282,7 @@ } } -void ModelAssociationManager::Stop(SyncStopMetadataFate metadata_fate) { +void ModelAssociationManager::Stop(ShutdownReason shutdown_reason) { // Ignore callbacks from controllers. weak_ptr_factory_.InvalidateWeakPtrs(); @@ -265,7 +293,7 @@ dtc->state() != DataTypeController::STOPPING) { // We don't really wait until all datatypes have been fully stopped, which // is only required (and in fact waited for) when Initialize() is called. - StopDatatype(SyncError(), metadata_fate, dtc, base::DoNothing()); + StopDatatype(SyncError(), shutdown_reason, dtc, base::DoNothing()); DVLOG(1) << "ModelAssociationManager: Stopped " << dtc->name(); } } @@ -335,8 +363,7 @@ DVLOG(1) << "ModelAssociationManager: Type encountered an error."; desired_types_.Remove(type); DataTypeController* dtc = controllers_->find(type)->second.get(); - StopDatatype(local_merge_result.error(), KEEP_METADATA, dtc, - base::DoNothing()); + StopDatatype(local_merge_result.error(), STOP_SYNC, dtc, base::DoNothing()); NotifyDelegateIfReadyForConfigure(); // Update configuration result. @@ -410,7 +437,7 @@ static_cast<int>(MODEL_TYPE_COUNT)); StopDatatype(SyncError(FROM_HERE, SyncError::DATATYPE_ERROR, "Association timed out.", dtc->type()), - KEEP_METADATA, dtc, base::DoNothing()); + STOP_SYNC, dtc, base::DoNothing()); } }
diff --git a/components/sync/driver/model_association_manager.h b/components/sync/driver/model_association_manager.h index 07dcc5f0..aada6fee 100644 --- a/components/sync/driver/model_association_manager.h +++ b/components/sync/driver/model_association_manager.h
@@ -11,12 +11,12 @@ #include "base/memory/weak_ptr.h" #include "base/timer/timer.h" -#include "components/sync/base/sync_stop_metadata_fate.h" #include "components/sync/base/weak_handle.h" #include "components/sync/driver/configure_context.h" #include "components/sync/driver/data_type_controller.h" #include "components/sync/driver/data_type_manager.h" #include "components/sync/engine/data_type_association_stats.h" +#include "components/sync/engine/shutdown_reason.h" namespace syncer { @@ -94,9 +94,7 @@ const ConfigureContext& context); // Can be called at any time. Synchronously stops all datatypes. - // If |metadata_fate| equals CLEAR_METADATA controllers should clear sync - // metadata. - void Stop(SyncStopMetadataFate metadata_fate); + void Stop(ShutdownReason shutdown_reason); // Should only be called after Initialize to start the actual association. // |types_to_associate| should be subset of |desired_types| in Initialize(). @@ -138,7 +136,7 @@ // A helper to stop an individual datatype. void StopDatatype(const SyncError& error, - SyncStopMetadataFate metadata_fate, + ShutdownReason shutdown_reason, DataTypeController* dtc, DataTypeController::StopCallback callback);
diff --git a/components/sync/driver/model_association_manager_unittest.cc b/components/sync/driver/model_association_manager_unittest.cc index 88f47cc..97c2856 100644 --- a/components/sync/driver/model_association_manager_unittest.cc +++ b/components/sync/driver/model_association_manager_unittest.cc
@@ -120,7 +120,7 @@ EXPECT_EQ(GetController(controllers_, BOOKMARKS)->state(), DataTypeController::ASSOCIATING); - model_association_manager.Stop(KEEP_METADATA); + model_association_manager.Stop(STOP_SYNC); EXPECT_EQ(GetController(controllers_, BOOKMARKS)->state(), DataTypeController::NOT_RUNNING); EXPECT_EQ( @@ -148,7 +148,7 @@ DataTypeController::ASSOCIATING); GetController(controllers_, BOOKMARKS)->FinishStart(DataTypeController::OK); - model_association_manager.Stop(KEEP_METADATA); + model_association_manager.Stop(STOP_SYNC); EXPECT_EQ(GetController(controllers_, BOOKMARKS)->state(), DataTypeController::NOT_RUNNING); EXPECT_EQ( @@ -572,7 +572,7 @@ ASSERT_EQ(GetController(controllers_, BOOKMARKS)->state(), DataTypeController::MODEL_LOADED); - model_association_manager.Stop(CLEAR_METADATA); + model_association_manager.Stop(DISABLE_SYNC); EXPECT_EQ(GetController(controllers_, BOOKMARKS)->state(), DataTypeController::NOT_RUNNING);
diff --git a/components/sync/engine/shutdown_reason.cc b/components/sync/engine/shutdown_reason.cc new file mode 100644 index 0000000..c95f91c --- /dev/null +++ b/components/sync/engine/shutdown_reason.cc
@@ -0,0 +1,25 @@ +// 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/sync/engine/shutdown_reason.h" + +#include "base/logging.h" + +namespace syncer { + +const char* ShutdownReasonToString(ShutdownReason reason) { + switch (reason) { + case STOP_SYNC: + return "STOP_SYNC"; + case DISABLE_SYNC: + return "DISABLE_SYNC"; + case BROWSER_SHUTDOWN: + return "BROWSER_SHUTDOWN"; + } + + NOTREACHED(); + return ""; +} + +} // namespace syncer
diff --git a/components/sync/engine/shutdown_reason.h b/components/sync/engine/shutdown_reason.h index a61be8f..1a3f082 100644 --- a/components/sync/engine/shutdown_reason.h +++ b/components/sync/engine/shutdown_reason.h
@@ -14,6 +14,8 @@ BROWSER_SHUTDOWN, // Browser is closed. }; +const char* ShutdownReasonToString(ShutdownReason reason); + } // namespace syncer #endif // COMPONENTS_SYNC_ENGINE_SHUTDOWN_REASON_H_
diff --git a/components/sync/engine/sync_backend_registrar.cc b/components/sync/engine/sync_backend_registrar.cc index cd1f78d..d4cf2d2 100644 --- a/components/sync/engine/sync_backend_registrar.cc +++ b/components/sync/engine/sync_backend_registrar.cc
@@ -80,8 +80,10 @@ void SyncBackendRegistrar::AddRestoredNonBlockingType(ModelType type) { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); base::AutoLock lock(lock_); - DCHECK(non_blocking_types_.Has(type)); - DCHECK(routing_info_.find(type) == routing_info_.end()); + DCHECK(non_blocking_types_.Has(type)) << syncer::ModelTypeToString(type); + DCHECK(routing_info_.find(type) == routing_info_.end() || + routing_info_[type] == GROUP_NON_BLOCKING) + << syncer::ModelTypeToString(type); routing_info_[type] = GROUP_NON_BLOCKING; last_configured_types_.Put(type); }
diff --git a/components/sync/model_impl/client_tag_based_model_type_processor.cc b/components/sync/model_impl/client_tag_based_model_type_processor.cc index ad090a9..f434a21 100644 --- a/components/sync/model_impl/client_tag_based_model_type_processor.cc +++ b/components/sync/model_impl/client_tag_based_model_type_processor.cc
@@ -133,7 +133,10 @@ } model_type_state_ = batch->GetModelTypeState(); } else { - DCHECK(commit_only_ || batch->TakeAllMetadata().empty()); + // TODO(crbug.com/872360): This DCHECK can currently trigger if the user's + // persisted Sync metadata is in an inconsistent state. + DCHECK(commit_only_ || batch->TakeAllMetadata().empty()) + << ModelTypeToString(type_); // First time syncing; initialize metadata. model_type_state_.mutable_progress_marker()->set_data_type_id( GetSpecificsFieldNumberFromModelType(type_));
diff --git a/components/sync_bookmarks/bookmark_model_merger.cc b/components/sync_bookmarks/bookmark_model_merger.cc index 3c8dde2..aa29578 100644 --- a/components/sync_bookmarks/bookmark_model_merger.cc +++ b/components/sync_bookmarks/bookmark_model_merger.cc
@@ -47,8 +47,6 @@ const char kMobileBookmarksTag[] = "synced_bookmarks"; const char kOtherBookmarksTag[] = "other_bookmarks"; -const char kBookmarksRootId[] = "32904_google_chrome_bookmarks"; - // Heuristic to consider two nodes (local and remote) a match for the purpose of // merging. Two folders match if they have the same title, two bookmarks match // if they have the same title and url. A folder and a bookmark never match. @@ -128,15 +126,9 @@ if (update_entity.is_deleted()) { continue; } - // Permanent nodes should be handled differently. They must be added even - // if they don't have children associated to them because they are the roots - // from which the merge starts. - if (update_entity.parent_id == kBookmarksRootId || - update_entity.parent_id == "0") { - // Make sure permanent node is added if it doesn't exist already. - updates_tree.emplace(&update, std::vector<const UpdateResponseData*>()); - // No need to associate it with its parent (the root node). We start - // merging from permanent nodes. + // No need to associate permanent nodes with their parent (the root node). + // We start merging from the permanent nodes. + if (!update_entity.server_defined_unique_tag.empty()) { continue; } if (!syncer::UniquePosition::FromProto(update_entity.unique_position)
diff --git a/components/sync_bookmarks/bookmark_model_merger_unittest.cc b/components/sync_bookmarks/bookmark_model_merger_unittest.cc index ecc78dc..d0cdad6 100644 --- a/components/sync_bookmarks/bookmark_model_merger_unittest.cc +++ b/components/sync_bookmarks/bookmark_model_merger_unittest.cc
@@ -27,7 +27,6 @@ const char kBookmarkBarId[] = "bookmark_bar_id"; const char kBookmarkBarTag[] = "bookmark_bar"; -const char kBookmarksRootId[] = "32904_google_chrome_bookmarks"; syncer::UpdateResponseData CreateUpdateResponseData( const std::string& server_id, @@ -61,7 +60,6 @@ syncer::UpdateResponseData CreateBookmarkBarNodeUpdateData() { syncer::EntityData data; data.id = kBookmarkBarId; - data.parent_id = kBookmarksRootId; data.server_defined_unique_tag = kBookmarkBarTag; data.specifics.mutable_bookmark();
diff --git a/components/sync_bookmarks/bookmark_model_type_processor_unittest.cc b/components/sync_bookmarks/bookmark_model_type_processor_unittest.cc index 6edcaef..49a0312 100644 --- a/components/sync_bookmarks/bookmark_model_type_processor_unittest.cc +++ b/components/sync_bookmarks/bookmark_model_type_processor_unittest.cc
@@ -31,7 +31,7 @@ const char kBookmarkBarTag[] = "bookmark_bar"; const char kBookmarkBarId[] = "bookmark_bar_id"; -const char kBookmarksRootId[] = "32904_google_chrome_bookmarks"; +const char kBookmarksRootId[] = "root_id"; const char kCacheGuid[] = "generated_id"; struct BookmarkInfo {
diff --git a/components/sync_bookmarks/bookmark_remote_updates_handler.cc b/components/sync_bookmarks/bookmark_remote_updates_handler.cc index 8e24310d..28c9f4a 100644 --- a/components/sync_bookmarks/bookmark_remote_updates_handler.cc +++ b/components/sync_bookmarks/bookmark_remote_updates_handler.cc
@@ -22,10 +22,6 @@ namespace { -// Id is created by concatenating the specifics field number and the server tag -// similar to LookbackServerEntity::CreateId() that uses -// GetSpecificsFieldNumberFromModelType() to compute the field number. -const char kBookmarksRootId[] = "32904_google_chrome_bookmarks"; const char kMobileBookmarksTag[] = "synced_bookmarks"; // Recursive method to traverse a forest created by ReorderUpdates() to to @@ -141,7 +137,7 @@ // Only non deletions and non premanent node should have valid specifics and // unique positions. if (!update_entity.is_deleted() && - update_entity.parent_id != kBookmarksRootId) { + update_entity.server_defined_unique_tag.empty()) { if (!IsValidBookmarkSpecifics(update_entity.specifics.bookmark(), update_entity.is_folder)) { // Ignore updates with invalid specifics. @@ -286,7 +282,7 @@ update_entity.specifics); return; } - if (update_entity.parent_id == kBookmarksRootId) { + if (!update_entity.server_defined_unique_tag.empty()) { DLOG(ERROR) << "Permanent nodes other than the Synced Bookmarks node " "should have been merged during intial sync."; return;
diff --git a/components/sync_bookmarks/bookmark_remote_updates_handler_unittest.cc b/components/sync_bookmarks/bookmark_remote_updates_handler_unittest.cc index fb6edd3..bb049a9 100644 --- a/components/sync_bookmarks/bookmark_remote_updates_handler_unittest.cc +++ b/components/sync_bookmarks/bookmark_remote_updates_handler_unittest.cc
@@ -25,6 +25,7 @@ using testing::_; using testing::ElementsAre; using testing::Eq; +using testing::NotNull; namespace sync_bookmarks { @@ -32,10 +33,12 @@ // The parent tag for children of the root entity. Entities with this parent are // referred to as top level enities. -const char kRootParentTag[] = "0"; +const char kRootParentId[] = "0"; +const char kBookmarksRootId[] = "root_id"; const char kBookmarkBarId[] = "bookmark_bar_id"; const char kBookmarkBarTag[] = "bookmark_bar"; -const char kBookmarksRootId[] = "32904_google_chrome_bookmarks"; +const char kMobileBookmarksId[] = "synced_bookmarks_id"; +const char kMobileBookmarksTag[] = "synced_bookmarks"; syncer::UpdateResponseData CreateUpdateResponseData( const std::string& server_id, @@ -76,7 +79,7 @@ syncer::UpdateResponseData CreateBookmarkRootUpdateData() { syncer::EntityData data; data.id = syncer::ModelTypeToRootTag(syncer::BOOKMARKS); - data.parent_id = kRootParentTag; + data.parent_id = kRootParentId; data.server_defined_unique_tag = syncer::ModelTypeToRootTag(syncer::BOOKMARKS); @@ -89,11 +92,13 @@ return response_data; } -syncer::UpdateResponseData CreateBookmarkBarNodeUpdateData() { +syncer::UpdateResponseData CreatePermanentFolderUpdateData( + const std::string& id, + const std::string& tag) { syncer::EntityData data; - data.id = kBookmarkBarId; - data.parent_id = kBookmarksRootId; - data.server_defined_unique_tag = kBookmarkBarTag; + data.id = id; + data.parent_id = "root_id"; + data.server_defined_unique_tag = tag; data.specifics.mutable_bookmark(); @@ -178,19 +183,49 @@ // Updates should be ordered such that parent node update comes first, and // deletions come last. - // node0 --> node1 --> node2 --> node4 --> node5 --> node6. + // node4 --> node5 --> node0 --> node1 --> node2 --> node6. // This is test is over verifying since the order requirements are // within subtrees only. (e.g it doesn't matter whether node1 comes before or // after node4). However, it's implemented this way for simplicity. - EXPECT_THAT(ordered_updates[0]->entity.value().id, Eq(ids[0])); - EXPECT_THAT(ordered_updates[1]->entity.value().id, Eq(ids[1])); - EXPECT_THAT(ordered_updates[2]->entity.value().id, Eq(ids[2])); - EXPECT_THAT(ordered_updates[3]->entity.value().id, Eq(ids[4])); - EXPECT_THAT(ordered_updates[4]->entity.value().id, Eq(ids[5])); + EXPECT_THAT(ordered_updates[0]->entity.value().id, Eq(ids[4])); + EXPECT_THAT(ordered_updates[1]->entity.value().id, Eq(ids[5])); + EXPECT_THAT(ordered_updates[2]->entity.value().id, Eq(ids[0])); + EXPECT_THAT(ordered_updates[3]->entity.value().id, Eq(ids[1])); + EXPECT_THAT(ordered_updates[4]->entity.value().id, Eq(ids[2])); EXPECT_THAT(ordered_updates[5]->entity.value().id, Eq(ids[6])); } TEST(BookmarkRemoteUpdatesHandlerReorderUpdatesTest, + ShouldProcessMobileBookmarksNodeCreation) { + // Init the processor to have only the bookmark bar. + std::unique_ptr<bookmarks::BookmarkModel> bookmark_model = + bookmarks::TestBookmarkClient::CreateModel(); + SyncedBookmarkTracker tracker(std::vector<NodeMetadataPair>(), + std::make_unique<sync_pb::ModelTypeState>()); + const syncer::UpdateResponseDataList bookmark_bar_updates = { + CreatePermanentFolderUpdateData(kBookmarkBarId, kBookmarkBarTag)}; + testing::NiceMock<favicon::MockFaviconService> favicon_service; + BookmarkModelMerger(&bookmark_bar_updates, bookmark_model.get(), + &favicon_service, &tracker) + .Merge(); + // Bookmark bar node should be tracked now. + ASSERT_THAT(tracker.TrackedEntitiesCountForTest(), Eq(1U)); + + // Construct the updates list to have mobile bookmarks node remote creation. + syncer::UpdateResponseDataList updates; + updates.push_back( + CreatePermanentFolderUpdateData(kMobileBookmarksId, kMobileBookmarksTag)); + BookmarkRemoteUpdatesHandler updates_handler(bookmark_model.get(), + &favicon_service, &tracker); + updates_handler.Process(updates); + + // Both the bookmark bar and mobile bookmarks nodes should be tracked. + EXPECT_THAT(tracker.TrackedEntitiesCountForTest(), Eq(2U)); + EXPECT_THAT(tracker.GetEntityForBookmarkNode(bookmark_model->mobile_node()), + NotNull()); +} + +TEST(BookmarkRemoteUpdatesHandlerReorderUpdatesTest, ShouldProcessRandomlyOrderedCreations) { // Prepare creation updates to construct this structure: // bookmark_bar @@ -203,7 +238,7 @@ SyncedBookmarkTracker tracker(std::vector<NodeMetadataPair>(), std::make_unique<sync_pb::ModelTypeState>()); const syncer::UpdateResponseDataList bookmark_bar_updates = { - CreateBookmarkBarNodeUpdateData()}; + CreatePermanentFolderUpdateData(kBookmarkBarId, kBookmarkBarTag)}; // TODO(crbug.com/516866): Create a test fixture that would encapsulate // the merge functionality for all relevant tests. testing::NiceMock<favicon::MockFaviconService> favicon_service; @@ -321,7 +356,7 @@ SyncedBookmarkTracker tracker(std::vector<NodeMetadataPair>(), std::make_unique<sync_pb::ModelTypeState>()); const syncer::UpdateResponseDataList bookmark_bar_updates = { - CreateBookmarkBarNodeUpdateData()}; + CreatePermanentFolderUpdateData(kBookmarkBarId, kBookmarkBarTag)}; testing::NiceMock<favicon::MockFaviconService> favicon_service; BookmarkModelMerger(&bookmark_bar_updates, bookmark_model.get(), &favicon_service, &tracker) @@ -340,7 +375,8 @@ // Constuct the updates list to have creations randomly ordered. syncer::UpdateResponseDataList updates; - updates.push_back(CreateBookmarkBarNodeUpdateData()); + updates.push_back( + CreatePermanentFolderUpdateData(kBookmarkBarId, kBookmarkBarTag)); updates.push_back(CreateUpdateResponseData( /*server_id=*/kId2, /*parent_id=*/kBookmarkBarId, /*is_deletion=*/false, /*unique_position=*/pos2)); @@ -580,7 +616,7 @@ SyncedBookmarkTracker tracker(std::vector<NodeMetadataPair>(), std::make_unique<sync_pb::ModelTypeState>()); const syncer::UpdateResponseDataList bookmark_bar_updates = { - CreateBookmarkBarNodeUpdateData()}; + CreatePermanentFolderUpdateData(kBookmarkBarId, kBookmarkBarTag)}; // TODO(crbug.com/516866): Create a test fixture that would encapsulate // the merge functionality for all relevant tests. testing::NiceMock<favicon::MockFaviconService> favicon_service; @@ -632,7 +668,7 @@ SyncedBookmarkTracker tracker(std::vector<NodeMetadataPair>(), std::make_unique<sync_pb::ModelTypeState>()); const syncer::UpdateResponseDataList bookmark_bar_updates = { - CreateBookmarkBarNodeUpdateData()}; + CreatePermanentFolderUpdateData(kBookmarkBarId, kBookmarkBarTag)}; // TODO(crbug.com/516866): Create a test fixture that would encapsulate // the merge functionality for all relevant tests. testing::NiceMock<favicon::MockFaviconService> favicon_service;
diff --git a/components/test/android/browsertests_apk/src/org/chromium/components_browsertests_apk/ComponentsBrowserTestsApplication.java b/components/test/android/browsertests_apk/src/org/chromium/components_browsertests_apk/ComponentsBrowserTestsApplication.java index 23cadf0..585e32d6 100644 --- a/components/test/android/browsertests_apk/src/org/chromium/components_browsertests_apk/ComponentsBrowserTestsApplication.java +++ b/components/test/android/browsertests_apk/src/org/chromium/components_browsertests_apk/ComponentsBrowserTestsApplication.java
@@ -24,8 +24,9 @@ super.attachBaseContext(base); ContextUtils.initApplicationContext(this); // The test harness runs in the main process, and browser in :test_process. + boolean isMainProcess = !ContextUtils.getProcessName().contains(":"); boolean isBrowserProcess = ContextUtils.getProcessName().contains(":test"); - if (BuildConfig.IS_MULTIDEX_ENABLED && (ContextUtils.isMainProcess() || isBrowserProcess)) { + if (BuildConfig.IS_MULTIDEX_ENABLED && (isMainProcess || isBrowserProcess)) { ChromiumMultiDexInstaller.install(this); } if (isBrowserProcess) {
diff --git a/components/unified_consent/unified_consent_metrics.cc b/components/unified_consent/unified_consent_metrics.cc index 153d675..d46dc0c 100644 --- a/components/unified_consent/unified_consent_metrics.cc +++ b/components/unified_consent/unified_consent_metrics.cc
@@ -5,12 +5,17 @@ #include "components/unified_consent/unified_consent_metrics.h" #include "base/metrics/histogram_macros.h" +#include "components/prefs/pref_service.h" namespace { // Histogram name for the consent bump action. const char kConsentBumpActionMetricName[] = "UnifiedConsent.ConsentBump.Action"; +// Histogram recorded at startup to log which Google services are enabled. +const char kSyncAndGoogleServicesSettingsHistogram[] = + "UnifiedConsent.SyncAndGoogleServicesSettings"; + } // namespace namespace unified_consent { @@ -32,6 +37,32 @@ UMA_HISTOGRAM_ENUMERATION("UnifiedConsent.RevokeReason", reason); } +void RecordSettingsHistogramSample(SettingsHistogramValue value) { + UMA_HISTOGRAM_ENUMERATION(kSyncAndGoogleServicesSettingsHistogram, value); +} + +bool RecordSettingsHistogramFromPref(const char* pref_name, + PrefService* pref_service, + SettingsHistogramValue value) { + if (!pref_service->GetBoolean(pref_name)) + return false; + RecordSettingsHistogramSample(value); + return true; +} + +bool RecordSettingsHistogramFromService( + UnifiedConsentServiceClient* client, + UnifiedConsentServiceClient::Service service, + SettingsHistogramValue value) { + if (client->GetServiceState(service) != + UnifiedConsentServiceClient::ServiceState::kEnabled) { + return false; + } + + RecordSettingsHistogramSample(value); + return true; +} + } // namespace metrics } // namespace unified_consent
diff --git a/components/unified_consent/unified_consent_metrics.h b/components/unified_consent/unified_consent_metrics.h index c275b8f..7ff8735 100644 --- a/components/unified_consent/unified_consent_metrics.h +++ b/components/unified_consent/unified_consent_metrics.h
@@ -5,6 +5,8 @@ #ifndef COMPONENTS_UNIFIED_CONSENT_UNIFIED_CONSENT_METRICS_H_ #define COMPONENTS_UNIFIED_CONSENT_UNIFIED_CONSENT_METRICS_H_ +#include "components/unified_consent/unified_consent_service_client.h" + namespace unified_consent { namespace metrics { @@ -27,6 +29,46 @@ kMaxValue = kUserDisabledSettingsToggle }; +// Used in histograms. Do not change existing values, append new values at the +// end. +enum class ConsentBumpSuppressReason { + // There is no suppress reason. The consent bump was shown. + kNone, + // The user wasn't signed in during the migration. + kNotSignedIn, + // The user wasn't syncing everything during the migration. + kSyncEverythingOff, + // The user didn't have all on-by-default privacy settings enabled during + // migration. + kPrivacySettingOff, + kSettingsOptIn, + // The user was eligible for seeing the consent bump, but then signed out. + kUserSignedOut, + kSyncPaused, + // The user was eligible for seeing the consent bump, but turned an individual + // sync data type off. + kUserTurnedSyncDatatypeOff, + // The user was eligible for seeing the consent bump, but turned an + // on-by-default privacy setting off. + kUserTurnedPrivacySettingOff, + + kMaxValue = kUserTurnedPrivacySettingOff +}; + +// Google services that can be toggled in user settings. +// Used in histograms. Do not change existing values, append new values at the +// end. +enum class SettingsHistogramValue { + kNone = 0, + kUnifiedConsentGiven = 1, + kUserEvents = 2, + kUrlKeyedAnonymizedDataCollection = 3, + kSafeBrowsingExtendedReporting = 4, + kSpellCheck = 5, + + kMaxValue = kSpellCheck +}; + // Records histogram action for the unified consent bump. void RecordConsentBumpMetric(UnifiedConsentBumpAction action); @@ -37,6 +79,25 @@ // Records the reason why the unified consent was revoked. void RecordUnifiedConsentRevoked(UnifiedConsentRevokeReason reason); +// Records a sample in the kSyncAndGoogleServicesSettingsHistogram. Wrapped in a +// function to avoid code size issues caused by histogram macros. +void RecordSettingsHistogramSample(SettingsHistogramValue value); + +// Checks if a pref is enabled and if so, records a sample in the +// kSyncAndGoogleServicesSettingsHistogram. Returns true if a sample was +// recorded. +bool RecordSettingsHistogramFromPref(const char* pref_name, + PrefService* pref_service, + SettingsHistogramValue value); + +// Checks if a service is enabled and if so, records a sample in the +// kSyncAndGoogleServicesSettingsHistogram. Returns true if a sample was +// recorded. +bool RecordSettingsHistogramFromService( + UnifiedConsentServiceClient* client, + UnifiedConsentServiceClient::Service service, + SettingsHistogramValue value); + } // namespace metrics } // namespace unified_consent
diff --git a/components/unified_consent/unified_consent_service.cc b/components/unified_consent/unified_consent_service.cc index 7db6822..97fbe7d 100644 --- a/components/unified_consent/unified_consent_service.cc +++ b/components/unified_consent/unified_consent_service.cc
@@ -19,51 +19,11 @@ #include "components/sync/driver/sync_service.h" #include "components/unified_consent/feature.h" #include "components/unified_consent/pref_names.h" -#include "components/unified_consent/unified_consent_metrics.h" -#include "components/unified_consent/unified_consent_service_client.h" namespace unified_consent { namespace { -// Histogram recorded at startup to log which Google services are enabled. -const char kSyncAndGoogleServicesSettingsHistogram[] = - "UnifiedConsent.SyncAndGoogleServicesSettings"; - -// Records a sample in the kSyncAndGoogleServicesSettingsHistogram. Wrapped in a -// function to avoid code size issues caused by histogram macros. -void RecordSettingsHistogramSample(SettingsHistogramValue value) { - UMA_HISTOGRAM_ENUMERATION(kSyncAndGoogleServicesSettingsHistogram, value); -} - -// Checks if a pref is enabled and if so, records a sample in the -// kSyncAndGoogleServicesSettingsHistogram. Returns true if a sample was -// recorded. -bool RecordSettingsHistogramFromPref(const char* pref_name, - PrefService* pref_service, - SettingsHistogramValue value) { - if (!pref_service->GetBoolean(pref_name)) - return false; - RecordSettingsHistogramSample(value); - return true; -} - -// Checks if a service is enabled and if so, records a sample in the -// kSyncAndGoogleServicesSettingsHistogram. Returns true if a sample was -// recorded. -bool RecordSettingsHistogramFromService( - UnifiedConsentServiceClient* client, - UnifiedConsentServiceClient::Service service, - SettingsHistogramValue value) { - if (client->GetServiceState(service) != - UnifiedConsentServiceClient::ServiceState::kEnabled) { - return false; - } - - RecordSettingsHistogramSample(value); - return true; -} - // Used for observing the sync service and finishing the rollback once the sync // engine is initialized. // Note: This object is suicidal - it will kill itself after it finishes the @@ -251,26 +211,26 @@ void UnifiedConsentService::MarkConsentBumpShown() { // Record suppress reason kNone, which means that it was shown. This also sets // the |kShouldShowConsentBump| pref to false. - RecordConsentBumpSuppressReason(ConsentBumpSuppressReason::kNone); + RecordConsentBumpSuppressReason(metrics::ConsentBumpSuppressReason::kNone); } void UnifiedConsentService::RecordConsentBumpSuppressReason( - ConsentBumpSuppressReason suppress_reason) { + metrics::ConsentBumpSuppressReason suppress_reason) { UMA_HISTOGRAM_ENUMERATION("UnifiedConsent.ConsentBump.SuppressReason", suppress_reason); switch (suppress_reason) { - case ConsentBumpSuppressReason::kNone: - case ConsentBumpSuppressReason::kNotSignedIn: - case ConsentBumpSuppressReason::kSyncEverythingOff: - case ConsentBumpSuppressReason::kPrivacySettingOff: - case ConsentBumpSuppressReason::kSettingsOptIn: - case ConsentBumpSuppressReason::kUserSignedOut: - case ConsentBumpSuppressReason::kUserTurnedSyncDatatypeOff: - case ConsentBumpSuppressReason::kUserTurnedPrivacySettingOff: + case metrics::ConsentBumpSuppressReason::kNone: + case metrics::ConsentBumpSuppressReason::kNotSignedIn: + case metrics::ConsentBumpSuppressReason::kSyncEverythingOff: + case metrics::ConsentBumpSuppressReason::kPrivacySettingOff: + case metrics::ConsentBumpSuppressReason::kSettingsOptIn: + case metrics::ConsentBumpSuppressReason::kUserSignedOut: + case metrics::ConsentBumpSuppressReason::kUserTurnedSyncDatatypeOff: + case metrics::ConsentBumpSuppressReason::kUserTurnedPrivacySettingOff: pref_service_->SetBoolean(prefs::kShouldShowUnifiedConsentBump, false); break; - case ConsentBumpSuppressReason::kSyncPaused: + case metrics::ConsentBumpSuppressReason::kSyncPaused: // Consent bump should be shown when sync is active again. DCHECK(ShouldShowConsentBump()); break; @@ -320,7 +280,8 @@ } if (ShouldShowConsentBump()) - RecordConsentBumpSuppressReason(ConsentBumpSuppressReason::kUserSignedOut); + RecordConsentBumpSuppressReason( + metrics::ConsentBumpSuppressReason::kUserSignedOut); } void UnifiedConsentService::OnStateChanged(syncer::SyncService* sync) { @@ -415,7 +376,8 @@ } if (ShouldShowConsentBump()) - RecordConsentBumpSuppressReason(ConsentBumpSuppressReason::kSettingsOptIn); + RecordConsentBumpSuppressReason( + metrics::ConsentBumpSuppressReason::kSettingsOptIn); // Enable all sync data types if possible, otherwise they will be enabled with // |OnStateChanged| once sync is active; @@ -456,7 +418,8 @@ DCHECK(!IsUnifiedConsentGiven()); if (!identity_manager_->HasPrimaryAccount()) { - RecordConsentBumpSuppressReason(ConsentBumpSuppressReason::kNotSignedIn); + RecordConsentBumpSuppressReason( + metrics::ConsentBumpSuppressReason::kNotSignedIn); SetMigrationState(MigrationState::kCompleted); return; } @@ -467,10 +430,10 @@ if (!is_syncing_everything) { RecordConsentBumpSuppressReason( - ConsentBumpSuppressReason::kSyncEverythingOff); + metrics::ConsentBumpSuppressReason::kSyncEverythingOff); } else if (!AreAllOnByDefaultPrivacySettingsOn()) { RecordConsentBumpSuppressReason( - ConsentBumpSuppressReason::kPrivacySettingOff); + metrics::ConsentBumpSuppressReason::kPrivacySettingOff); } else { // When the user was syncing everything, and all on-by-default privacy // settings were on, the consent bump should be shown. @@ -539,27 +502,28 @@ bool metric_recorded = false; if (IsUnifiedConsentGiven()) { - RecordSettingsHistogramSample(SettingsHistogramValue::kUnifiedConsentGiven); + RecordSettingsHistogramSample( + metrics::SettingsHistogramValue::kUnifiedConsentGiven); metric_recorded = true; } if (identity_manager_->HasPrimaryAccount() && sync_service_->GetPreferredDataTypes().Has(syncer::USER_EVENTS)) { - RecordSettingsHistogramSample(SettingsHistogramValue::kUserEvents); + RecordSettingsHistogramSample(metrics::SettingsHistogramValue::kUserEvents); metric_recorded = true; } metric_recorded |= RecordSettingsHistogramFromPref( prefs::kUrlKeyedAnonymizedDataCollectionEnabled, pref_service_, - SettingsHistogramValue::kUrlKeyedAnonymizedDataCollection); + metrics::SettingsHistogramValue::kUrlKeyedAnonymizedDataCollection); metric_recorded |= RecordSettingsHistogramFromService( service_client_.get(), UnifiedConsentServiceClient::Service::kSafeBrowsingExtendedReporting, - SettingsHistogramValue::kSafeBrowsingExtendedReporting); + metrics::SettingsHistogramValue::kSafeBrowsingExtendedReporting); metric_recorded |= RecordSettingsHistogramFromService( service_client_.get(), UnifiedConsentServiceClient::Service::kSpellCheck, - SettingsHistogramValue::kSpellCheck); + metrics::SettingsHistogramValue::kSpellCheck); if (!metric_recorded) - RecordSettingsHistogramSample(SettingsHistogramValue::kNone); + RecordSettingsHistogramSample(metrics::SettingsHistogramValue::kNone); } void UnifiedConsentService::CheckConsentBumpEligibility() { @@ -576,10 +540,10 @@ if (!sync_service_->GetPreferredDataTypes().HasAll( user_types_without_user_events)) { RecordConsentBumpSuppressReason( - ConsentBumpSuppressReason::kUserTurnedSyncDatatypeOff); + metrics::ConsentBumpSuppressReason::kUserTurnedSyncDatatypeOff); } else if (!AreAllOnByDefaultPrivacySettingsOn()) { RecordConsentBumpSuppressReason( - ConsentBumpSuppressReason::kUserTurnedPrivacySettingOff); + metrics::ConsentBumpSuppressReason::kUserTurnedPrivacySettingOff); } metrics::RecordConsentBumpEligibility( pref_service_->GetBoolean(prefs::kShouldShowUnifiedConsentBump));
diff --git a/components/unified_consent/unified_consent_service.h b/components/unified_consent/unified_consent_service.h index 800fba5e..2c1c2d86 100644 --- a/components/unified_consent/unified_consent_service.h +++ b/components/unified_consent/unified_consent_service.h
@@ -12,6 +12,7 @@ #include "components/keyed_service/core/keyed_service.h" #include "components/sync/base/model_type.h" #include "components/sync/driver/sync_service_observer.h" +#include "components/unified_consent/unified_consent_metrics.h" #include "components/unified_consent/unified_consent_service_client.h" #include "services/identity/public/cpp/identity_manager.h" @@ -38,46 +39,6 @@ kCompleted = 10, }; -// Used in histograms. Do not change existing values, append new values at the -// end. -enum class ConsentBumpSuppressReason { - // There is no suppress reason. The consent bump was shown. - kNone, - // The user wasn't signed in during the migration. - kNotSignedIn, - // The user wasn't syncing everything during the migration. - kSyncEverythingOff, - // The user didn't have all on-by-default privacy settings enabled during - // migration. - kPrivacySettingOff, - kSettingsOptIn, - // The user was eligible for seeing the consent bump, but then signed out. - kUserSignedOut, - kSyncPaused, - // The user was eligible for seeing the consent bump, but turned an individual - // sync data type off. - kUserTurnedSyncDatatypeOff, - // The user was eligible for seeing the consent bump, but turned an - // on-by-default privacy setting off. - kUserTurnedPrivacySettingOff, - - kMaxValue = kUserTurnedPrivacySettingOff -}; - -// Google services that can be toggled in user settings. -// Used in histograms. Do not change existing values, append new values at the -// end. -enum class SettingsHistogramValue { - kNone = 0, - kUnifiedConsentGiven = 1, - kUserEvents = 2, - kUrlKeyedAnonymizedDataCollection = 3, - kSafeBrowsingExtendedReporting = 4, - kSpellCheck = 5, - - kMaxValue = kSpellCheck -}; - // A browser-context keyed service that is used to manage the user consent // when UnifiedConsent feature is enabled. class UnifiedConsentService : public KeyedService, @@ -114,7 +75,7 @@ // consent bump should be shown. Note: In some cases, e.g. sync paused, // |ShouldShowConsentBump| will still return true. void RecordConsentBumpSuppressReason( - ConsentBumpSuppressReason suppress_reason); + metrics::ConsentBumpSuppressReason suppress_reason); // KeyedService: void Shutdown() override;
diff --git a/components/unified_consent/unified_consent_service_unittest.cc b/components/unified_consent/unified_consent_service_unittest.cc index a0a8394c..b5ae38b 100644 --- a/components/unified_consent/unified_consent_service_unittest.cc +++ b/components/unified_consent/unified_consent_service_unittest.cc
@@ -419,7 +419,7 @@ // this point. histogram_tester.ExpectBucketCount( "UnifiedConsent.ConsentBump.SuppressReason", - unified_consent::ConsentBumpSuppressReason::kUserSignedOut, 1); + metrics::ConsentBumpSuppressReason::kUserSignedOut, 1); } TEST_F(UnifiedConsentServiceTest, Migration_SyncingEverythingAndServicesOff) { @@ -446,7 +446,7 @@ // this point. histogram_tester.ExpectBucketCount( "UnifiedConsent.ConsentBump.SuppressReason", - unified_consent::ConsentBumpSuppressReason::kPrivacySettingOff, 1); + metrics::ConsentBumpSuppressReason::kPrivacySettingOff, 1); } #endif // !defined(OS_CHROMEOS) @@ -466,7 +466,7 @@ // The suppress reason for not showing the consent bump should be recorded. histogram_tester.ExpectBucketCount( "UnifiedConsent.ConsentBump.SuppressReason", - unified_consent::ConsentBumpSuppressReason::kSyncEverythingOff, 1); + metrics::ConsentBumpSuppressReason::kSyncEverythingOff, 1); } TEST_F(UnifiedConsentServiceTest, Migration_UpdateSettings) { @@ -546,7 +546,7 @@ // The suppress reason for not showing the consent bump should be recorded. histogram_tester.ExpectBucketCount( "UnifiedConsent.ConsentBump.SuppressReason", - unified_consent::ConsentBumpSuppressReason::kNotSignedIn, 1); + metrics::ConsentBumpSuppressReason::kNotSignedIn, 1); } #endif // !defined(OS_CHROMEOS) @@ -630,7 +630,7 @@ histogram_tester.ExpectUniqueSample( "UnifiedConsent.SyncAndGoogleServicesSettings", - SettingsHistogramValue::kNone, 1); + metrics::SettingsHistogramValue::kNone, 1); } TEST_F(UnifiedConsentServiceTest, SettingsHistogram_UnifiedConsentGiven) { @@ -645,22 +645,22 @@ histogram_tester.ExpectBucketCount( "UnifiedConsent.SyncAndGoogleServicesSettings", - SettingsHistogramValue::kNone, 0); + metrics::SettingsHistogramValue::kNone, 0); histogram_tester.ExpectBucketCount( "UnifiedConsent.SyncAndGoogleServicesSettings", - SettingsHistogramValue::kUnifiedConsentGiven, 1); + metrics::SettingsHistogramValue::kUnifiedConsentGiven, 1); histogram_tester.ExpectBucketCount( "UnifiedConsent.SyncAndGoogleServicesSettings", - SettingsHistogramValue::kUserEvents, 1); + metrics::SettingsHistogramValue::kUserEvents, 1); histogram_tester.ExpectBucketCount( "UnifiedConsent.SyncAndGoogleServicesSettings", - SettingsHistogramValue::kUrlKeyedAnonymizedDataCollection, 1); + metrics::SettingsHistogramValue::kUrlKeyedAnonymizedDataCollection, 1); histogram_tester.ExpectBucketCount( "UnifiedConsent.SyncAndGoogleServicesSettings", - SettingsHistogramValue::kSafeBrowsingExtendedReporting, 1); + metrics::SettingsHistogramValue::kSafeBrowsingExtendedReporting, 1); histogram_tester.ExpectBucketCount( "UnifiedConsent.SyncAndGoogleServicesSettings", - SettingsHistogramValue::kSpellCheck, 1); + metrics::SettingsHistogramValue::kSpellCheck, 1); histogram_tester.ExpectTotalCount( "UnifiedConsent.SyncAndGoogleServicesSettings", 5); } @@ -675,7 +675,7 @@ // because the user is not signed in. histogram_tester.ExpectUniqueSample( "UnifiedConsent.SyncAndGoogleServicesSettings", - SettingsHistogramValue::kSpellCheck, 1); + metrics::SettingsHistogramValue::kSpellCheck, 1); } TEST_F(UnifiedConsentServiceTest, ConsentBump_EligibleOnSecondStartup) { @@ -744,8 +744,7 @@ EXPECT_FALSE(consent_service_->ShouldShowConsentBump()); histogram_tester.ExpectBucketCount( "UnifiedConsent.ConsentBump.SuppressReason", - unified_consent::ConsentBumpSuppressReason::kUserTurnedSyncDatatypeOff, - 1); + metrics::ConsentBumpSuppressReason::kUserTurnedSyncDatatypeOff, 1); histogram_tester.ExpectBucketCount( "UnifiedConsent.ConsentBump.EligibleAtStartup", true, 1); histogram_tester.ExpectBucketCount( @@ -779,8 +778,7 @@ EXPECT_FALSE(consent_service_->ShouldShowConsentBump()); histogram_tester.ExpectBucketCount( "UnifiedConsent.ConsentBump.SuppressReason", - unified_consent::ConsentBumpSuppressReason::kUserTurnedPrivacySettingOff, - 1); + metrics::ConsentBumpSuppressReason::kUserTurnedPrivacySettingOff, 1); } } // namespace unified_consent
diff --git a/components/variations/service/BUILD.gn b/components/variations/service/BUILD.gn index c77020f..5e79f406 100644 --- a/components/variations/service/BUILD.gn +++ b/components/variations/service/BUILD.gn
@@ -20,6 +20,7 @@ "//base", "//components/data_use_measurement/core", "//components/encrypted_messages", + "//components/language/core/browser", "//components/metrics", "//components/network_time", "//components/pref_registry",
diff --git a/components/variations/service/DEPS b/components/variations/service/DEPS index 7d4e98a..4ccdcd6 100644 --- a/components/variations/service/DEPS +++ b/components/variations/service/DEPS
@@ -1,6 +1,7 @@ include_rules = [ "+components/data_use_measurement/core", "+components/encrypted_messages", + "+components/language/core/browser", "+components/metrics", "+components/network_time", "+components/pref_registry",
diff --git a/components/variations/service/variations_field_trial_creator.cc b/components/variations/service/variations_field_trial_creator.cc index 0797532..28d063e 100644 --- a/components/variations/service/variations_field_trial_creator.cc +++ b/components/variations/service/variations_field_trial_creator.cc
@@ -24,6 +24,7 @@ #include "base/trace_event/trace_event.h" #include "base/version.h" #include "build/build_config.h" +#include "components/language/core/browser/locale_util.h" #include "components/prefs/pref_service.h" #include "components/variations/field_trial_config/field_trial_util.h" #include "components/variations/platform_field_trials.h" @@ -35,6 +36,7 @@ #include "components/variations/variations_seed_processor.h" #include "components/variations/variations_switches.h" #include "ui/base/device_form_factor.h" +#include "ui/base/l10n/l10n_util.h" namespace variations { namespace { @@ -162,6 +164,8 @@ ui_string_overrider_(ui_string_overrider), seed_store_(std::move(seed_store)), create_trials_from_seed_called_(false), + application_locale_( + language::GetApplicationLocale(seed_store_->local_state())), has_platform_override_(false), platform_override_(Study::PLATFORM_WINDOWS) {} @@ -236,7 +240,7 @@ const base::Version& version) { std::unique_ptr<ClientFilterableState> state = std::make_unique<ClientFilterableState>(); - state->locale = client_->GetApplicationLocale(); + state->locale = application_locale_; state->reference_date = GetReferenceDateForExpiryChecks(local_state()); state->version = version; state->channel = GetChannelForVariations(client_->GetChannel());
diff --git a/components/variations/service/variations_field_trial_creator.h b/components/variations/service/variations_field_trial_creator.h index 6fa9356..a1ca0da2 100644 --- a/components/variations/service/variations_field_trial_creator.h +++ b/components/variations/service/variations_field_trial_creator.h
@@ -145,6 +145,11 @@ // called at most once. bool create_trials_from_seed_called_; + // The application locale won't change after the startup, so we cache the + // value the first time when GetApplicationLocale() is called in the + // constructor. + std::string application_locale_; + // Indiciate if OverrideVariationsPlatform has been used to set // |platform_override_|. bool has_platform_override_;
diff --git a/components/variations/service/variations_field_trial_creator_unittest.cc b/components/variations/service/variations_field_trial_creator_unittest.cc index 7b05d32..c1088cda 100644 --- a/components/variations/service/variations_field_trial_creator_unittest.cc +++ b/components/variations/service/variations_field_trial_creator_unittest.cc
@@ -166,7 +166,6 @@ ~TestVariationsServiceClient() override = default; // VariationsServiceClient: - std::string GetApplicationLocale() override { return std::string(); } base::Callback<base::Version(void)> GetVersionForSimulationCallback() override { return base::Callback<base::Version(void)>();
diff --git a/components/variations/service/variations_service_client.h b/components/variations/service/variations_service_client.h index 4e2c644..c573180 100644 --- a/components/variations/service/variations_service_client.h +++ b/components/variations/service/variations_service_client.h
@@ -29,9 +29,6 @@ public: virtual ~VariationsServiceClient() {} - // Returns the current application locale (e.g. "en-US"). - virtual std::string GetApplicationLocale() = 0; - // Returns a callback that when run returns the base::Version to use for // variations seed simulation. VariationsService guarantees that the callback // will be run on a background thread that permits blocking.
diff --git a/components/variations/service/variations_service_unittest.cc b/components/variations/service/variations_service_unittest.cc index 1061962..41dc47d 100644 --- a/components/variations/service/variations_service_unittest.cc +++ b/components/variations/service/variations_service_unittest.cc
@@ -72,7 +72,6 @@ ~TestVariationsServiceClient() override {} // VariationsServiceClient: - std::string GetApplicationLocale() override { return std::string(); } base::Callback<base::Version(void)> GetVersionForSimulationCallback() override { return base::Bind(&StubGetVersionForSimulation);
diff --git a/content/app/content_main_runner_impl.cc b/content/app/content_main_runner_impl.cc index 8540e79..feae0afd 100644 --- a/content/app/content_main_runner_impl.cc +++ b/content/app/content_main_runner_impl.cc
@@ -45,6 +45,7 @@ #include "content/browser/browser_thread_impl.h" #include "content/browser/scheduler/browser_task_executor.h" #include "content/browser/startup_data_impl.h" +#include "content/browser/startup_helper.h" #include "content/common/content_constants_internal.h" #include "content/common/url_schemes.h" #include "content/public/app/content_main_delegate.h" @@ -74,6 +75,7 @@ #include <cstring> #include "base/trace_event/trace_event_etw_export_win.h" +#include "ui/base/l10n/l10n_util_win.h" #include "ui/display/win/dpi.h" #elif defined(OS_MACOSX) #include "base/mac/mach_port_broker.h" @@ -884,6 +886,14 @@ BrowserTaskExecutor::Create(); delegate_->PreCreateMainMessageLoop(); +#if defined(OS_WIN) + if (l10n_util::GetLocaleOverrides().empty()) { + // Override the configured locale with the user's preferred UI language. + // Don't do this if the locale is already set, which is done by + // integration tests to ensure tests always run with the same locale. + l10n_util::OverrideLocaleWithUILanguageList(); + } +#endif // Create a MessageLoop if one does not already exist for the current // thread. This thread won't be promoted as BrowserThread::UI until @@ -891,7 +901,13 @@ if (!base::MessageLoopCurrentForUI::IsSet()) main_message_loop_ = std::make_unique<base::MessageLoopForUI>(); + if (delegate_->ShouldCreateFeatureList()) { + DCHECK(!field_trial_list_); + field_trial_list_ = SetUpFieldTrialsAndFeatureList(); + } + delegate_->PostEarlyInitialization(); + return RunBrowserProcessMain(main_params, delegate_); } #endif // !defined(CHROME_MULTIPLE_DLL_CHILD)
diff --git a/content/app/content_main_runner_impl.h b/content/app/content_main_runner_impl.h index 118b91b..c402da2 100644 --- a/content/app/content_main_runner_impl.h +++ b/content/app/content_main_runner_impl.h
@@ -10,6 +10,7 @@ #include "base/callback_forward.h" #include "base/memory/scoped_refptr.h" #include "base/message_loop/message_loop.h" +#include "base/metrics/field_trial.h" #include "build/build_config.h" #include "content/browser/startup_data_impl.h" #include "content/public/app/content_main.h" @@ -76,6 +77,8 @@ std::unique_ptr<base::MessageLoop> main_message_loop_; std::unique_ptr<StartupDataImpl> startup_data_; + + std::unique_ptr<base::FieldTrialList> field_trial_list_; #endif // !defined(CHROME_MULTIPLE_DLL_CHILD) DISALLOW_COPY_AND_ASSIGN(ContentMainRunnerImpl);
diff --git a/content/browser/BUILD.gn b/content/browser/BUILD.gn index cfb622a..40b5af79 100644 --- a/content/browser/BUILD.gn +++ b/content/browser/BUILD.gn
@@ -592,6 +592,8 @@ "code_cache/generated_code_cache_context.h", "startup_data_impl.cc", "startup_data_impl.h", + "startup_helper.cc", + "startup_helper.h", # NOTE: These files are here instead of in compositor_browser_sources # because the latter is not built on Android, whereas these files are
diff --git a/content/browser/background_fetch/background_fetch_job_controller.cc b/content/browser/background_fetch/background_fetch_job_controller.cc index aed7bec..706ad0b4 100644 --- a/content/browser/background_fetch/background_fetch_job_controller.cc +++ b/content/browser/background_fetch/background_fetch_job_controller.cc
@@ -4,6 +4,7 @@ #include "content/browser/background_fetch/background_fetch_job_controller.h" #include "content/public/common/origin_util.h" +#include "services/network/public/cpp/cors/cors.h" #include "third_party/blink/public/platform/modules/background_fetch/background_fetch.mojom.h" #include <utility> @@ -84,6 +85,32 @@ return !IsOriginSecure(request.fetch_request().url); } +bool BackgroundFetchJobController::RequiresCORSPreflight( + const BackgroundFetchRequestInfo& request) { + auto fetch_request = request.fetch_request(); + + // Same origin requests don't require a CORS preflight. + // https://fetch.spec.whatwg.org/#main-fetch + // TODO(crbug.com/711354): Make sure that cross-origin redirects are disabled. + if (url::IsSameOriginWith(registration_id().origin().GetURL(), + fetch_request.url)) { + return false; + } + + // Requests that are more involved than what is possible with HTML's form + // element require a CORS-preflight request. + // https://fetch.spec.whatwg.org/#main-fetch + if (!fetch_request.method.empty() && + !network::cors::IsCORSSafelistedMethod(fetch_request.method)) { + return true; + } + + net::HttpRequestHeaders::HeaderVector headers; + for (const auto& header : fetch_request.headers) + headers.emplace_back(header.first, header.second); + return !network::cors::CORSUnsafeRequestHeaderNames(headers).empty(); +} + void BackgroundFetchJobController::StartRequest( scoped_refptr<BackgroundFetchRequestInfo> request, RequestFinishedCallback request_finished_callback) { @@ -95,7 +122,7 @@ active_request_downloaded_bytes_ = 0; active_request_finished_callback_ = std::move(request_finished_callback); - if (IsMixedContent(*request.get())) { + if (IsMixedContent(*request.get()) || RequiresCORSPreflight(*request.get())) { request->SetEmptyResultWithFailureReason( BackgroundFetchResult::FailureReason::FETCH_ERROR);
diff --git a/content/browser/background_fetch/background_fetch_job_controller.h b/content/browser/background_fetch/background_fetch_job_controller.h index 254d69c..29e609a7 100644 --- a/content/browser/background_fetch/background_fetch_job_controller.h +++ b/content/browser/background_fetch/background_fetch_job_controller.h
@@ -123,6 +123,12 @@ // request is also secure. bool IsMixedContent(const BackgroundFetchRequestInfo& request); + // Whether the |request| needs CORS preflight. + // Requests that require CORS preflights are temporarily blocked, because the + // browser side of Background Fetch doesn't yet support performing CORS + // checks. TODO(crbug.com/711354): Remove this temporary block. + bool RequiresCORSPreflight(const BackgroundFetchRequestInfo& request); + // Options for the represented background fetch registration. BackgroundFetchOptions options_;
diff --git a/content/browser/browser_main_loop.cc b/content/browser/browser_main_loop.cc index 35df8ff..2b16f9bc 100644 --- a/content/browser/browser_main_loop.cc +++ b/content/browser/browser_main_loop.cc
@@ -192,7 +192,6 @@ #include "base/memory/memory_pressure_monitor_win.h" #include "net/base/winsock_init.h" #include "services/service_manager/sandbox/win/sandbox_win.h" -#include "ui/base/l10n/l10n_util_win.h" #include "ui/display/win/screen_win.h" #endif @@ -646,29 +645,11 @@ #endif // defined(USE_GLIB) if (parts_) { -#if defined(OS_WIN) - // If we're running tests (ui_task is non-null), then the ResourceBundle - // has already been initialized. - if (!parameters_.ui_task) { - // Override the configured locale with the user's preferred UI language. - l10n_util::OverrideLocaleWithUILanguageList(); - } -#endif const int pre_early_init_error_code = parts_->PreEarlyInitialization(); if (pre_early_init_error_code != service_manager::RESULT_CODE_NORMAL_EXIT) return pre_early_init_error_code; } - if (!parts_ || parts_->ShouldContentCreateFeatureList()) { - // Note that we do not initialize a new FeatureList when calling this for - // the second time. - const base::CommandLine* command_line = - base::CommandLine::ForCurrentProcess(); - base::FeatureList::InitializeInstance( - command_line->GetSwitchValueASCII(switches::kEnableFeatures), - command_line->GetSwitchValueASCII(switches::kDisableFeatures)); - } - #if defined(OS_ANDROID) || defined(OS_CHROMEOS) // Up the priority of the UI thread unless it was already high (since recent // versions of Android (O+) do this automatically).
diff --git a/content/browser/cache_storage/cache_storage_cache.cc b/content/browser/cache_storage/cache_storage_cache.cc index 030b08a..c6cd338 100644 --- a/content/browser/cache_storage/cache_storage_cache.cc +++ b/content/browser/cache_storage/cache_storage_cache.cc
@@ -30,6 +30,7 @@ #include "content/browser/cache_storage/cache_storage_cache_handle.h" #include "content/browser/cache_storage/cache_storage_cache_observer.h" #include "content/browser/cache_storage/cache_storage_histogram_utils.h" +#include "content/browser/cache_storage/cache_storage_manager.h" #include "content/browser/cache_storage/cache_storage_quota_client.h" #include "content/browser/cache_storage/cache_storage_scheduler.h" #include "content/public/browser/browser_thread.h" @@ -956,7 +957,8 @@ return; } - if ((!options || !options->ignore_method) && request && + if (owner_ != CacheStorageOwner::kBackgroundFetch && + (!options || !options->ignore_method) && request && !request->method.empty() && request->method != "GET") { std::move(callback).Run(CacheStorageError::kSuccess, std::make_unique<QueryCacheResults>());
diff --git a/content/browser/frame_host/frame_tree_node.cc b/content/browser/frame_host/frame_tree_node.cc index f422fe8..6ce11e7 100644 --- a/content/browser/frame_host/frame_tree_node.cc +++ b/content/browser/frame_host/frame_tree_node.cc
@@ -494,6 +494,9 @@ void FrameTreeNode::DidStartLoading(bool to_different_document, bool was_previously_loading) { + TRACE_EVENT2("navigation", "FrameTreeNode::DidStartLoading", + "frame_tree_node", frame_tree_node_id(), "to different document", + to_different_document); // Any main frame load to a new document should reset the load progress since // it will replace the current page and any frames. The WebContents will // be notified when DidChangeLoadProgress is called. @@ -513,6 +516,8 @@ } void FrameTreeNode::DidStopLoading() { + TRACE_EVENT1("navigation", "FrameTreeNode::DidStopLoading", "frame_tree_node", + frame_tree_node_id()); // Set final load progress and update overall progress. This will notify // the WebContents of the load progress change. DidChangeLoadProgress(kLoadingProgressDone);
diff --git a/content/browser/frame_host/render_frame_host_impl.cc b/content/browser/frame_host/render_frame_host_impl.cc index 8a746e44..60ac57d 100644 --- a/content/browser/frame_host/render_frame_host_impl.cc +++ b/content/browser/frame_host/render_frame_host_impl.cc
@@ -1251,7 +1251,6 @@ IPC_MESSAGE_HANDLER(FrameHostMsg_ExitFullscreen, OnExitFullscreen) IPC_MESSAGE_HANDLER(FrameHostMsg_SuddenTerminationDisablerChanged, OnSuddenTerminationDisablerChanged) - IPC_MESSAGE_HANDLER(FrameHostMsg_DidStartLoading, OnDidStartLoading) IPC_MESSAGE_HANDLER(FrameHostMsg_DidStopLoading, OnDidStopLoading) IPC_MESSAGE_HANDLER(FrameHostMsg_DidChangeLoadProgress, OnDidChangeLoadProgress) @@ -3082,29 +3081,6 @@ render_view_host_->GetWidget()->SynchronizeVisualProperties(); } -// TODO(clamy): Remove this IPC now that it is only used for same-document -// navigations. -void RenderFrameHostImpl::OnDidStartLoading(bool to_different_document) { - TRACE_EVENT2("navigation", "RenderFrameHostImpl::OnDidStartLoading", - "frame_tree_node", frame_tree_node_->frame_tree_node_id(), - "to different document", to_different_document); - - if (to_different_document) { - bad_message::ReceivedBadMessage(GetProcess(), - bad_message::RFH_UNEXPECTED_LOAD_START); - return; - } - bool was_previously_loading = frame_tree_node_->frame_tree()->IsLoading(); - is_loading_ = true; - - // Only inform the FrameTreeNode of a change in load state if the load state - // of this RenderFrameHost is being tracked. - if (is_active()) { - frame_tree_node_->DidStartLoading(to_different_document, - was_previously_loading); - } -} - void RenderFrameHostImpl::OnSuddenTerminationDisablerChanged( bool present, blink::WebSuddenTerminationDisablerType disabler_type) { @@ -5666,12 +5642,15 @@ if (!ValidateDidCommitParams(validated_params)) return false; - // A racy DidStopLoading IPC might have reset the loading state that was set - // to true in CommitNavigation. Set it to true now. + // Set is loading to true now if it has not been set yet. This happens for + // renderer-initiated same-document navigations. It can also happen when a + // racy DidStopLoading IPC resets the loading state that was set to true in + // CommitNavigation. if (!is_loading()) { bool was_loading = frame_tree_node()->frame_tree()->IsLoading(); is_loading_ = true; - frame_tree_node()->DidStartLoading(true, was_loading); + frame_tree_node()->DidStartLoading(!is_same_document_navigation, + was_loading); } if (navigation_request_)
diff --git a/content/browser/frame_host/render_frame_host_impl.h b/content/browser/frame_host/render_frame_host_impl.h index a03c4c1c..6d2f10d63 100644 --- a/content/browser/frame_host/render_frame_host_impl.h +++ b/content/browser/frame_host/render_frame_host_impl.h
@@ -929,7 +929,6 @@ void OnSuddenTerminationDisablerChanged( bool present, blink::WebSuddenTerminationDisablerType disabler_type); - void OnDidStartLoading(bool to_different_document); void OnDidStopLoading(); void OnDidChangeLoadProgress(double load_progress); void OnSerializeAsMHTMLResponse(
diff --git a/content/browser/navigation_browsertest.cc b/content/browser/navigation_browsertest.cc index c101d5f..a1ebb099 100644 --- a/content/browser/navigation_browsertest.cc +++ b/content/browser/navigation_browsertest.cc
@@ -9,6 +9,7 @@ #include "base/strings/stringprintf.h" #include "base/strings/utf_string_conversions.h" #include "base/task/post_task.h" +#include "base/test/bind_test_util.h" #include "base/test/scoped_feature_list.h" #include "build/build_config.h" #include "content/browser/child_process_security_policy_impl.h" @@ -25,6 +26,7 @@ #include "content/public/browser/download_manager_delegate.h" #include "content/public/browser/navigation_controller.h" #include "content/public/browser/notification_types.h" +#include "content/public/browser/site_isolation_policy.h" #include "content/public/browser/web_contents.h" #include "content/public/common/browser_side_navigation_policy.h" #include "content/public/common/content_features.h" @@ -163,6 +165,29 @@ DISALLOW_COPY_AND_ASSIGN(BrowserMessageObserver); }; +// Execute a callback whenever an observed IPC is received +class BrowserMessageCallback : public content::BrowserMessageFilter { + public: + BrowserMessageCallback(uint32_t observed_message_class, + uint32_t observed_message_type, + base::RepeatingClosure callback) + : content::BrowserMessageFilter(observed_message_class), + observed_message_type_(observed_message_type), + callback_(callback) {} + + bool OnMessageReceived(const IPC::Message& message) override { + if (message.type() == observed_message_type_) + callback_.Run(); + return false; + } + + private: + ~BrowserMessageCallback() override {} + uint32_t observed_message_type_; + base::RepeatingClosure callback_; + DISALLOW_COPY_AND_ASSIGN(BrowserMessageCallback); +}; + } // namespace // Test about navigation. @@ -1218,4 +1243,104 @@ EXPECT_FALSE(navigation.was_successful()); } +// Ensure the renderer process doesn't send too much IPC to the browser process +// when history.pushState() and history.back() are called in a loop. +// Failing to do so causes the browser to freeze. +// See https://crbug.com/882238 +IN_PROC_BROWSER_TEST_F(NavigationBrowserTest, IPCFlood_GoToEntryAtOffset) { + GURL url(embedded_test_server()->GetURL("/title1.html")); + NavigateToURL(shell(), url); + + // Count the maximum number of GoToEntryAtOffset IPC the renderer process + // autorizes itself to send. + int count_history_back = 0; + auto observer_history_back = base::MakeRefCounted<BrowserMessageCallback>( + ViewMsgStart, ViewHostMsg_GoToEntryAtOffset::ID, + base::BindLambdaForTesting([&]() { ++count_history_back; })); + int count_replace_state = 0; + auto observer_push_state = base::MakeRefCounted<BrowserMessageCallback>( + FrameMsgStart, FrameHostMsg_UpdateState::ID, + base::BindLambdaForTesting([&]() { ++count_replace_state; })); + + RenderProcessHost* process = + static_cast<RenderFrameHostImpl*>(shell()->web_contents()->GetMainFrame()) + ->GetProcess(); + process->AddFilter(observer_push_state.get()); + process->AddFilter(observer_history_back.get()); + + EXPECT_TRUE(ExecuteScript(shell(), R"( + var start = new Date().getTime(); + while(new Date().getTime() < start + 2000) { + history.pushState({},"page 2", "bar.html"); + history.back(); + } + )")); + + // The quota is shared in between history.back() and history.pushState(). + EXPECT_EQ(100, count_history_back); + EXPECT_EQ(100, count_replace_state); +} + +// Ensure the renderer process doesn't send too much IPC to the browser process +// when doing a same-document navigation is requested in a loop. +// Failing to do so causes the browser to freeze. +// See https://crbug.com/882238 +IN_PROC_BROWSER_TEST_F(NavigationBrowserTest, IPCFlood_NavigationLocal) { + GURL url(embedded_test_server()->GetURL("/title1.html")); + NavigateToURL(shell(), url); + + NavigationRecorder recorder(shell()->web_contents()); + + EXPECT_TRUE(ExecuteScript(shell(), R"( + var start = new Date().getTime(); + let i = 0; + while(new Date().getTime() < start + 2000) { + location.href = "#" + i; + ++i; + } + )")); + + // For each IPC, DidStartNavigation and DidFinishNavigation are recorded, so + // twice the quota is recorded. + EXPECT_EQ(400u, recorder.records().size()); +} + +// Ensure the renderer process doesn't send too much IPC to the browser process +// when a frame request another one in a different process to navigate. +// Failing to do so causes the browser to freeze. +// See https://crbug.com/882238 +IN_PROC_BROWSER_TEST_F(NavigationBrowserTest, IPCFlood_NavigationRemote) { + GURL url(embedded_test_server()->GetURL( + "a.com", "/cross_site_iframe_factory.html?a(b)")); + GURL b_url(embedded_test_server()->GetURL("b.com", "/title1.html")); + NavigateToURL(shell(), url); + + // This test assumes A and B are not sharing the same process. This requires + // site isolation to be enabled. + if (!SiteIsolationPolicy::AreIsolatedOriginsEnabled()) + return; + + // Count the maximum number of GoToEntryAtOffset IPC the renderer process + // autorizes itself to send. + int count = 0; + auto increment_count = + base::BindRepeating([](int* count) { (*count)++; }, &count); + auto observer = base::MakeRefCounted<BrowserMessageCallback>( + FrameMsgStart, FrameHostMsg_OpenURL::ID, increment_count); + static_cast<RenderFrameHostImpl*>(shell()->web_contents()->GetMainFrame()) + ->GetProcess() + ->AddFilter(observer.get()); + + EXPECT_TRUE(ExecuteScript(shell(), R"( + let iframe = document.querySelector("iframe"); + let initial_url = iframe.src; + var start = new Date().getTime(); + while(new Date().getTime() < start + 2000) { + iframe.src = initial_url; + } + )")); + + EXPECT_EQ(200, count); +} + } // namespace content
diff --git a/content/browser/renderer_host/input/fling_browsertest.cc b/content/browser/renderer_host/input/fling_browsertest.cc index 14afc422..ece901d 100644 --- a/content/browser/renderer_host/input/fling_browsertest.cc +++ b/content/browser/renderer_host/input/fling_browsertest.cc
@@ -92,7 +92,7 @@ void LoadPageWithOOPIF() { // navigate main frame to URL. GURL main_url(embedded_test_server()->GetURL( - "a.com", "/frame_tree/page_with_positioned_frame.html")); + "a.com", "/frame_tree/scrollable_page_with_positioned_frame.html")); EXPECT_TRUE(NavigateToURL(shell(), main_url)); // Navigate oopif to URL. @@ -119,17 +119,21 @@ iframe_node->current_frame_host()->GetRenderWidgetHost()->GetView()); } - void SimulateTouchscreenFling(RenderWidgetHostImpl* render_widget_host) { + void SimulateTouchscreenFling( + RenderWidgetHostImpl* render_widget_host, + const gfx::Vector2dF& fling_velocity = gfx::Vector2dF(0.f, -2000.f)) { DCHECK(render_widget_host); // Send a GSB to start scrolling sequence. + auto input_msg_watcher = std::make_unique<InputMsgWatcher>( + render_widget_host, blink::WebInputEvent::kGestureScrollBegin); blink::WebGestureEvent gesture_scroll_begin( blink::WebGestureEvent::kGestureScrollBegin, blink::WebInputEvent::kNoModifiers, ui::EventTimeForNow()); gesture_scroll_begin.SetSourceDevice(blink::kWebGestureDeviceTouchscreen); gesture_scroll_begin.data.scroll_begin.delta_hint_units = blink::WebGestureEvent::ScrollUnits::kPrecisePixels; - gesture_scroll_begin.data.scroll_begin.delta_x_hint = 0.f; - gesture_scroll_begin.data.scroll_begin.delta_y_hint = -5.f; + gesture_scroll_begin.data.scroll_begin.delta_x_hint = fling_velocity.x(); + gesture_scroll_begin.data.scroll_begin.delta_y_hint = fling_velocity.y(); const gfx::PointF scroll_location_in_widget(1, 1); const gfx::PointF scroll_location_in_root = child_view_ ? child_view_->TransformPointToRootCoordSpaceF( @@ -142,26 +146,31 @@ gesture_scroll_begin.SetPositionInWidget(scroll_location_in_widget); gesture_scroll_begin.SetPositionInScreen(scroll_location_in_screen); render_widget_host->ForwardGestureEvent(gesture_scroll_begin); + input_msg_watcher->WaitForAck(); // Send a GFS. blink::WebGestureEvent gesture_fling_start( blink::WebGestureEvent::kGestureFlingStart, blink::WebInputEvent::kNoModifiers, ui::EventTimeForNow()); gesture_fling_start.SetSourceDevice(blink::kWebGestureDeviceTouchscreen); - gesture_fling_start.data.fling_start.velocity_x = 0.f; - gesture_fling_start.data.fling_start.velocity_y = -2000.f; + gesture_fling_start.data.fling_start.velocity_x = fling_velocity.x(); + gesture_fling_start.data.fling_start.velocity_y = fling_velocity.y(); gesture_fling_start.SetPositionInWidget(scroll_location_in_widget); gesture_fling_start.SetPositionInScreen(scroll_location_in_screen); render_widget_host->ForwardGestureEvent(gesture_fling_start); } - void SimulateTouchpadFling(RenderWidgetHostImpl* render_widget_host) { + void SimulateTouchpadFling( + RenderWidgetHostImpl* render_widget_host, + const gfx::Vector2dF& fling_velocity = gfx::Vector2dF(0.f, -2000.f)) { DCHECK(render_widget_host); // Send a wheel event to start scrolling sequence. auto input_msg_watcher = std::make_unique<InputMsgWatcher>( - GetWidgetHost(), blink::WebInputEvent::kMouseWheel); + render_widget_host, blink::WebInputEvent::kMouseWheel); blink::WebMouseWheelEvent wheel_event = - SyntheticWebMouseWheelEventBuilder::Build(10, 10, 0, -53, 0, true); + SyntheticWebMouseWheelEventBuilder::Build( + 10, 10, fling_velocity.x() / 1000, fling_velocity.y() / 1000, 0, + true); wheel_event.phase = blink::WebMouseWheelEvent::kPhaseBegan; const gfx::PointF position_in_widget(1, 1); const gfx::PointF position_in_root = @@ -182,8 +191,8 @@ blink::WebGestureEvent::kGestureFlingStart, blink::WebInputEvent::kNoModifiers, ui::EventTimeForNow()); gesture_fling_start.SetSourceDevice(blink::kWebGestureDeviceTouchpad); - gesture_fling_start.data.fling_start.velocity_x = 0.f; - gesture_fling_start.data.fling_start.velocity_y = -2000.f; + gesture_fling_start.data.fling_start.velocity_x = fling_velocity.x(); + gesture_fling_start.data.fling_start.velocity_y = fling_velocity.y(); gesture_fling_start.SetPositionInWidget(position_in_widget); gesture_fling_start.SetPositionInScreen(position_in_screen); render_widget_host->ForwardGestureEvent(gesture_fling_start); @@ -212,24 +221,30 @@ run_loop.Run(); } - void WaitForChildScroll() { - FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents()) - ->GetFrameTree() - ->root(); - ASSERT_EQ(1U, root->child_count()); - FrameTreeNode* iframe_node = root->child_at(0); + void WaitForOOPIFScroll(FrameTreeNode* iframe_node, + int target_scroll_offset = 100, + bool upward = false) { + DCHECK(iframe_node); int scroll_top = EvalJs(iframe_node->current_frame_host(), "window.scrollY") .ExtractDouble(); - // scrollTop > 0 is not enough since the first progressFling is called from - // FlingController::ProcessGestureFlingStart. Wait for scrollTop to exceed - // 100 pixels to make sure that ProgressFling has been called through - // FlingScheduler at least once. - while (scroll_top < 100) { + + while ((upward && scroll_top > target_scroll_offset) || + (!upward && scroll_top < target_scroll_offset)) { GiveItSomeTime(); scroll_top = EvalJs(iframe_node->current_frame_host(), "window.scrollY") .ExtractDouble(); } } + FrameTreeNode* GetRootNode() { + return static_cast<WebContentsImpl*>(shell()->web_contents()) + ->GetFrameTree() + ->root(); + } + FrameTreeNode* GetChildNode() { + FrameTreeNode* root = GetRootNode(); + // ASSERT_EQ(1U, root->child_count()); + return root->child_at(0); + } std::unique_ptr<base::RunLoop> run_loop_; RenderWidgetHostViewBase* child_view_ = nullptr; @@ -281,12 +296,44 @@ IN_PROC_BROWSER_TEST_F(BrowserSideFlingBrowserTest, TouchscreenFlingInOOPIF) { LoadPageWithOOPIF(); SimulateTouchscreenFling(child_view_->host()); - WaitForChildScroll(); + WaitForOOPIFScroll(GetChildNode()); } IN_PROC_BROWSER_TEST_F(BrowserSideFlingBrowserTest, TouchpadFlingInOOPIF) { LoadPageWithOOPIF(); - SimulateTouchscreenFling(child_view_->host()); - WaitForChildScroll(); + SimulateTouchpadFling(child_view_->host()); + WaitForOOPIFScroll(GetChildNode()); +} +IN_PROC_BROWSER_TEST_F(BrowserSideFlingBrowserTest, + TouchscreenFlingBubblesFromOOPIF) { + LoadPageWithOOPIF(); + // Scroll the parent down so that it is scrollable upward. + EXPECT_TRUE( + ExecJs(GetRootNode()->current_frame_host(), "window.scrollTo(0, 20)")); + // We expect to have window.scrollY == 20 after scrolling but with zoom for + // dsf enabled on android we get window.scrollY == 19 (see + // https://crbug.com/891860). + WaitForOOPIFScroll(GetRootNode(), 19); + + // Fling and wait for the parent to scroll upward. + gfx::Vector2d fling_velocity(0, 2000); + SimulateTouchscreenFling(child_view_->host(), fling_velocity); + WaitForOOPIFScroll(GetRootNode(), 15, true /* upward */); +} +IN_PROC_BROWSER_TEST_F(BrowserSideFlingBrowserTest, + TouchpadFlingBubblesFromOOPIF) { + LoadPageWithOOPIF(); + // Scroll the parent down so that it is scrollable upward. + EXPECT_TRUE( + ExecJs(GetRootNode()->current_frame_host(), "window.scrollTo(0, 20)")); + // We expect to have window.scrollY == 20 after scrolling but with zoom for + // dsf enabled on android we get window.scrollY == 19 (see + // https://crbug.com/891860). + WaitForOOPIFScroll(GetRootNode(), 19); + + // Fling and wait for the parent to scroll upward. + gfx::Vector2d fling_velocity(0, 2000); + SimulateTouchpadFling(child_view_->host(), fling_velocity); + WaitForOOPIFScroll(GetRootNode(), 15, true /* upward */); } // Disabled on MacOS because it doesn't support touchscreen scroll.
diff --git a/content/browser/renderer_host/input/fling_controller.cc b/content/browser/renderer_host/input/fling_controller.cc index c09268d..99e08746 100644 --- a/content/browser/renderer_host/input/fling_controller.cc +++ b/content/browser/renderer_host/input/fling_controller.cc
@@ -190,13 +190,7 @@ current_fling_parameters_.velocity, current_fling_parameters_.source_device, current_fling_parameters_.modifiers); - // Wait for BeginFrame to call ProgressFling when - // SetNeedsBeginFrameForFlingProgress is used to progress flings instead of - // compositor animation observer (happens on Android WebView). - if (scheduler_client_->NeedsBeginFrameForFlingProgress()) - ScheduleFlingProgress(); - else - ProgressFling(clock_->NowTicks()); + ScheduleFlingProgress(); } void FlingController::ScheduleFlingProgress() {
diff --git a/content/browser/renderer_host/input/fling_controller.h b/content/browser/renderer_host/input/fling_controller.h index 3f02f83..10c07bf 100644 --- a/content/browser/renderer_host/input/fling_controller.h +++ b/content/browser/renderer_host/input/fling_controller.h
@@ -46,8 +46,6 @@ virtual void DidStopFlingingOnBrowser( base::WeakPtr<FlingController> fling_controller) = 0; - - virtual bool NeedsBeginFrameForFlingProgress() = 0; }; class CONTENT_EXPORT FlingController {
diff --git a/content/browser/renderer_host/input/fling_controller_unittest.cc b/content/browser/renderer_host/input/fling_controller_unittest.cc index 51e37f8..c73b6f6c 100644 --- a/content/browser/renderer_host/input/fling_controller_unittest.cc +++ b/content/browser/renderer_host/input/fling_controller_unittest.cc
@@ -42,12 +42,11 @@ class FlingControllerTest : public GestureEventQueueClient, public FlingControllerEventSenderClient, public FlingControllerSchedulerClient, - public testing::TestWithParam<bool> { + public testing::Test { public: // testing::Test FlingControllerTest() - : needs_begin_frame_for_fling_progress_(GetParam()), - scoped_task_environment_( + : scoped_task_environment_( base::test::ScopedTaskEnvironment::MainThreadType::UI) {} ~FlingControllerTest() override {} @@ -93,9 +92,6 @@ base::WeakPtr<FlingController> fling_controller) override { notified_client_after_fling_stop_ = true; } - bool NeedsBeginFrameForFlingProgress() override { - return needs_begin_frame_for_fling_progress_; - } void SimulateFlingStart(blink::WebGestureDevice source_device, const gfx::Vector2dF& velocity, @@ -157,15 +153,12 @@ private: base::SimpleTestTickClock mock_clock_; - bool needs_begin_frame_for_fling_progress_; base::test::ScopedTaskEnvironment scoped_task_environment_; std::unique_ptr<GestureEventQueue> queue_; DISALLOW_COPY_AND_ASSIGN(FlingControllerTest); }; -INSTANTIATE_TEST_CASE_P(, FlingControllerTest, testing::Bool()); - -TEST_P(FlingControllerTest, +TEST_F(FlingControllerTest, ControllerSendsWheelEndOnTouchpadFlingWithZeroVelocity) { SimulateFlingStart(blink::kWebGestureDeviceTouchpad, gfx::Vector2dF()); // The controller doesn't start a fling and sends a wheel end event @@ -176,7 +169,7 @@ EXPECT_EQ(0.f, last_sent_wheel_.delta_y); } -TEST_P(FlingControllerTest, +TEST_F(FlingControllerTest, ControllerSendsGSEOnTouchscreenFlingWithZeroVelocity) { SimulateFlingStart(blink::kWebGestureDeviceTouchscreen, gfx::Vector2dF()); // The controller doesn't start a fling and sends a GSE immediately. @@ -184,7 +177,7 @@ EXPECT_EQ(WebInputEvent::kGestureScrollEnd, last_sent_gesture_.GetType()); } -TEST_P(FlingControllerTest, ControllerHandlesTouchpadGestureFling) { +TEST_F(FlingControllerTest, ControllerHandlesTouchpadGestureFling) { SimulateFlingStart(blink::kWebGestureDeviceTouchpad, gfx::Vector2dF(1000, 0)); EXPECT_TRUE(FlingInProgress()); // Processing GFS will send the first fling prgoress event if the time delta @@ -223,7 +216,7 @@ EXPECT_EQ(0.f, last_sent_wheel_.delta_y); } -TEST_P(FlingControllerTest, ControllerHandlesTouchscreenGestureFling) { +TEST_F(FlingControllerTest, ControllerHandlesTouchscreenGestureFling) { SimulateFlingStart(blink::kWebGestureDeviceTouchscreen, gfx::Vector2dF(1000, 0)); EXPECT_TRUE(FlingInProgress()); @@ -248,7 +241,7 @@ EXPECT_EQ(WebInputEvent::kGestureScrollEnd, last_sent_gesture_.GetType()); } -TEST_P(FlingControllerTest, ControllerSendsWheelEndWhenTouchpadFlingIsOver) { +TEST_F(FlingControllerTest, ControllerSendsWheelEndWhenTouchpadFlingIsOver) { SimulateFlingStart(blink::kWebGestureDeviceTouchpad, gfx::Vector2dF(100, 0)); EXPECT_TRUE(FlingInProgress()); // Processing GFS will send the first fling prgoress event if the time delta @@ -281,7 +274,7 @@ EXPECT_EQ(0.f, last_sent_wheel_.delta_y); } -TEST_P(FlingControllerTest, ControllerSendsGSEWhenTouchscreenFlingIsOver) { +TEST_F(FlingControllerTest, ControllerSendsGSEWhenTouchscreenFlingIsOver) { SimulateFlingStart(blink::kWebGestureDeviceTouchscreen, gfx::Vector2dF(100, 0)); EXPECT_TRUE(FlingInProgress()); @@ -301,7 +294,7 @@ EXPECT_EQ(WebInputEvent::kGestureScrollEnd, last_sent_gesture_.GetType()); } -TEST_P(FlingControllerTest, +TEST_F(FlingControllerTest, EarlyTouchpadFlingCancelationOnInertialGSUAckNotConsumed) { SimulateFlingStart(blink::kWebGestureDeviceTouchpad, gfx::Vector2dF(1000, 0)); EXPECT_TRUE(FlingInProgress()); @@ -335,7 +328,7 @@ EXPECT_EQ(0.f, last_sent_wheel_.delta_y); } -TEST_P(FlingControllerTest, +TEST_F(FlingControllerTest, EarlyTouchscreenFlingCancelationOnInertialGSUAckNotConsumed) { SimulateFlingStart(blink::kWebGestureDeviceTouchscreen, gfx::Vector2dF(1000, 0)); @@ -360,7 +353,7 @@ EXPECT_EQ(WebInputEvent::kGestureScrollEnd, last_sent_gesture_.GetType()); } -TEST_P(FlingControllerTest, EarlyTouchpadFlingCancelationOnFlingStop) { +TEST_F(FlingControllerTest, EarlyTouchpadFlingCancelationOnFlingStop) { SimulateFlingStart(blink::kWebGestureDeviceTouchpad, gfx::Vector2dF(1000, 0)); EXPECT_TRUE(FlingInProgress()); // Processing GFS will send the first fling prgoress event if the time delta @@ -385,7 +378,7 @@ EXPECT_EQ(0.f, last_sent_wheel_.delta_y); } -TEST_P(FlingControllerTest, EarlyTouchscreenFlingCancelationOnFlingStop) { +TEST_F(FlingControllerTest, EarlyTouchscreenFlingCancelationOnFlingStop) { SimulateFlingStart(blink::kWebGestureDeviceTouchscreen, gfx::Vector2dF(1000, 0)); EXPECT_TRUE(FlingInProgress()); @@ -403,7 +396,7 @@ EXPECT_EQ(WebInputEvent::kGestureScrollEnd, last_sent_gesture_.GetType()); } -TEST_P(FlingControllerTest, GestureFlingCancelsFiltered) { +TEST_F(FlingControllerTest, GestureFlingCancelsFiltered) { // GFC without previous GFS is dropped. SimulateFlingCancel(blink::kWebGestureDeviceTouchscreen); EXPECT_TRUE(last_fling_cancel_filtered_); @@ -421,7 +414,7 @@ EXPECT_TRUE(last_fling_cancel_filtered_); } -TEST_P(FlingControllerTest, GestureFlingNotCancelledBySmallTimeDelta) { +TEST_F(FlingControllerTest, GestureFlingNotCancelledBySmallTimeDelta) { SimulateFlingStart(blink::kWebGestureDeviceTouchscreen, gfx::Vector2dF(1000, 0), false); EXPECT_TRUE(FlingInProgress()); @@ -444,7 +437,7 @@ EXPECT_GT(last_sent_gesture_.data.scroll_update.delta_x, 0.f); } -TEST_P(FlingControllerTest, GestureFlingWithNegativeTimeDelta) { +TEST_F(FlingControllerTest, GestureFlingWithNegativeTimeDelta) { base::TimeTicks initial_time = NowTicks(); AdvanceTime(); SimulateFlingStart(blink::kWebGestureDeviceTouchscreen, @@ -475,7 +468,7 @@ #else #define MAYBE_ControllerBoostsTouchpadFling ControllerBoostsTouchpadFling #endif -TEST_P(FlingControllerTest, MAYBE_ControllerBoostsTouchpadFling) { +TEST_F(FlingControllerTest, MAYBE_ControllerBoostsTouchpadFling) { SimulateFlingStart(blink::kWebGestureDeviceTouchpad, gfx::Vector2dF(1000, 0)); EXPECT_TRUE(FlingInProgress()); // Processing GFS will send the first fling prgoress event if the time delta @@ -510,7 +503,7 @@ EXPECT_TRUE(FlingBoosted()); } -TEST_P(FlingControllerTest, ControllerBoostsTouchscreenFling) { +TEST_F(FlingControllerTest, ControllerBoostsTouchscreenFling) { SimulateFlingStart(blink::kWebGestureDeviceTouchscreen, gfx::Vector2dF(1000, 0)); EXPECT_TRUE(FlingInProgress()); @@ -534,7 +527,7 @@ EXPECT_TRUE(FlingBoosted()); } -TEST_P(FlingControllerTest, ControllerNotifiesTheClientAfterFlingStart) { +TEST_F(FlingControllerTest, ControllerNotifiesTheClientAfterFlingStart) { SimulateFlingStart(blink::kWebGestureDeviceTouchscreen, gfx::Vector2dF(1000, 0)); EXPECT_TRUE(FlingInProgress()); @@ -553,7 +546,7 @@ EXPECT_TRUE(notified_client_after_fling_stop_); } -TEST_P(FlingControllerTest, MiddleClickAutoScrollFling) { +TEST_F(FlingControllerTest, MiddleClickAutoScrollFling) { SimulateFlingStart(blink::kWebGestureDeviceSyntheticAutoscroll, gfx::Vector2dF(1000, 0)); EXPECT_TRUE(FlingInProgress());
diff --git a/content/browser/renderer_host/input/fling_scheduler.cc b/content/browser/renderer_host/input/fling_scheduler.cc index 02772e70..63a6f7c 100644 --- a/content/browser/renderer_host/input/fling_scheduler.cc +++ b/content/browser/renderer_host/input/fling_scheduler.cc
@@ -52,10 +52,6 @@ host_->DidStopFlinging(); } -bool FlingScheduler::NeedsBeginFrameForFlingProgress() { - return !GetCompositor(); -} - void FlingScheduler::ProgressFlingOnBeginFrameIfneeded( base::TimeTicks current_time) { // No fling is active.
diff --git a/content/browser/renderer_host/input/fling_scheduler.h b/content/browser/renderer_host/input/fling_scheduler.h index 7e263503..634904e7 100644 --- a/content/browser/renderer_host/input/fling_scheduler.h +++ b/content/browser/renderer_host/input/fling_scheduler.h
@@ -28,7 +28,6 @@ base::WeakPtr<FlingController> fling_controller) override; void DidStopFlingingOnBrowser( base::WeakPtr<FlingController> fling_controller) override; - bool NeedsBeginFrameForFlingProgress() override; // FlingSchedulerBase void ProgressFlingOnBeginFrameIfneeded(base::TimeTicks current_time) override;
diff --git a/content/browser/renderer_host/input/fling_scheduler_android.cc b/content/browser/renderer_host/input/fling_scheduler_android.cc index 28cb2db..c2e9684 100644 --- a/content/browser/renderer_host/input/fling_scheduler_android.cc +++ b/content/browser/renderer_host/input/fling_scheduler_android.cc
@@ -50,14 +50,6 @@ host_->DidStopFlinging(); } -bool FlingSchedulerAndroid::NeedsBeginFrameForFlingProgress() { - ui::WindowAndroid* window = GetRootWindow(); - // If the root window does not have a Compositor (happens on Android - // WebView), we'll never receive an OnAnimate call. In this case fall back - // to BeginFrames coming from the host. - return !window || !window->GetCompositor(); -} - void FlingSchedulerAndroid::ProgressFlingOnBeginFrameIfneeded( base::TimeTicks current_time) { // If a WindowAndroid is being observed, there is no need for BeginFrames
diff --git a/content/browser/renderer_host/input/fling_scheduler_android.h b/content/browser/renderer_host/input/fling_scheduler_android.h index 3b54e4e..cbe1e6e1 100644 --- a/content/browser/renderer_host/input/fling_scheduler_android.h +++ b/content/browser/renderer_host/input/fling_scheduler_android.h
@@ -25,7 +25,6 @@ base::WeakPtr<FlingController> fling_controller) override; void DidStopFlingingOnBrowser( base::WeakPtr<FlingController> fling_controller) override; - bool NeedsBeginFrameForFlingProgress() override; // FlingSchedulerBase void ProgressFlingOnBeginFrameIfneeded(base::TimeTicks current_time) override;
diff --git a/content/browser/renderer_host/input/gesture_event_queue_unittest.cc b/content/browser/renderer_host/input/gesture_event_queue_unittest.cc index 34e5da17..aee20ab 100644 --- a/content/browser/renderer_host/input/gesture_event_queue_unittest.cc +++ b/content/browser/renderer_host/input/gesture_event_queue_unittest.cc
@@ -107,7 +107,6 @@ base::WeakPtr<FlingController> fling_controller) override {} void DidStopFlingingOnBrowser( base::WeakPtr<FlingController> fling_controller) override {} - bool NeedsBeginFrameForFlingProgress() override { return false; } protected: static GestureEventQueue::Config DefaultConfig() {
diff --git a/content/browser/renderer_host/input/mock_input_router_client.cc b/content/browser/renderer_host/input/mock_input_router_client.cc index c3e8f83c..3d93e01 100644 --- a/content/browser/renderer_host/input/mock_input_router_client.cc +++ b/content/browser/renderer_host/input/mock_input_router_client.cc
@@ -110,8 +110,4 @@ return white_listed_touch_action; } -bool MockInputRouterClient::NeedsBeginFrameForFlingProgress() { - return false; -} - } // namespace content
diff --git a/content/browser/renderer_host/input/mock_input_router_client.h b/content/browser/renderer_host/input/mock_input_router_client.h index 508701d..1ddce1a 100644 --- a/content/browser/renderer_host/input/mock_input_router_client.h +++ b/content/browser/renderer_host/input/mock_input_router_client.h
@@ -73,7 +73,6 @@ base::WeakPtr<FlingController> fling_controller) override {} void DidStopFlingingOnBrowser( base::WeakPtr<FlingController> fling_controller) override {} - bool NeedsBeginFrameForFlingProgress() override; private: InputRouter* input_router_;
diff --git a/content/browser/renderer_host/render_view_host_impl.cc b/content/browser/renderer_host/render_view_host_impl.cc index 1468588..9750d3c 100644 --- a/content/browser/renderer_host/render_view_host_impl.cc +++ b/content/browser/renderer_host/render_view_host_impl.cc
@@ -458,7 +458,8 @@ prefs.history_entry_requires_user_gesture = command_line.HasSwitch(switches::kHistoryEntryRequiresUserGesture); - prefs.disable_pushstate_throttle = + prefs.disable_ipc_flooding_protection = + command_line.HasSwitch(switches::kDisableIpcFloodingProtection) || command_line.HasSwitch(switches::kDisablePushStateThrottle); #if defined(OS_ANDROID)
diff --git a/content/browser/startup_helper.cc b/content/browser/startup_helper.cc new file mode 100644 index 0000000..8df403a4 --- /dev/null +++ b/content/browser/startup_helper.cc
@@ -0,0 +1,34 @@ +// 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 "content/browser/startup_helper.h" + +#include "base/base_switches.h" +#include "base/command_line.h" + +namespace content { + +std::unique_ptr<base::FieldTrialList> SetUpFieldTrialsAndFeatureList() { + auto field_trial_list = std::make_unique<base::FieldTrialList>(nullptr); + const base::CommandLine* command_line = + base::CommandLine::ForCurrentProcess(); + + // Ensure any field trials specified on the command line are initialized. + if (command_line->HasSwitch(::switches::kForceFieldTrials)) { + // Create field trials without activating them, so that this behaves in a + // consistent manner with field trials created from the server. + bool result = base::FieldTrialList::CreateTrialsFromString( + command_line->GetSwitchValueASCII(::switches::kForceFieldTrials), + std::set<std::string>()); + CHECK(result) << "Invalid --" << ::switches::kForceFieldTrials + << " list specified."; + } + + base::FeatureList::InitializeInstance( + command_line->GetSwitchValueASCII(switches::kEnableFeatures), + command_line->GetSwitchValueASCII(switches::kDisableFeatures)); + return field_trial_list; +} + +} // namespace content
diff --git a/content/browser/startup_helper.h b/content/browser/startup_helper.h new file mode 100644 index 0000000..01285782 --- /dev/null +++ b/content/browser/startup_helper.h
@@ -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. + +#ifndef CONTENT_BROWSER_STARTUP_HELPER_H_ +#define CONTENT_BROWSER_STARTUP_HELPER_H_ + +#include "base/metrics/field_trial.h" +#include "content/common/content_export.h" + +namespace content { + +// Setups fields trials and the FeatureList, and returns the unique pointer of +// the field trials. +std::unique_ptr<base::FieldTrialList> CONTENT_EXPORT +SetUpFieldTrialsAndFeatureList(); + +} // namespace content + +#endif // CONTENT_BROWSER_STARTUP_HELPER_H_
diff --git a/content/browser/tracing/background_tracing_manager_impl.cc b/content/browser/tracing/background_tracing_manager_impl.cc index 59cfcaf..5f488fcd 100644 --- a/content/browser/tracing/background_tracing_manager_impl.cc +++ b/content/browser/tracing/background_tracing_manager_impl.cc
@@ -673,7 +673,7 @@ return TraceConfig("blink.console,v8", record_mode); case BackgroundTracingConfigImpl::CategoryPreset::BENCHMARK_NAVIGATION: { auto config = TraceConfig( - "benchmark,toplevel,ipc,base,browser,navigation,omnibox,ui," + "benchmark,toplevel,ipc,base,browser,navigation,omnibox,ui,shutdown," "safe_browsing,task_scheduler," "disabled-by-default-task_scheduler_diagnostics," "disabled-by-default-system_stats,disabled-by-default-cpu_profiler",
diff --git a/content/browser/web_contents/web_contents_impl_unittest.cc b/content/browser/web_contents/web_contents_impl_unittest.cc index 78c6716..046668f3 100644 --- a/content/browser/web_contents/web_contents_impl_unittest.cc +++ b/content/browser/web_contents/web_contents_impl_unittest.cc
@@ -3140,59 +3140,51 @@ // Ensure that WebContentsImpl does not stop loading too early when there still // is a pending renderer. This can happen if a same-process non user-initiated // navigation completes while there is an ongoing cross-process navigation. -// TODO(fdegans): Rewrite the test for PlzNavigate when DidStartLoading and -// DidStopLoading are properly called. -TEST_F(WebContentsImplTest, NoEarlyStop) { +// TODO(clamy): Rewrite that test when the renderer-initiated non-user-initiated +// navigation no longer kills the speculative RenderFrameHost. See +// https://crbug.com/889039. +TEST_F(WebContentsImplTest, DISABLED_NoEarlyStop) { const GURL kUrl1("http://www.chromium.org"); const GURL kUrl2("http://www.google.com"); - const GURL kUrl3("http://www.wikipedia.org"); + const GURL kUrl3("http://www.chromium.org/foo"); contents()->NavigateAndCommit(kUrl1); TestRenderFrameHost* current_rfh = main_test_rfh(); - // Start a browser-initiated cross-process navigation to |kUrl2|. There should - // be a pending RenderFrameHost and the WebContents should be loading. - controller().LoadURL( - kUrl2, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string()); - int entry_id = controller().GetPendingEntry()->GetUniqueID(); - EXPECT_TRUE(contents()->CrossProcessNavigationPending()); + // Start a browser-initiated cross-process navigation to |kUrl2|. The + // WebContents should be loading. + auto cross_process_navigation = + NavigationSimulator::CreateBrowserInitiated(kUrl2, contents()); + cross_process_navigation->ReadyToCommit(); TestRenderFrameHost* pending_rfh = contents()->GetPendingMainFrame(); - ASSERT_TRUE(pending_rfh); EXPECT_TRUE(contents()->IsLoading()); // The current RenderFrameHost starts a non user-initiated render-initiated - // navigation and sends a DidStartLoading IPC. The WebContents should still be - // loading. - current_rfh->OnMessageReceived( - FrameHostMsg_DidStartLoading(current_rfh->GetRoutingID(), false)); - EXPECT_TRUE(contents()->IsLoading()); - - // Simulate the pending RenderFrameHost DidStartLoading. There should still be - // a pending RenderFrameHost and the WebContents should still be loading. - pending_rfh->PrepareForCommit(); - pending_rfh->OnMessageReceived( - FrameHostMsg_DidStartLoading(pending_rfh->GetRoutingID(), false)); - EXPECT_EQ(contents()->GetPendingMainFrame(), pending_rfh); + // navigation. The WebContents should still be loading. + auto same_process_navigation = + NavigationSimulator::CreateRendererInitiated(kUrl3, current_rfh); + same_process_navigation->SetHasUserGesture(false); + same_process_navigation->Start(); EXPECT_TRUE(contents()->IsLoading()); // Simulate the commit and DidStopLoading from the renderer-initiated // navigation in the current RenderFrameHost. There should still be a pending // RenderFrameHost and the WebContents should still be loading. - current_rfh->SendNavigateWithModificationCallback( - 0, true, kUrl3, base::Bind(SetAsNonUserGesture)); + same_process_navigation->Commit(); current_rfh->OnMessageReceived( FrameHostMsg_DidStopLoading(current_rfh->GetRoutingID())); EXPECT_EQ(contents()->GetPendingMainFrame(), pending_rfh); EXPECT_TRUE(contents()->IsLoading()); - // It should commit. + + // The same-process navigation should have committed. ASSERT_EQ(2, controller().GetEntryCount()); EXPECT_EQ(kUrl3, controller().GetLastCommittedEntry()->GetURL()); - // Commit the navigation. The formerly pending RenderFrameHost should now be - // the current RenderFrameHost and the WebContents should still be loading. - contents()->TestDidNavigate(pending_rfh, entry_id, true, kUrl2, - ui::PAGE_TRANSITION_TYPED); + // Commit the cross-process navigation. The formerly pending RenderFrameHost + // should now be the current RenderFrameHost and the WebContents should still + // be loading. + cross_process_navigation->Commit(); EXPECT_FALSE(contents()->GetPendingMainFrame()); TestRenderFrameHost* new_current_rfh = main_test_rfh(); EXPECT_EQ(new_current_rfh, pending_rfh);
diff --git a/content/common/frame_messages.h b/content/common/frame_messages.h index 506bef7..6bfafce 100644 --- a/content/common/frame_messages.h +++ b/content/common/frame_messages.h
@@ -1190,12 +1190,6 @@ int /* error_code */, base::string16 /* error_description */) -// Sent when the renderer starts loading the page. |to_different_document| will -// be true unless the load is a fragment navigation, or triggered by -// history.pushState/replaceState. -IPC_MESSAGE_ROUTED1(FrameHostMsg_DidStartLoading, - bool /* to_different_document */) - // Sent when the renderer is done loading a page. IPC_MESSAGE_ROUTED0(FrameHostMsg_DidStopLoading)
diff --git a/content/common/page_state_serialization.cc b/content/common/page_state_serialization.cc index 4231b01..ae64073 100644 --- a/content/common/page_state_serialization.cc +++ b/content/common/page_state_serialization.cc
@@ -25,17 +25,15 @@ #include "ui/gfx/geometry/mojo/geometry_struct_traits.h" #include "url/mojom/url_gurl_mojom_traits.h" -namespace mojom = content::history::mojom; - namespace content { #define STATIC_ASSERT_ENUM(a, b) \ static_assert(static_cast<int>(a) == static_cast<int>(b), \ "mismatching enums: " #a) -STATIC_ASSERT_ENUM(mojom::ScrollRestorationType::kAuto, +STATIC_ASSERT_ENUM(history::mojom::ScrollRestorationType::kAuto, blink::kWebHistoryScrollRestorationAuto); -STATIC_ASSERT_ENUM(mojom::ScrollRestorationType::kManual, +STATIC_ASSERT_ENUM(history::mojom::ScrollRestorationType::kManual, blink::kWebHistoryScrollRestorationManual); namespace { @@ -686,9 +684,9 @@ // "Modern" read/write functions start here. These are probably what you want. void WriteResourceRequestBody(const network::ResourceRequestBody& request_body, - mojom::RequestBody* mojo_body) { + history::mojom::RequestBody* mojo_body) { for (const auto& element : *request_body.elements()) { - mojom::ElementPtr data_element = mojom::Element::New(); + history::mojom::ElementPtr data_element = history::mojom::Element::New(); switch (element.type()) { case network::DataElement::TYPE_BYTES: { data_element->set_bytes(std::vector<unsigned char>( @@ -697,7 +695,7 @@ break; } case network::DataElement::TYPE_FILE: { - mojom::FilePtr file = mojom::File::New( + history::mojom::FilePtr file = history::mojom::File::New( element.path().AsUTF16Unsafe(), element.offset(), element.length(), element.expected_modification_time()); data_element->set_file(std::move(file)); @@ -721,27 +719,27 @@ } void ReadResourceRequestBody( - mojom::RequestBody* mojo_body, + history::mojom::RequestBody* mojo_body, const scoped_refptr<network::ResourceRequestBody>& request_body) { for (const auto& element : mojo_body->elements) { - mojom::Element::Tag tag = element->which(); + history::mojom::Element::Tag tag = element->which(); switch (tag) { - case mojom::Element::Tag::BYTES: + case history::mojom::Element::Tag::BYTES: AppendDataToRequestBody( request_body, reinterpret_cast<const char*>(element->get_bytes().data()), element->get_bytes().size()); break; - case mojom::Element::Tag::FILE: { - mojom::File* file = element->get_file().get(); + case history::mojom::Element::Tag::FILE: { + history::mojom::File* file = element->get_file().get(); AppendFileRangeToRequestBody(request_body, file->path, file->offset, file->length, file->modification_time); break; } - case mojom::Element::Tag::BLOB_UUID: + case history::mojom::Element::Tag::BLOB_UUID: AppendBlobToRequestBody(request_body, element->get_blob_uuid()); break; - case mojom::Element::Tag::DEPRECATED_FILE_SYSTEM_FILE: + case history::mojom::Element::Tag::DEPRECATED_FILE_SYSTEM_FILE: // No longer supported. break; } @@ -750,9 +748,9 @@ } void WriteHttpBody(const ExplodedHttpBody& http_body, - mojom::HttpBody* mojo_body) { + history::mojom::HttpBody* mojo_body) { if (http_body.request_body != nullptr) { - mojo_body->request_body = mojom::RequestBody::New(); + mojo_body->request_body = history::mojom::RequestBody::New(); mojo_body->contains_passwords = http_body.contains_passwords; mojo_body->http_content_type = http_body.http_content_type; WriteResourceRequestBody(*http_body.request_body, @@ -760,7 +758,8 @@ } } -void ReadHttpBody(mojom::HttpBody* mojo_body, ExplodedHttpBody* http_body) { +void ReadHttpBody(history::mojom::HttpBody* mojo_body, + ExplodedHttpBody* http_body) { http_body->contains_passwords = mojo_body->contains_passwords; http_body->http_content_type = mojo_body->http_content_type; if (mojo_body->request_body) { @@ -772,7 +771,7 @@ } void WriteFrameState(const ExplodedFrameState& state, - mojom::FrameState* frame) { + history::mojom::FrameState* frame) { frame->url_string = state.url_string; frame->referrer = state.referrer; frame->target = state.target; @@ -783,10 +782,11 @@ } frame->scroll_restoration_type = - static_cast<mojom::ScrollRestorationType>(state.scroll_restoration_type); + static_cast<history::mojom::ScrollRestorationType>( + state.scroll_restoration_type); if (state.did_save_scroll_or_scale_state) { - frame->view_state = mojom::ViewState::New(); + frame->view_state = history::mojom::ViewState::New(); frame->view_state->scroll_offset = state.scroll_offset; frame->view_state->visual_viewport_scroll_offset = state.visual_viewport_scroll_offset; @@ -807,19 +807,21 @@ frame->referrer_policy = state.referrer_policy; - frame->http_body = mojom::HttpBody::New(); + frame->http_body = history::mojom::HttpBody::New(); WriteHttpBody(state.http_body, frame->http_body.get()); // Subitems const std::vector<ExplodedFrameState>& children = state.children; for (const auto& child : children) { - mojom::FrameStatePtr child_frame = mojom::FrameState::New(); + history::mojom::FrameStatePtr child_frame = + history::mojom::FrameState::New(); WriteFrameState(child, child_frame.get()); frame->children.push_back(std::move(child_frame)); } } -void ReadFrameState(mojom::FrameState* frame, ExplodedFrameState* state) { +void ReadFrameState(history::mojom::FrameState* frame, + ExplodedFrameState* state) { state->url_string = frame->url_string; state->referrer = frame->referrer; state->target = frame->target; @@ -872,8 +874,9 @@ if (obj->parse_error) return; - mojom::PageStatePtr page; - obj->parse_error = !(mojom::PageState::Deserialize(tmp, length, &page)); + history::mojom::PageStatePtr page; + obj->parse_error = + !(history::mojom::PageState::Deserialize(tmp, length, &page)); if (obj->parse_error) return; @@ -891,15 +894,15 @@ void WriteMojoPageState(const ExplodedPageState& state, SerializeObject* obj) { WriteInteger(obj->version, obj); - mojom::PageStatePtr page = mojom::PageState::New(); + history::mojom::PageStatePtr page = history::mojom::PageState::New(); for (const auto& referenced_file : state.referenced_files) { page->referenced_files.push_back(referenced_file.value()); } - page->top = mojom::FrameState::New(); + page->top = history::mojom::FrameState::New(); WriteFrameState(state.top, page->top.get()); - std::vector<uint8_t> page_bytes = mojom::PageState::Serialize(&page); + std::vector<uint8_t> page_bytes = history::mojom::PageState::Serialize(&page); obj->pickle.WriteData(reinterpret_cast<char*>(page_bytes.data()), page_bytes.size()); }
diff --git a/content/public/app/content_main_delegate.cc b/content/public/app/content_main_delegate.cc index c4bdfd3..6fce3efb 100644 --- a/content/public/app/content_main_delegate.cc +++ b/content/public/app/content_main_delegate.cc
@@ -75,6 +75,10 @@ const base::Closure& quit_closure, service_manager::BackgroundServiceManager* service_manager) {} +bool ContentMainDelegate::ShouldCreateFeatureList() { + return true; +} + ContentBrowserClient* ContentMainDelegate::CreateContentBrowserClient() { #if defined(CHROME_MULTIPLE_DLL_CHILD) return NULL;
diff --git a/content/public/app/content_main_delegate.h b/content/public/app/content_main_delegate.h index 42310279..f0c23432 100644 --- a/content/public/app/content_main_delegate.h +++ b/content/public/app/content_main_delegate.h
@@ -129,9 +129,15 @@ // creating the main message loop. virtual void PreCreateMainMessageLoop() {} - // Allows the embedder to perform platform-specific initializatioion. For - // example, things that should be done right after TaskScheduler starts and - // the main MessageLoop was installed. + // Returns true if content should create field trials and initialize the + // FeatureList instance for this process. Default implementation returns true. + // Embedders that need to control when and/or how FeatureList should be + // created should override and return false. + virtual bool ShouldCreateFeatureList(); + + // Allows the embedder to perform its own initialization after content + // performed its own and already brought up MessageLoop, TaskScheduler, field + // tials and FeatureList (by default). virtual void PostEarlyInitialization() {} protected:
diff --git a/content/public/browser/browser_main_parts.cc b/content/public/browser/browser_main_parts.cc index 130ad375..7d75bc6f 100644 --- a/content/public/browser/browser_main_parts.cc +++ b/content/public/browser/browser_main_parts.cc
@@ -8,10 +8,6 @@ namespace content { -bool BrowserMainParts::ShouldContentCreateFeatureList() { - return true; -} - int BrowserMainParts::PreEarlyInitialization() { return service_manager::RESULT_CODE_NORMAL_EXIT; }
diff --git a/content/public/browser/browser_main_parts.h b/content/public/browser/browser_main_parts.h index 2013a970..9001f21 100644 --- a/content/public/browser/browser_main_parts.h +++ b/content/public/browser/browser_main_parts.h
@@ -54,11 +54,6 @@ BrowserMainParts() {} virtual ~BrowserMainParts() {} - // Returns true if content should create a FeatureList. Default - // implementation returns true. Embedders that need to control when and/or - // how FeatureList should be created should override and return false. - virtual bool ShouldContentCreateFeatureList(); - // A return value other than RESULT_CODE_NORMAL_EXIT indicates error and is // used as the exit status. virtual int PreEarlyInitialization();
diff --git a/content/public/common/common_param_traits_macros.h b/content/public/common/common_param_traits_macros.h index 09aa092..d993bd0 100644 --- a/content/public/common/common_param_traits_macros.h +++ b/content/public/common/common_param_traits_macros.h
@@ -133,7 +133,7 @@ IPC_STRUCT_TRAITS_MEMBER(application_cache_enabled) IPC_STRUCT_TRAITS_MEMBER(tabs_to_links) IPC_STRUCT_TRAITS_MEMBER(history_entry_requires_user_gesture) - IPC_STRUCT_TRAITS_MEMBER(disable_pushstate_throttle) + IPC_STRUCT_TRAITS_MEMBER(disable_ipc_flooding_protection) IPC_STRUCT_TRAITS_MEMBER(hyperlink_auditing_enabled) IPC_STRUCT_TRAITS_MEMBER(allow_universal_access_from_file_urls) IPC_STRUCT_TRAITS_MEMBER(allow_file_access_from_file_urls)
diff --git a/content/public/common/content_switches.cc b/content/public/common/content_switches.cc index e9f3fcc..02e5be2 100644 --- a/content/public/common/content_switches.cc +++ b/content/public/common/content_switches.cc
@@ -162,6 +162,12 @@ // many frames. Only effective if compositor image animations are enabled. const char kDisableImageAnimationResync[] = "disable-image-animation-resync"; +// Disables the IPC flooding protection. +// It is activated by default. Some javascript functions can be used to flood +// the browser process with IPC. This protection limits the rate at which they +// can be used. +const char kDisableIpcFloodingProtection[] = "disable-ipc-flooding-protection"; + // Suppresses hang monitor dialogs in renderer processes. This may allow slow // unload handlers on a page to prevent the tab from closing, but the Task // Manager can be used to terminate the offending process in this case.
diff --git a/content/public/common/content_switches.h b/content/public/common/content_switches.h index e7f9962..bb72c2f 100644 --- a/content/public/common/content_switches.h +++ b/content/public/common/content_switches.h
@@ -58,6 +58,7 @@ extern const char kDisableGpuProcessCrashLimit[]; CONTENT_EXPORT extern const char kDisableGpuWatchdog[]; CONTENT_EXPORT extern const char kDisableImageAnimationResync[]; +CONTENT_EXPORT extern const char kDisableIpcFloodingProtection[]; CONTENT_EXPORT extern const char kDisableJavaScriptHarmonyShipping[]; CONTENT_EXPORT extern const char kDisableLowLatencyDxva[]; CONTENT_EXPORT extern const char kDisableLowResTiling[];
diff --git a/content/public/common/web_preferences.cc b/content/public/common/web_preferences.cc index 581c666..5bede35 100644 --- a/content/public/common/web_preferences.cc +++ b/content/public/common/web_preferences.cc
@@ -97,7 +97,7 @@ application_cache_enabled(false), tabs_to_links(true), history_entry_requires_user_gesture(false), - disable_pushstate_throttle(false), + disable_ipc_flooding_protection(false), hyperlink_auditing_enabled(true), allow_universal_access_from_file_urls(false), allow_file_access_from_file_urls(false),
diff --git a/content/public/common/web_preferences.h b/content/public/common/web_preferences.h index c1881cb0..7fefb27b 100644 --- a/content/public/common/web_preferences.h +++ b/content/public/common/web_preferences.h
@@ -131,7 +131,7 @@ bool application_cache_enabled; bool tabs_to_links; bool history_entry_requires_user_gesture; - bool disable_pushstate_throttle; + bool disable_ipc_flooding_protection; bool hyperlink_auditing_enabled; bool allow_universal_access_from_file_urls; bool allow_file_access_from_file_urls;
diff --git a/content/public/test/browser_test_base.cc b/content/public/test/browser_test_base.cc index 71b1075..29f79761 100644 --- a/content/public/test/browser_test_base.cc +++ b/content/public/test/browser_test_base.cc
@@ -27,6 +27,7 @@ #include "content/browser/browser_thread_impl.h" #include "content/browser/renderer_host/render_process_host_impl.h" #include "content/browser/scheduler/browser_task_executor.h" +#include "content/browser/startup_helper.h" #include "content/browser/tracing/tracing_controller_impl.h" #include "content/public/app/content_main.h" #include "content/public/browser/browser_task_traits.h" @@ -326,6 +327,8 @@ params.ui_task = ui_task.release(); params.created_main_parts_closure = created_main_parts_closure.release(); base::TaskScheduler::Create("Browser"); + DCHECK(!field_trial_list_); + field_trial_list_ = SetUpFieldTrialsAndFeatureList(); BrowserTaskExecutor::Create(); // TODO(phajdan.jr): Check return code, http://crbug.com/374738 . BrowserMain(params);
diff --git a/content/public/test/navigation_simulator.cc b/content/public/test/navigation_simulator.cc index 2b214f6..f4c6fc1 100644 --- a/content/public/test/navigation_simulator.cc +++ b/content/public/test/navigation_simulator.cc
@@ -685,9 +685,6 @@ CHECK_EQ(STARTED, state_); } - render_frame_host_->OnMessageReceived( - FrameHostMsg_DidStartLoading(render_frame_host_->GetRoutingID(), false)); - FrameHostMsg_DidCommitProvisionalLoad_Params params; params.nav_entry_id = 0; params.url = navigation_url_;
diff --git a/content/renderer/render_frame_impl.cc b/content/renderer/render_frame_impl.cc index 8da77ba7..ee4469b 100644 --- a/content/renderer/render_frame_impl.cc +++ b/content/renderer/render_frame_impl.cc
@@ -3051,7 +3051,7 @@ } void RenderFrameImpl::PluginDidStartLoading() { - DidStartLoading(true); + DidStartLoading(); } void RenderFrameImpl::PluginDidStopLoading() { @@ -5932,16 +5932,10 @@ return true; } -void RenderFrameImpl::DidStartLoading(bool to_different_document) { +void RenderFrameImpl::DidStartLoading() { TRACE_EVENT1("navigation,rail", "RenderFrameImpl::didStartLoading", "id", routing_id_); render_view_->FrameDidStartLoading(frame_); - - // The browser is responsible for knowing the start of all non-synchronous - // navigations. - // TODO(clamy): Remove this IPC. - if (!to_different_document) - Send(new FrameHostMsg_DidStartLoading(routing_id_, to_different_document)); } void RenderFrameImpl::DidStopLoading() {
diff --git a/content/renderer/render_frame_impl.h b/content/renderer/render_frame_impl.h index 149529e..3b2515d 100644 --- a/content/renderer/render_frame_impl.h +++ b/content/renderer/render_frame_impl.h
@@ -337,9 +337,7 @@ // TODO(nasko): Those are page-level methods at this time and come from // WebViewClient. We should move them to be WebLocalFrameClient calls and put // logic in the browser side to balance starts/stops. - // |to_different_document| will be true unless the load is a fragment - // navigation, or triggered by history.pushState/replaceState. - void DidStartLoading(bool to_different_document) override; + void DidStartLoading() override; void DidStopLoading() override; void DidChangeLoadProgress(double load_progress) override;
diff --git a/content/renderer/render_view_impl.cc b/content/renderer/render_view_impl.cc index 05deb7b..fcab7999 100644 --- a/content/renderer/render_view_impl.cc +++ b/content/renderer/render_view_impl.cc
@@ -694,7 +694,8 @@ prefs.application_cache_enabled); settings->SetHistoryEntryRequiresUserGesture( prefs.history_entry_requires_user_gesture); - settings->SetShouldThrottlePushState(!prefs.disable_pushstate_throttle); + settings->SetShouldProtectAgainstIpcFlooding( + !prefs.disable_ipc_flooding_protection); settings->SetHyperlinkAuditingEnabled(prefs.hyperlink_auditing_enabled); settings->SetCookieEnabled(prefs.cookie_enabled); settings->SetNavigateOnDragDrop(prefs.navigate_on_drag_drop);
diff --git a/content/shell/android/shell_apk/src/org/chromium/content_shell_apk/ContentShellApplication.java b/content/shell/android/shell_apk/src/org/chromium/content_shell_apk/ContentShellApplication.java index 360d2285..f754e53 100644 --- a/content/shell/android/shell_apk/src/org/chromium/content_shell_apk/ContentShellApplication.java +++ b/content/shell/android/shell_apk/src/org/chromium/content_shell_apk/ContentShellApplication.java
@@ -25,8 +25,9 @@ @Override protected void attachBaseContext(Context base) { super.attachBaseContext(base); + boolean isBrowserProcess = !ContextUtils.getProcessName().contains(":"); ContextUtils.initApplicationContext(this); - if (ContextUtils.isMainProcess()) { + if (isBrowserProcess) { if (BuildConfig.IS_MULTIDEX_ENABLED) { ChromiumMultiDexInstaller.install(this); }
diff --git a/content/shell/browser/shell_browser_main_parts.cc b/content/shell/browser/shell_browser_main_parts.cc index 1d6e25d1..5dac9b3 100644 --- a/content/shell/browser/shell_browser_main_parts.cc +++ b/content/shell/browser/shell_browser_main_parts.cc
@@ -133,7 +133,6 @@ net::NetworkChangeNotifier::SetFactory( new net::NetworkChangeNotifierFactoryAndroid()); #endif - SetupFieldTrials(); return service_manager::RESULT_CODE_NORMAL_EXIT; } @@ -149,25 +148,6 @@ gfx::Size()); } -void ShellBrowserMainParts::SetupFieldTrials() { - DCHECK(!field_trial_list_); - field_trial_list_.reset(new base::FieldTrialList(nullptr)); - - const base::CommandLine* command_line = - base::CommandLine::ForCurrentProcess(); - - // Ensure any field trials specified on the command line are initialized. - if (command_line->HasSwitch(::switches::kForceFieldTrials)) { - // Create field trials without activating them, so that this behaves in a - // consistent manner with field trials created from the server. - bool result = base::FieldTrialList::CreateTrialsFromString( - command_line->GetSwitchValueASCII(::switches::kForceFieldTrials), - std::set<std::string>()); - CHECK(result) << "Invalid --" << ::switches::kForceFieldTrials - << " list specified."; - } -} - int ShellBrowserMainParts::PreCreateThreads() { #if defined(OS_ANDROID) const base::CommandLine* command_line =
diff --git a/content/shell/browser/shell_browser_main_parts.h b/content/shell/browser/shell_browser_main_parts.h index fc5c4eb..09de5a0 100644 --- a/content/shell/browser/shell_browser_main_parts.h +++ b/content/shell/browser/shell_browser_main_parts.h
@@ -55,7 +55,6 @@ } private: - void SetupFieldTrials(); std::unique_ptr<net::NetLog> net_log_; std::unique_ptr<ShellBrowserContext> browser_context_; @@ -65,10 +64,6 @@ const MainFunctionParams parameters_; bool run_message_loop_; - // Statistical testing infrastructure for the entire browser. nullptr until - // |SetupFieldTrials()| is called. - std::unique_ptr<base::FieldTrialList> field_trial_list_; - DISALLOW_COPY_AND_ASSIGN(ShellBrowserMainParts); };
diff --git a/content/test/test_render_frame_host.cc b/content/test/test_render_frame_host.cc index 151b260..6c427b77 100644 --- a/content/test/test_render_frame_host.cc +++ b/content/test/test_render_frame_host.cc
@@ -321,9 +321,6 @@ ui::PageTransition transition, int response_code, const ModificationCallback& callback) { - if (!IsBrowserSideNavigationEnabled()) - OnDidStartLoading(true); - FrameHostMsg_DidCommitProvisionalLoad_Params params; params.nav_entry_id = nav_entry_id; params.url = url;
diff --git a/device/bluetooth/dbus/bluetooth_dbus_client_bundle.cc b/device/bluetooth/dbus/bluetooth_dbus_client_bundle.cc index 3258c8b..9819427 100644 --- a/device/bluetooth/dbus/bluetooth_dbus_client_bundle.cc +++ b/device/bluetooth/dbus/bluetooth_dbus_client_bundle.cc
@@ -57,8 +57,6 @@ BluetoothGattDescriptorClient::Create()); bluetooth_gatt_manager_client_.reset(BluetoothGattManagerClient::Create()); bluetooth_gatt_service_client_.reset(BluetoothGattServiceClient::Create()); - - alternate_bluetooth_adapter_client_.reset(BluetoothAdapterClient::Create()); } else { bluetooth_adapter_client_.reset(new FakeBluetoothAdapterClient); bluetooth_le_advertising_manager_client_.reset( @@ -77,8 +75,6 @@ new FakeBluetoothGattDescriptorClient); bluetooth_gatt_manager_client_.reset(new FakeBluetoothGattManagerClient); bluetooth_gatt_service_client_.reset(new FakeBluetoothGattServiceClient); - - alternate_bluetooth_adapter_client_.reset(new FakeBluetoothAdapterClient); } }
diff --git a/device/bluetooth/dbus/bluetooth_dbus_client_bundle.h b/device/bluetooth/dbus/bluetooth_dbus_client_bundle.h index 3561896a..3d97ee8 100644 --- a/device/bluetooth/dbus/bluetooth_dbus_client_bundle.h +++ b/device/bluetooth/dbus/bluetooth_dbus_client_bundle.h
@@ -86,10 +86,6 @@ return bluetooth_profile_manager_client_.get(); } - BluetoothAdapterClient* alternate_bluetooth_adapter_client() { - return alternate_bluetooth_adapter_client_.get(); - } - private: friend class BluezDBusManagerSetter; @@ -113,9 +109,6 @@ std::unique_ptr<BluetoothProfileManagerClient> bluetooth_profile_manager_client_; - // See "Alternate D-Bus Client" note in bluez_dbus_manager.h. - std::unique_ptr<BluetoothAdapterClient> alternate_bluetooth_adapter_client_; - DISALLOW_COPY_AND_ASSIGN(BluetoothDBusClientBundle); };
diff --git a/device/bluetooth/dbus/bluez_dbus_manager.cc b/device/bluetooth/dbus/bluez_dbus_manager.cc index 1e71203f..a17917d 100644 --- a/device/bluetooth/dbus/bluez_dbus_manager.cc +++ b/device/bluetooth/dbus/bluez_dbus_manager.cc
@@ -43,11 +43,8 @@ static BluezDBusManager* g_bluez_dbus_manager = nullptr; static bool g_using_bluez_dbus_manager_for_testing = false; -BluezDBusManager::BluezDBusManager(dbus::Bus* bus, - dbus::Bus* alternate_bus, - bool use_dbus_fakes) +BluezDBusManager::BluezDBusManager(dbus::Bus* bus, bool use_dbus_fakes) : bus_(bus), - alternate_bus_(alternate_bus), object_manager_support_known_(false), object_manager_supported_(false), weak_ptr_factory_(this) { @@ -164,11 +161,6 @@ return client_bundle_->bluetooth_profile_manager_client(); } -BluetoothAdapterClient* BluezDBusManager::GetAlternateBluetoothAdapterClient() { - DCHECK(object_manager_support_known_); - return client_bundle_->alternate_bluetooth_adapter_client(); -} - void BluezDBusManager::OnObjectManagerSupported(dbus::Response* response) { VLOG(1) << "Bluetooth supported. Initializing clients."; object_manager_supported_ = true; @@ -223,9 +215,6 @@ GetSystemBus(), bluetooth_service_name); client_bundle_->bluetooth_profile_manager_client()->Init( GetSystemBus(), bluetooth_service_name); - - client_bundle_->alternate_bluetooth_adapter_client()->Init( - alternate_bus_, bluetooth_service_name); } std::string BluezDBusManager::GetBluetoothServiceName() { @@ -249,19 +238,10 @@ CHECK(!g_bluez_dbus_manager); #if defined(OS_CHROMEOS) - // On ChromeOS, BluetoothSystem needs a separate connection to Bluez, so we - // use BluezDBusThreadManager to get two different connections to the same - // services. This allows us to have two separate sets of clients in the same - // process. - BluezDBusThreadManager::Initialize(); - CreateGlobalInstance(chromeos::DBusThreadManager::Get()->GetSystemBus(), - BluezDBusThreadManager::Get()->GetSystemBus(), chromeos::DBusThreadManager::Get()->IsUsingFakes()); #elif defined(OS_LINUX) - // BluetoothSystem, the client that needs the extra connection, is not - // implemented on Linux, so no need for an extra Bus. - CreateGlobalInstance(BluezDBusThreadManager::Get()->GetSystemBus(), nullptr, + CreateGlobalInstance(BluezDBusThreadManager::Get()->GetSystemBus(), false /* use_dbus_stubs */); #endif } @@ -271,18 +251,16 @@ bluez::BluezDBusManager::GetSetterForTesting() { if (!g_using_bluez_dbus_manager_for_testing) { g_using_bluez_dbus_manager_for_testing = true; - CreateGlobalInstance(nullptr, nullptr, true); + CreateGlobalInstance(nullptr, true); } return base::WrapUnique(new BluezDBusManagerSetter()); } // static -void BluezDBusManager::CreateGlobalInstance(dbus::Bus* bus, - dbus::Bus* alternate_bus, - bool use_stubs) { +void BluezDBusManager::CreateGlobalInstance(dbus::Bus* bus, bool use_stubs) { CHECK(!g_bluez_dbus_manager); - g_bluez_dbus_manager = new BluezDBusManager(bus, alternate_bus, use_stubs); + g_bluez_dbus_manager = new BluezDBusManager(bus, use_stubs); } // static @@ -296,14 +274,8 @@ CHECK(g_bluez_dbus_manager); BluezDBusManager* dbus_manager = g_bluez_dbus_manager; g_bluez_dbus_manager = nullptr; - delete dbus_manager; - -#if defined(OS_CHROMEOS) - if (!g_using_bluez_dbus_manager_for_testing) - BluezDBusThreadManager::Shutdown(); -#endif - g_using_bluez_dbus_manager_for_testing = false; + delete dbus_manager; VLOG(1) << "BluezDBusManager Shutdown completed"; } @@ -392,10 +364,4 @@ ->client_bundle_->bluetooth_profile_manager_client_ = std::move(client); } -void BluezDBusManagerSetter::SetAlternateBluetoothAdapterClient( - std::unique_ptr<BluetoothAdapterClient> client) { - bluez::BluezDBusManager::Get() - ->client_bundle_->alternate_bluetooth_adapter_client_ = std::move(client); -} - } // namespace bluez
diff --git a/device/bluetooth/dbus/bluez_dbus_manager.h b/device/bluetooth/dbus/bluez_dbus_manager.h index 2202240..cf4c053 100644 --- a/device/bluetooth/dbus/bluez_dbus_manager.h +++ b/device/bluetooth/dbus/bluez_dbus_manager.h
@@ -53,20 +53,6 @@ // WeakPtrFactory when creating callbacks that run on UI thread. See // session_manager_client.cc for examples. // -// Alternate D-Bus Client: -// -// BluezDBusManager is used by two separate clients. If both clients used the -// same DBus connection to talk to BlueZ, then they could override each others' -// state. For example, clients can start a scan with a set of filters; if -// client #1 sets filter A, and then client #2 sets filter B, BlueZ would only -// scan with filter B. BlueZ distinguishes between clients based on their D-Bus -// connection, so if two clients with different connections try to start a scan -// with two filters, BlueZ will merge these filters. -// -// For this reason, BluezDBusManager keeps two sets of the same client and uses -// two separate D-Bus connections: "Bluetooth*Client" and -// "AlternateBluetooth*Client". - class DEVICE_BLUETOOTH_EXPORT BluezDBusManager { public: // Sets the global instance. Must be called before any calls to Get(). @@ -97,7 +83,7 @@ // Returns true once we know whether Object Manager is supported or not. // Until this method returns true, no classes should try to use the - // D-Bus Clients. + // DBus Clients. bool IsObjectManagerSupportKnown() { return object_manager_support_known_; } // Calls |callback| once we know whether Object Manager is supported or not. @@ -124,25 +110,17 @@ BluetoothMediaTransportClient* GetBluetoothMediaTransportClient(); BluetoothProfileManagerClient* GetBluetoothProfileManagerClient(); - // See "Alternate D-Bus Client" note above. - BluetoothAdapterClient* GetAlternateBluetoothAdapterClient(); - private: friend class BluezDBusManagerSetter; // Creates a new BluezDBusManager using the DBusClients set in - // |client_bundle|. |alternate_bus| is used by a separate set of D-Bus - // clients; see "Alternate D-Bus Client" note above. - explicit BluezDBusManager(dbus::Bus* bus, - dbus::Bus* alternate_bus, - bool use_stubs); + // |client_bundle|. + explicit BluezDBusManager(dbus::Bus* bus, bool use_stubs); ~BluezDBusManager(); // Creates a global instance of BluezDBusManager. Cannot be called more than // once. - static void CreateGlobalInstance(dbus::Bus* bus, - dbus::Bus* alternate_bus, - bool use_stubs); + static void CreateGlobalInstance(dbus::Bus* bus, bool use_stubs); void OnObjectManagerSupported(dbus::Response* response); void OnObjectManagerNotSupported(dbus::ErrorResponse* response); @@ -155,10 +133,6 @@ std::string GetBluetoothServiceName(); dbus::Bus* bus_; - // Separate D-Bus connection used by the "Alternate" set of D-Bus clients. See - // "Alternate D-Bus Client" note above. - dbus::Bus* alternate_bus_; - std::unique_ptr<BluetoothDBusClientBundle> client_bundle_; base::Closure object_manager_support_known_callback_; @@ -199,9 +173,6 @@ void SetBluetoothProfileManagerClient( std::unique_ptr<BluetoothProfileManagerClient> client); - void SetAlternateBluetoothAdapterClient( - std::unique_ptr<BluetoothAdapterClient> client); - private: friend class BluezDBusManager;
diff --git a/extensions/browser/api/display_source/OWNERS b/extensions/browser/api/display_source/OWNERS index bff88c9..b3fe3e5 100644 --- a/extensions/browser/api/display_source/OWNERS +++ b/extensions/browser/api/display_source/OWNERS
@@ -1 +1 @@ -alexander.shalamov@intel.com +eero.hakkinen@intel.com
diff --git a/extensions/browser/lazy_background_task_queue_unittest.cc b/extensions/browser/lazy_background_task_queue_unittest.cc index 8c77af3..51e81a58 100644 --- a/extensions/browser/lazy_background_task_queue_unittest.cc +++ b/extensions/browser/lazy_background_task_queue_unittest.cc
@@ -105,7 +105,7 @@ process_manager_ = static_cast<TestProcessManager*>( ProcessManagerFactory::GetInstance()->SetTestingFactoryAndUse( - browser_context(), CreateTestProcessManager)); + browser_context(), base::BindRepeating(&CreateTestProcessManager))); } void TearDown() override {
diff --git a/extensions/browser/test_event_router.h b/extensions/browser/test_event_router.h index f7f92bea..1d60a1b 100644 --- a/extensions/browser/test_event_router.h +++ b/extensions/browser/test_event_router.h
@@ -77,10 +77,10 @@ "T must be derived from EventRouter"); return static_cast<T*>( extensions::EventRouterFactory::GetInstance()->SetTestingFactoryAndUse( - context, [](content::BrowserContext* context) { + context, base::BindRepeating([](content::BrowserContext* context) { return static_cast<std::unique_ptr<KeyedService>>( std::make_unique<T>(context)); - })); + }))); } } // namespace extensions
diff --git a/extensions/renderer/api/display_source/OWNERS b/extensions/renderer/api/display_source/OWNERS index 29a7a21..b3fe3e5 100644 --- a/extensions/renderer/api/display_source/OWNERS +++ b/extensions/renderer/api/display_source/OWNERS
@@ -1,2 +1 @@ -alexander.shalamov@intel.com eero.hakkinen@intel.com
diff --git a/google_apis/gaia/gaia_auth_fetcher.cc b/google_apis/gaia/gaia_auth_fetcher.cc index 8f226bd..bf005da6 100644 --- a/google_apis/gaia/gaia_auth_fetcher.cc +++ b/google_apis/gaia/gaia_auth_fetcher.cc
@@ -1054,12 +1054,14 @@ GoogleServiceAuthError auth_error = GoogleServiceAuthError::AuthErrorNone(); if (net_error == net::Error::OK && response_code == net::HTTP_OK) { OAuthMultiloginResult result; - if (!OAuthMultiloginResult::CreateOAuthMultiloginResultFromString( - data, &result)) { - consumer_->OnOAuthMultiloginFailure(GoogleServiceAuthError( - GoogleServiceAuthError::UNEXPECTED_SERVICE_RESPONSE)); - } else + const GoogleServiceAuthError error = + OAuthMultiloginResult::CreateOAuthMultiloginResultFromString(data, + &result); + if (error.state() != GoogleServiceAuthError::State::NONE) { + consumer_->OnOAuthMultiloginFailure(error); + } else { consumer_->OnOAuthMultiloginSuccess(result); + } } else { auth_error = GenerateAuthError(data, net_error); consumer_->OnOAuthMultiloginFailure(auth_error);
diff --git a/google_apis/gaia/gaia_auth_fetcher_unittest.cc b/google_apis/gaia/gaia_auth_fetcher_unittest.cc index e48d124..5e267a6 100644 --- a/google_apis/gaia/gaia_auth_fetcher_unittest.cc +++ b/google_apis/gaia/gaia_auth_fetcher_unittest.cc
@@ -22,6 +22,7 @@ #include "google_apis/gaia/gaia_urls.h" #include "google_apis/gaia/google_service_auth_error.h" #include "google_apis/gaia/mock_url_fetcher_factory.h" +#include "google_apis/gaia/oauth_multilogin_result.h" #include "google_apis/google_api_keys.h" #include "net/base/load_flags.h" #include "net/base/net_errors.h" @@ -146,6 +147,8 @@ MOCK_METHOD1(OnClientOAuthSuccess, void(const GaiaAuthConsumer::ClientOAuthResult& result)); MOCK_METHOD1(OnMergeSessionSuccess, void(const std::string& data)); + MOCK_METHOD1(OnOAuthMultiloginSuccess, + void(const OAuthMultiloginResult& result)); MOCK_METHOD1(OnUberAuthTokenSuccess, void(const std::string& data)); MOCK_METHOD1(OnClientLoginFailure, void(const GoogleServiceAuthError& error)); @@ -155,6 +158,8 @@ void(GaiaAuthConsumer::TokenRevocationStatus status)); MOCK_METHOD1(OnMergeSessionFailure, void( const GoogleServiceAuthError& error)); + MOCK_METHOD1(OnOAuthMultiloginFailure, + void(const GoogleServiceAuthError& error)); MOCK_METHOD1(OnUberAuthTokenFailure, void( const GoogleServiceAuthError& error)); MOCK_METHOD1(OnListAccountsSuccess, void(const std::string& data)); @@ -377,6 +382,55 @@ EXPECT_FALSE(auth.HasPendingFetch()); } +TEST_F(GaiaAuthFetcherTest, MultiloginSuccess) { + MockGaiaConsumer consumer; + EXPECT_CALL(consumer, OnOAuthMultiloginSuccess(::testing::_)).Times(1); + + TestGaiaAuthFetcher auth(&consumer, std::string(), GetURLLoaderFactory()); + auth.StartOAuthMultilogin( + std::vector<GaiaAuthFetcher::MultiloginTokenIDPair>()); + + EXPECT_TRUE(auth.HasPendingFetch()); + auth.TestOnURLLoadCompleteInternal(net::OK, net::HTTP_OK, {}, + "\n{\"status\": \"OK\"}"); + + EXPECT_FALSE(auth.HasPendingFetch()); +} + +TEST_F(GaiaAuthFetcherTest, MultiloginFailureNetError) { + MockGaiaConsumer consumer; + EXPECT_CALL(consumer, OnOAuthMultiloginFailure(GoogleServiceAuthError( + GoogleServiceAuthError::REQUEST_CANCELED))) + .Times(1); + + TestGaiaAuthFetcher auth(&consumer, std::string(), GetURLLoaderFactory()); + auth.StartOAuthMultilogin( + std::vector<GaiaAuthFetcher::MultiloginTokenIDPair>()); + + EXPECT_TRUE(auth.HasPendingFetch()); + auth.TestOnURLLoadCompleteInternal(net::ERR_ABORTED, net::HTTP_OK, {}, + "\n{\"status\": \"OK\"}"); + + EXPECT_FALSE(auth.HasPendingFetch()); +} + +TEST_F(GaiaAuthFetcherTest, MultiloginFailureServerError) { + MockGaiaConsumer consumer; + EXPECT_CALL(consumer, OnOAuthMultiloginFailure(GoogleServiceAuthError( + GoogleServiceAuthError::SERVICE_ERROR))) + .Times(1); + + TestGaiaAuthFetcher auth(&consumer, std::string(), GetURLLoaderFactory()); + auth.StartOAuthMultilogin( + std::vector<GaiaAuthFetcher::MultiloginTokenIDPair>()); + + EXPECT_TRUE(auth.HasPendingFetch()); + auth.TestOnURLLoadCompleteInternal(net::OK, net::HTTP_OK, {}, + "\n{\"status\": \"ERROR\"}"); + + EXPECT_FALSE(auth.HasPendingFetch()); +} + TEST_F(GaiaAuthFetcherTest, UberAuthTokenSuccess) { MockGaiaConsumer consumer; EXPECT_CALL(consumer, OnUberAuthTokenSuccess("uberToken")).Times(1);
diff --git a/google_apis/gaia/oauth_multilogin_result.cc b/google_apis/gaia/oauth_multilogin_result.cc index 6212cbc..fd803f0 100644 --- a/google_apis/gaia/oauth_multilogin_result.cc +++ b/google_apis/gaia/oauth_multilogin_result.cc
@@ -15,6 +15,24 @@ } // static +GoogleServiceAuthError OAuthMultiloginResult::TryParseStatusFromValue( + base::DictionaryValue* dictionary_value) { + std::string status; + dictionary_value->GetString("status", &status); + if (status == "OK") { + return GoogleServiceAuthError::AuthErrorNone(); + } else if (status == "RETRY") { + // This is a transient error. + return GoogleServiceAuthError(GoogleServiceAuthError::SERVICE_UNAVAILABLE); + } else if (status == "INVALID_TOKENS") { + return GoogleServiceAuthError( + GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS); + } else { + return GoogleServiceAuthError(GoogleServiceAuthError::SERVICE_ERROR); + } +} + +// static base::StringPiece OAuthMultiloginResult::StripXSSICharacters( const std::string& raw_data) { base::StringPiece body(raw_data); @@ -73,17 +91,22 @@ } // static -bool OAuthMultiloginResult::CreateOAuthMultiloginResultFromString( +GoogleServiceAuthError +OAuthMultiloginResult::CreateOAuthMultiloginResultFromString( const std::string& raw_data, OAuthMultiloginResult* result) { base::StringPiece data = StripXSSICharacters(raw_data); std::unique_ptr<base::DictionaryValue> dictionary_value = base::DictionaryValue::From(base::JSONReader::Read(data)); if (!dictionary_value) { - return false; + return GoogleServiceAuthError( + GoogleServiceAuthError::UNEXPECTED_SERVICE_RESPONSE); } - result->TryParseCookiesFromValue(dictionary_value.get()); - return true; + const GoogleServiceAuthError error = + TryParseStatusFromValue(dictionary_value.get()); + if (error.state() == GoogleServiceAuthError::State::NONE) + result->TryParseCookiesFromValue(dictionary_value.get()); + return error; } OAuthMultiloginResult::~OAuthMultiloginResult() = default; \ No newline at end of file
diff --git a/google_apis/gaia/oauth_multilogin_result.h b/google_apis/gaia/oauth_multilogin_result.h index c6375ed..1efb7b0 100644 --- a/google_apis/gaia/oauth_multilogin_result.h +++ b/google_apis/gaia/oauth_multilogin_result.h
@@ -11,6 +11,7 @@ #include "base/time/time.h" #include "base/values.h" #include "google_apis/gaia/gaia_auth_util.h" +#include "google_apis/gaia/google_service_auth_error.h" #include "net/cookies/canonical_cookie.h" #include "net/cookies/cookie_constants.h" #include "net/url_request/url_request_status.h" @@ -24,8 +25,10 @@ std::vector<net::CanonicalCookie> cookies() const { return cookies_; } - // Returns true in case of success and false when there is a parse error. - static bool CreateOAuthMultiloginResultFromString( + // Parses cookies and status from JSON response. Maps status to + // GoogleServiceAuthError::State values or returns UNEXPECTED_SERVER_RESPONSE + // if JSON string cannot be parsed. + static GoogleServiceAuthError CreateOAuthMultiloginResultFromString( const std::string& data, OAuthMultiloginResult* result); @@ -37,6 +40,11 @@ // Response body that has a form of JSON contains protection characters // against XSSI that have to be removed. See go/xssi. static base::StringPiece StripXSSICharacters(const std::string& data); + + // Maps status in JSON response to one of the GoogleServiceAuthError state + // values. + static GoogleServiceAuthError TryParseStatusFromValue( + base::DictionaryValue* dictionary_value); }; #endif // GOOGLE_APIS_GAIA_OAUTH_MULTILOGIN_RESULT_H_ \ No newline at end of file
diff --git a/google_apis/gaia/oauth_multilogin_result_unittest.cc b/google_apis/gaia/oauth_multilogin_result_unittest.cc index 0741f90..905427b 100644 --- a/google_apis/gaia/oauth_multilogin_result_unittest.cc +++ b/google_apis/gaia/oauth_multilogin_result_unittest.cc
@@ -149,17 +149,125 @@ TEST(OAuthMultiloginResultTest, CreateOAuthMultiloginResultFromString) { OAuthMultiloginResult result1; - EXPECT_TRUE(OAuthMultiloginResult::CreateOAuthMultiloginResultFromString( - ")]}\'\n{}", &result1)); + EXPECT_EQ(OAuthMultiloginResult::CreateOAuthMultiloginResultFromString( + ")]}\'\n{ \"status\" : \"OK\" }", &result1) + .state(), + GoogleServiceAuthError::State::NONE); EXPECT_TRUE(result1.cookies().empty()); OAuthMultiloginResult result2; - EXPECT_TRUE(OAuthMultiloginResult::CreateOAuthMultiloginResultFromString( - "many_random_characters_before_newline\'\n{}", &result2)); + EXPECT_EQ( + OAuthMultiloginResult::CreateOAuthMultiloginResultFromString( + "many_random_characters_before_newline\'\n{ \"status\" : \"OK\" }", + &result2) + .state(), + GoogleServiceAuthError::State::NONE); EXPECT_TRUE(result2.cookies().empty()); OAuthMultiloginResult result3; - EXPECT_FALSE(OAuthMultiloginResult::CreateOAuthMultiloginResultFromString( - ")]}\'\n)]}'\n{}", &result3)); + EXPECT_EQ(OAuthMultiloginResult::CreateOAuthMultiloginResultFromString( + ")]}\'\n)]}'\n{ \"status\" : \"OK\" }", &result3) + .state(), + GoogleServiceAuthError::State::UNEXPECTED_SERVICE_RESPONSE); EXPECT_TRUE(result3.cookies().empty()); +} + +TEST(OAuthMultiloginResultTest, ProduceErrorFromResponseStatus) { + OAuthMultiloginResult result1; + std::string data_error_none = + R"()]}' + { + "status": "OK", + "cookies":[ + { + "name":"SID", + "value":"vAlUe1", + "domain":".google.ru", + "path":"/", + "isSecure":true, + "isHttpOnly":false, + "priority":"HIGH", + "maxAge":63070000 + } + ] + } + )"; + EXPECT_EQ(OAuthMultiloginResult::CreateOAuthMultiloginResultFromString( + data_error_none, &result1) + .state(), + GoogleServiceAuthError::State::NONE); + + OAuthMultiloginResult result2; + std::string data_error_transient = + R"(()]}' + { + "status": "RETRY", + "cookies":[ + { + "name":"SID", + "value":"vAlUe1", + "domain":".google.ru", + "path":"/", + "isSecure":true, + "isHttpOnly":false, + "priority":"HIGH", + "maxAge":63070000 + } + ] + } + )"; + EXPECT_TRUE(OAuthMultiloginResult::CreateOAuthMultiloginResultFromString( + data_error_transient, &result2) + .IsTransientError()); + + OAuthMultiloginResult result3; + // "ERROR" is a real response status that Gaia sends. This is a persistent + // error. + std::string data_error_persistent = + R"(()]}' + { + "status": "ERROR", + "cookies":[ + { + "name":"SID", + "value":"vAlUe1", + "domain":".google.ru", + "path":"/", + "isSecure":true, + "isHttpOnly":false, + "priority":"HIGH", + "maxAge":63070000 + } + ] + } + )"; + EXPECT_TRUE(OAuthMultiloginResult::CreateOAuthMultiloginResultFromString( + data_error_persistent, &result3) + .IsPersistentError()); + + OAuthMultiloginResult result4; + std::string data_error_invalid_credentials = + R"()]}' + { + "status": "INVALID_TOKENS", + "cookies":[ + { + "name":"SID", + "value":"vAlUe1", + "domain":".google.ru", + "path":"/", + "isSecure":true, + "isHttpOnly":false, + "priority":"HIGH", + "maxAge":63070000 + } + ] + } + )"; + const GoogleServiceAuthError error = + OAuthMultiloginResult::CreateOAuthMultiloginResultFromString( + data_error_invalid_credentials, &result4); + EXPECT_EQ(error.state(), + GoogleServiceAuthError::State::INVALID_GAIA_CREDENTIALS); + EXPECT_TRUE(error.IsPersistentError()); } \ No newline at end of file
diff --git a/ios/build/bots/chromium.fyi/ios11-beta-simulator.json b/ios/build/bots/chromium.fyi/ios11-beta-simulator.json index 5374b98f..d90ba2a 100644 --- a/ios/build/bots/chromium.fyi/ios11-beta-simulator.json +++ b/ios/build/bots/chromium.fyi/ios11-beta-simulator.json
@@ -12,77 +12,5 @@ "target_cpu=\"x64\"", "target_os=\"ios\"", "use_goma=true" - ], - "tests": [ - { - "include": "common_tests.json", - "device type": "iPhone X", - "os": "11.4", - "host os": "Mac-10.13", - "xcode build version": "9f2000" - }, - { - "include": "eg_tests.json", - "device type": "iPhone X", - "os": "11.4", - "host os": "Mac-10.13", - "xcode build version": "9f2000" - }, - { - "include": "eg_tests.json", - "device type": "iPad Air", - "os": "11.4", - "host os": "Mac-10.13", - "xcode build version": "9f2000" - }, - { - "include": "eg_tests.json", - "device type": "iPhone 5s", - "os": "11.4", - "host os": "Mac-10.13", - "xcode build version": "9f2000" - }, - { - "include": "eg_tests.json", - "device type": "iPhone 6s Plus", - "os": "11.4", - "host os": "Mac-10.13", - "xcode build version": "9f2000" - }, - { - "include": "screen_size_dependent_tests.json", - "device type": "iPad Air 2", - "os": "11.4", - "host os": "Mac-10.13", - "xcode build version": "9f2000" - }, - { - "include": "screen_size_dependent_tests.json", - "device type": "iPhone 5s", - "os": "11.4", - "host os": "Mac-10.13", - "xcode build version": "9f2000" - }, - { - "include": "screen_size_dependent_tests.json", - "device type": "iPhone 6s", - "os": "11.4", - "host os": "Mac-10.13", - "xcode build version": "9f2000" - }, - { - "include": "screen_size_dependent_tests.json", - "device type": "iPhone 6s Plus", - "os": "11.4", - "host os": "Mac-10.13", - "xcode build version": "9f2000" - }, - { - "include": "screen_size_dependent_tests.json", - "device type": "iPhone X", - "os": "11.4", - "host os": "Mac-10.13", - "xcode build version": "9f2000" - } ] }
diff --git a/ios/build/bots/tests/eg_tests.json b/ios/build/bots/tests/eg_tests.json index a2cc88b..7ea59225 100644 --- a/ios/build/bots/tests/eg_tests.json +++ b/ios/build/bots/tests/eg_tests.json
@@ -8,6 +8,13 @@ "xctest": true }, { + "app": "ios_chrome_manual_fill_egtests", + "test args": [ + "--enable-features=AutofillManualFallback" + ], + "xctest": true + }, + { "app": "ios_chrome_web_egtests", "xctest": true },
diff --git a/ios/chrome/app/strings/ios_strings.grd b/ios/chrome/app/strings/ios_strings.grd index 49e9830..2cc41dc 100644 --- a/ios/chrome/app/strings/ios_strings.grd +++ b/ios/chrome/app/strings/ios_strings.grd
@@ -864,13 +864,16 @@ <message name="IDS_IOS_MANAGED_SWITCH_TITLE" desc="The title of the Switch from a managed account dialog. [40em]"> Sign out of managed account </message> + <message name="IDS_IOS_MANUAL_FALLBACK_MANAGE_PASSWORDS" desc="The title for the button in the manual fallback UI that takes the user to the passwords settings. In this screen they see all the passwords and can erase them. Note it is different from IDS_IOS_MANUAL_FALLBACK_USE_OTHER_PASSWORD_WITH_DOTS [30em]"> + Manage Passwords... + </message> <message name="IDS_IOS_MANUAL_FALLBACK_NO_USERNAME" desc="The title for disabled buttons on the manual fallback passwords UI when a credential doesn't contains a username. [30em]"> No Username </message> <message name="IDS_IOS_MANUAL_FALLBACK_USE_OTHER_PASSWORD" desc="The title for the manual fallback UI with all passwords without filter. [30em]"> Use Other Password </message> - <message name="IDS_IOS_MANUAL_FALLBACK_USE_OTHER_PASSWORD_WITH_DOTS" desc="The title for the button at the end of the manual fallback passwords UI. The button is used to open a new screen with the list of all the user credentials. [30em]"> + <message name="IDS_IOS_MANUAL_FALLBACK_USE_OTHER_PASSWORD_WITH_DOTS" desc="The title for the button in the manual fallback passwords UI that is used to open a list of all the user credentials where they can select one to fill a form. This button is showed at the same time as a different button with IDS_IOS_MANUAL_FALLBACK_MANAGE_PASSWORDS as title. [30em]"> Use Other Password... </message> <message name="IDS_IOS_MICROPHONE_USAGE_DESCRIPTION" desc="Specifies the reason for accessing the user's microphone while the app is in use [Length: unlimited] [iOS only].">
diff --git a/ios/chrome/app/tests_fake_hook.mm b/ios/chrome/app/tests_fake_hook.mm index a3137d7..b502b62 100644 --- a/ios/chrome/app/tests_fake_hook.mm +++ b/ios/chrome/app/tests_fake_hook.mm
@@ -31,10 +31,6 @@ bool DisableUpdateService() { return false; } -// TODO(crbug.com/885003) : Remove this hook. -bool ForceWKWebViewSnapshots() { - return false; -} void SetUpTestsIfPresent() {} void RunTestsIfPresent() {}
diff --git a/ios/chrome/app/tests_hook.h b/ios/chrome/app/tests_hook.h index 16d0db4..e92cafa1 100644 --- a/ios/chrome/app/tests_hook.h +++ b/ios/chrome/app/tests_hook.h
@@ -36,11 +36,6 @@ // infobar won't be shown during testing. bool DisableUpdateService(); -// TODO(crbug.com/885003) : Remove this hook. -// Returns true if the WKWebView snapshotting API will be used, overriding the -// flag value. -bool ForceWKWebViewSnapshots(); - // Global integration tests setup. This is not used by EarlGrey-based // integration tests. void SetUpTestsIfPresent();
diff --git a/ios/chrome/browser/autofill/form_input_accessory_consumer.h b/ios/chrome/browser/autofill/form_input_accessory_consumer.h index 9910bd6..c5fb7ed1 100644 --- a/ios/chrome/browser/autofill/form_input_accessory_consumer.h +++ b/ios/chrome/browser/autofill/form_input_accessory_consumer.h
@@ -14,9 +14,17 @@ // Removes the animations on the custom keyboard view. - (void)removeAnimationsOnKeyboardView; -// Restores the keyboard and its default input accessory view, removing (if -// necessary) any previously-added custom view. -- (void)restoreKeyboardView; +// Removes the presented keyboard view and the input accessory view. Also clears +// the references to them, so nothing shows until a new custom view is passed. +- (void)restoreOriginalKeyboardView; + +// Removes the presented keyboard view and the input accessory view until +// |continueCustomKeyboardView| is called. +- (void)pauseCustomKeyboardView; + +// Adds the previously presented views to the keyboard. If they have not been +// reset. +- (void)continueCustomKeyboardView; // Hides the default input accessory view and replaces it with one that shows // |customView| and form navigation controls.
diff --git a/ios/chrome/browser/autofill/form_input_accessory_view_controller.mm b/ios/chrome/browser/autofill/form_input_accessory_view_controller.mm index 5af3cc8..d0fa79a 100644 --- a/ios/chrome/browser/autofill/form_input_accessory_view_controller.mm +++ b/ios/chrome/browser/autofill/form_input_accessory_view_controller.mm
@@ -29,6 +29,12 @@ // The keyboard replacement view, if any. @property(nonatomic, weak) UIView* keyboardReplacementView; +// The custom view that should be shown in the input accessory view. +@property(nonatomic, strong) FormInputAccessoryView* customAccessoryView; + +// If this view controller is paused it shouldn't add its views to the keyboard. +@property(nonatomic, getter=isPaused) BOOL paused; + // Called when the keyboard will or did change frame. - (void)keyboardWillOrDidChangeFrame:(NSNotification*)notification; @@ -38,16 +44,10 @@ // Last registered keyboard rectangle. CGRect _keyboardFrame; - // The custom view that should be shown in the input accessory view. - FormInputAccessoryView* _customAccessoryView; - // Whether suggestions have previously been shown. BOOL _suggestionsHaveBeenShown; } -@synthesize grayBackgroundView = _grayBackgroundView; -@synthesize keyboardReplacementView = _keyboardReplacementView; - #pragma mark - Life Cycle - (instancetype)init { @@ -88,6 +88,9 @@ #pragma mark - Public - (void)presentView:(UIView*)view { + if (self.paused) { + return; + } DCHECK(view); DCHECK(!view.superview); UIView* keyboardView = [self getKeyboardView]; @@ -110,14 +113,14 @@ if (IsIPadIdiom()) { // On iPad, there's no inputAccessoryView available, so we attach the custom // view directly to the keyboard view instead. - [_customAccessoryView removeFromSuperview]; + [self.customAccessoryView removeFromSuperview]; [self.grayBackgroundView removeFromSuperview]; // If the keyboard isn't visible don't show the custom view. if (CGRectIntersection([UIScreen mainScreen].bounds, _keyboardFrame) .size.height == 0 || CGRectEqualToRect(_keyboardFrame, CGRectZero)) { - _customAccessoryView = nil; + self.customAccessoryView = nil; return; } @@ -128,36 +131,41 @@ if (formSuggestionView) { int numSuggestions = [[formSuggestionView suggestions] count]; if (!_suggestionsHaveBeenShown && numSuggestions == 0) { - _customAccessoryView = nil; + self.customAccessoryView = nil; return; } } _suggestionsHaveBeenShown = YES; - _customAccessoryView = [[FormInputAccessoryView alloc] init]; - [_customAccessoryView setUpWithCustomView:view]; + self.customAccessoryView = [[FormInputAccessoryView alloc] init]; + [self.customAccessoryView setUpWithCustomView:view]; [self addCustomAccessoryViewIfNeeded]; } else { // On iPhone, the custom view replaces the default UI of the // inputAccessoryView. - [self restoreInputAccessoryView]; - _customAccessoryView = [[FormInputAccessoryView alloc] init]; - [_customAccessoryView setUpWithNavigationDelegate:navigationDelegate - customView:view]; + [self restoreOriginalInputAccessoryView]; + self.customAccessoryView = [[FormInputAccessoryView alloc] init]; + [self.customAccessoryView setUpWithNavigationDelegate:navigationDelegate + customView:view]; [self addCustomAccessoryViewIfNeeded]; } } -- (void)restoreInputAccessoryView { - [_customAccessoryView removeFromSuperview]; - [self.grayBackgroundView removeFromSuperview]; - _customAccessoryView = nil; -} - -- (void)restoreKeyboardView { - [self restoreInputAccessoryView]; +- (void)restoreOriginalKeyboardView { + [self restoreOriginalInputAccessoryView]; [self.keyboardReplacementView removeFromSuperview]; self.keyboardReplacementView = nil; + self.paused = NO; +} + +- (void)pauseCustomKeyboardView { + [self removeCustomInputAccessoryView]; + [self.keyboardReplacementView removeFromSuperview]; + self.paused = YES; +} + +- (void)continueCustomKeyboardView { + self.paused = NO; } - (void)removeAnimationsOnKeyboardView { @@ -170,6 +178,18 @@ #pragma mark - Private +// Removes the custom views related to the input accessory view. +- (void)removeCustomInputAccessoryView { + [self.customAccessoryView removeFromSuperview]; + [self.grayBackgroundView removeFromSuperview]; +} + +// Removes the custom input accessory views and clears the references. +- (void)restoreOriginalInputAccessoryView { + [self removeCustomInputAccessoryView]; + self.customAccessoryView = nil; +} + // This searches in a keyboard view hierarchy for the best candidate to // constrain a view to the keyboard. - (UIView*)recursiveGetKeyboardConstraintView:(UIView*)view { @@ -230,9 +250,7 @@ // will appear. if (!IsIPadIdiom()) { [self addCustomAccessoryViewIfNeeded]; - } - if (self.keyboardReplacementView) { - [self presentView:self.keyboardReplacementView]; + [self addCustomKeyboardViewIfNeeded]; } } @@ -251,53 +269,65 @@ } // On ipad we hide the views so they don't stick around at the bottom. Only // needed on iPad because we add the view directly to the keyboard view. - if (IsIPadIdiom() && _customAccessoryView) { + if (IsIPadIdiom() && self.customAccessoryView) { if (@available(iOS 11, *)) { } else { // [iPad iOS 10] There is a bug when constraining something to the // keyboard view. So this updates the frame instead. CGFloat height = autofill::kInputAccessoryHeight; - _customAccessoryView.frame = + self.customAccessoryView.frame = CGRectMake(keyboardView.frame.origin.x, -height, keyboardView.frame.size.width, height); } if (CGRectEqualToRect(_keyboardFrame, CGRectZero)) { - _customAccessoryView.hidden = true; + self.customAccessoryView.hidden = true; self.grayBackgroundView.hidden = true; } else { - _customAccessoryView.hidden = false; + self.customAccessoryView.hidden = false; self.grayBackgroundView.hidden = false; } } } +- (void)addCustomKeyboardViewIfNeeded { + if (self.isPaused) { + return; + } + if (self.keyboardReplacementView && !self.keyboardReplacementView.superview) { + [self presentView:self.keyboardReplacementView]; + } +} + // Adds the customAccessoryView and the backgroundView (on iPads), if those are // not already in the hierarchy. - (void)addCustomAccessoryViewIfNeeded { - if (_customAccessoryView && !_customAccessoryView.superview) { + if (self.isPaused) { + return; + } + if (self.customAccessoryView && !self.customAccessoryView.superview) { if (IsIPadIdiom()) { UIView* keyboardView = [self getKeyboardView]; // [iPad iOS 10] There is a bug when constraining something to the // keyboard view. So this sets the frame instead. if (@available(iOS 11, *)) { - _customAccessoryView.translatesAutoresizingMaskIntoConstraints = NO; - [keyboardView addSubview:_customAccessoryView]; + self.customAccessoryView.translatesAutoresizingMaskIntoConstraints = NO; + [keyboardView addSubview:self.customAccessoryView]; [NSLayoutConstraint activateConstraints:@[ - [_customAccessoryView.leadingAnchor + [self.customAccessoryView.leadingAnchor constraintEqualToAnchor:keyboardView.leadingAnchor], - [_customAccessoryView.trailingAnchor + [self.customAccessoryView.trailingAnchor constraintEqualToAnchor:keyboardView.trailingAnchor], - [_customAccessoryView.bottomAnchor + [self.customAccessoryView.bottomAnchor constraintEqualToAnchor:keyboardView.topAnchor], - [_customAccessoryView.heightAnchor + [self.customAccessoryView.heightAnchor constraintEqualToConstant:autofill::kInputAccessoryHeight] ]]; } else { CGFloat height = autofill::kInputAccessoryHeight; - _customAccessoryView.frame = + self.customAccessoryView.frame = CGRectMake(keyboardView.frame.origin.x, -height, keyboardView.frame.size.width, height); - [keyboardView addSubview:_customAccessoryView]; + [keyboardView addSubview:self.customAccessoryView]; } if (!self.grayBackgroundView.superview) { [keyboardView addSubview:self.grayBackgroundView]; @@ -308,8 +338,8 @@ UIResponder* firstResponder = GetFirstResponder(); UIView* inputAccessoryView = firstResponder.inputAccessoryView; if (inputAccessoryView) { - [inputAccessoryView addSubview:_customAccessoryView]; - AddSameConstraints(_customAccessoryView, inputAccessoryView); + [inputAccessoryView addSubview:self.customAccessoryView]; + AddSameConstraints(self.customAccessoryView, inputAccessoryView); } } }
diff --git a/ios/chrome/browser/autofill/form_suggestion_controller_unittest.mm b/ios/chrome/browser/autofill/form_suggestion_controller_unittest.mm index 743ac7f3..c52a9db 100644 --- a/ios/chrome/browser/autofill/form_suggestion_controller_unittest.mm +++ b/ios/chrome/browser/autofill/form_suggestion_controller_unittest.mm
@@ -208,7 +208,7 @@ [view removeFromSuperview]; } }; - [[[mock_consumer_ stub] andDo:mockRestore] restoreKeyboardView]; + [[[mock_consumer_ stub] andDo:mockRestore] restoreOriginalKeyboardView]; accessory_mediator_ = [[FormInputAccessoryMediator alloc] initWithConsumer:mock_consumer_
diff --git a/ios/chrome/browser/snapshots/snapshot_generator.mm b/ios/chrome/browser/snapshots/snapshot_generator.mm index b44499b..3b4bdbc 100644 --- a/ios/chrome/browser/snapshots/snapshot_generator.mm +++ b/ios/chrome/browser/snapshots/snapshot_generator.mm
@@ -259,7 +259,7 @@ _webState->TakeSnapshot( webViewSnapshotFrame, base::BindOnce(^(gfx::Image image) { SnapshotGenerator* strongSelf = weakSelf; - if (!strongSelf) + if (!strongSelf || !_webState) return; UIImage* snapshot = image.ToUIImage(); if (overlays.count > 0) { @@ -457,8 +457,6 @@ #pragma mark - Properties. - (SnapshotCache*)snapshotCache { - DCHECK(_webState); - DCHECK(_webState->GetBrowserState()); return SnapshotCacheFactory::GetForBrowserState( ios::ChromeBrowserState::FromBrowserState(_webState->GetBrowserState())); }
diff --git a/ios/chrome/browser/ui/BUILD.gn b/ios/chrome/browser/ui/BUILD.gn index 77a4819..71fde2c 100644 --- a/ios/chrome/browser/ui/BUILD.gn +++ b/ios/chrome/browser/ui/BUILD.gn
@@ -348,6 +348,7 @@ "//ios/chrome/browser/ui/authentication", "//ios/chrome/browser/ui/authentication/consent_bump", "//ios/chrome/browser/ui/autofill:autofill", + "//ios/chrome/browser/ui/autofill/manual_fill", "//ios/chrome/browser/ui/bookmarks", "//ios/chrome/browser/ui/browser_container", "//ios/chrome/browser/ui/browser_container:ui",
diff --git a/ios/chrome/browser/ui/autofill/form_input_accessory_coordinator.h b/ios/chrome/browser/ui/autofill/form_input_accessory_coordinator.h index 6949fa84..3dbb98d 100644 --- a/ios/chrome/browser/ui/autofill/form_input_accessory_coordinator.h +++ b/ios/chrome/browser/ui/autofill/form_input_accessory_coordinator.h
@@ -11,11 +11,22 @@ class WebStateList; +// Delegate for the coordinator actions. +@protocol FormInputAccessoryCoordinatorDelegate<NSObject> + +// Opens the passwords settings. +- (void)openPasswordSettings; + +@end + // Creates and manages a custom input accessory view while the user is // interacting with a form. Also handles hiding and showing the default // accessory view elements. @interface FormInputAccessoryCoordinator : ChromeCoordinator +// The delegate for the password coordinator. Must be set before it starts. +@property(nonatomic, weak) id<FormInputAccessoryCoordinatorDelegate> delegate; + // Creates a coordinator that uses a |viewController| a |browserState| and // a |webStateList|. - (instancetype)initWithBaseViewController:(UIViewController*)viewController
diff --git a/ios/chrome/browser/ui/autofill/form_input_accessory_coordinator.mm b/ios/chrome/browser/ui/autofill/form_input_accessory_coordinator.mm index e527160..3e49373 100644 --- a/ios/chrome/browser/ui/autofill/form_input_accessory_coordinator.mm +++ b/ios/chrome/browser/ui/autofill/form_input_accessory_coordinator.mm
@@ -17,7 +17,8 @@ #endif @interface FormInputAccessoryCoordinator ()< - ManualFillAccessoryViewControllerDelegate> + ManualFillAccessoryViewControllerDelegate, + PasswordCoordinatorDelegate> // The Mediator for the input accessory view controller. @property(nonatomic, strong) @@ -84,7 +85,7 @@ - (void)stop { [self stopChildren]; [self.manualFillAccessoryViewController reset]; - [self.formInputAccessoryViewController restoreKeyboardView]; + [self.formInputAccessoryViewController restoreOriginalKeyboardView]; } #pragma mark - Presenting Children @@ -103,6 +104,7 @@ browserState:self.browserState webStateList:self.webStateList injectionHandler:self.manualFillInjectionHandler]; + passwordCoordinator.delegate = self; [self.formInputAccessoryViewController presentView:passwordCoordinator.viewController.view]; [self.childCoordinators addObject:passwordCoordinator]; @@ -132,4 +134,10 @@ [self startPasswords]; } +#pragma mark - PasswordCoordinatorDelegate + +- (void)openPasswordSettings { + [self.delegate openPasswordSettings]; +} + @end
diff --git a/ios/chrome/browser/ui/autofill/form_input_accessory_mediator.mm b/ios/chrome/browser/ui/autofill/form_input_accessory_mediator.mm index db61696..15ec596 100644 --- a/ios/chrome/browser/ui/autofill/form_input_accessory_mediator.mm +++ b/ios/chrome/browser/ui/autofill/form_input_accessory_mediator.mm
@@ -164,7 +164,9 @@ } - (void)keyboardDidHide { - [self reset]; + if (_webState && _webState->IsVisible()) { + [self reset]; + } } #pragma mark - FormActivityObserver @@ -198,6 +200,11 @@ #pragma mark - CRWWebStateObserver +- (void)webStateWasShown:(web::WebState*)webState { + DCHECK_EQ(_webState, webState); + [self.consumer continueCustomKeyboardView]; +} + - (void)webStateWasHidden:(web::WebState*)webState { DCHECK_EQ(_webState, webState); // On some iPhone with newers iOS (>11.3) when a view controller is presented, @@ -209,6 +216,8 @@ // element gets the focus. On iPad the keyboard stays dismissed. if (IsIPadIdiom()) { [self reset]; + } else { + [self.consumer pauseCustomKeyboardView]; } } @@ -229,6 +238,7 @@ oldWebState:(web::WebState*)oldWebState atIndex:(int)atIndex reason:(int)reason { + [self reset]; [self updateWithNewWebState:newWebState]; } @@ -289,7 +299,7 @@ // Resets the current provider, the consumer view and the navigation handler. As // well as reenables suggestions. - (void)reset { - [self.consumer restoreKeyboardView]; + [self.consumer restoreOriginalKeyboardView]; [self.manualFillAccessoryViewController reset]; [self.formInputAccessoryHandler reset]; @@ -400,7 +410,7 @@ // begins editing, reset ourselves so that we don't present our custom view over // the keyboard. - (void)handleTextInputDidBeginEditing:(NSNotification*)notification { - [self reset]; + [self.consumer pauseCustomKeyboardView]; } #pragma mark - Tests
diff --git a/ios/chrome/browser/ui/autofill/manual_fill/BUILD.gn b/ios/chrome/browser/ui/autofill/manual_fill/BUILD.gn index d9b0f76..ad9f099 100644 --- a/ios/chrome/browser/ui/autofill/manual_fill/BUILD.gn +++ b/ios/chrome/browser/ui/autofill/manual_fill/BUILD.gn
@@ -111,12 +111,18 @@ testonly = true sources = [ "keyboard_observer_egtest.mm", + "password_view_controller_egtest.mm", ] deps = [ ":manual_fill", ":manual_fill_ui", "//base", "//base/test:test_support", + "//components/autofill/core/common", + "//components/keyed_service/core", + "//components/password_manager/core/browser", + "//ios/chrome/browser/passwords", + "//ios/chrome/browser/ui:ui_util", "//ios/chrome/test/app:test_support", "//ios/chrome/test/earl_grey:test_support", "//ios/testing/earl_grey:earl_grey_support",
diff --git a/ios/chrome/browser/ui/autofill/manual_fill/action_cell.h b/ios/chrome/browser/ui/autofill/manual_fill/action_cell.h index 5b515eb..9a1e711 100644 --- a/ios/chrome/browser/ui/autofill/manual_fill/action_cell.h +++ b/ios/chrome/browser/ui/autofill/manual_fill/action_cell.h
@@ -22,9 +22,10 @@ // A table view cell which contains a button and holds an action block, which // is called when the button is touched. @interface ManualFillActionCell : UITableViewCell - // Updates the cell with the passed title and action block. -- (void)setUpWithTitle:(NSString*)title action:(void (^)(void))action; +- (void)setUpWithTitle:(NSString*)title + accessibilityID:(NSString*)accessibilityID + action:(void (^)(void))action; @end
diff --git a/ios/chrome/browser/ui/autofill/manual_fill/action_cell.mm b/ios/chrome/browser/ui/autofill/manual_fill/action_cell.mm index c47966c..144da80 100644 --- a/ios/chrome/browser/ui/autofill/manual_fill/action_cell.mm +++ b/ios/chrome/browser/ui/autofill/manual_fill/action_cell.mm
@@ -21,14 +21,14 @@ static const CGFloat iOS10MarginFontMultiplier = 1.18; // The base top margin, only used in iOS 10. Refer to // |iOS10MarginFontMultiplier| for how it is used. -static const CGFloat iOS10BaseTopMargin = 24; +static const CGFloat iOS10BaseTopMargin = 4; // The base bottom margin, only used in iOS 10. Refer to // |iOS10MarginFontMultiplier| for how it is used. -static const CGFloat iOS10BaseBottomMargin = 6; +static const CGFloat iOS10BaseBottomMargin = 4; // The multiplier for the base system spacing at the top margin. -static const CGFloat TopBaseSystemSpacingMultiplier = 1.78; +static const CGFloat TopBaseSystemSpacingMultiplier = 1.1; // The multiplier for the base system spacing at the bottom margin. -static const CGFloat BottomBaseSystemSpacingMultiplier = 2.26; +static const CGFloat BottomBaseSystemSpacingMultiplier = 1.5; } // namespace @interface ManualFillActionItem () @@ -39,8 +39,6 @@ @end @implementation ManualFillActionItem -@synthesize action = _action; -@synthesize title = _title; - (instancetype)initWithTitle:(NSString*)title action:(void (^)(void))action { self = [super initWithType:kItemTypeEnumZero]; @@ -55,7 +53,10 @@ - (void)configureCell:(ManualFillActionCell*)cell withStyler:(ChromeTableViewStyler*)styler { [super configureCell:cell withStyler:styler]; - [cell setUpWithTitle:self.title action:self.action]; + cell.accessibilityIdentifier = nil; + [cell setUpWithTitle:self.title + accessibilityID:self.accessibilityIdentifier + action:self.action]; } @end @@ -76,13 +77,19 @@ - (void)prepareForReuse { [super prepareForReuse]; self.action = nil; + [self.titleButton setTitle:nil forState:UIControlStateNormal]; + self.titleButton.accessibilityIdentifier = nil; } -- (void)setUpWithTitle:(NSString*)title action:(void (^)(void))action { +- (void)setUpWithTitle:(NSString*)title + accessibilityID:(NSString*)accessibilityID + action:(void (^)(void))action { if (self.contentView.subviews.count == 0) { [self createView]; } + [self.titleButton setTitle:title forState:UIControlStateNormal]; + self.titleButton.accessibilityIdentifier = accessibilityID; self.action = action; }
diff --git a/ios/chrome/browser/ui/autofill/manual_fill/manual_fill_accessory_view_controller.h b/ios/chrome/browser/ui/autofill/manual_fill/manual_fill_accessory_view_controller.h index 51082f7..bae9fc4 100644 --- a/ios/chrome/browser/ui/autofill/manual_fill/manual_fill_accessory_view_controller.h +++ b/ios/chrome/browser/ui/autofill/manual_fill/manual_fill_accessory_view_controller.h
@@ -7,6 +7,19 @@ #import <UIKit/UIKit.h> +namespace manual_fill { + +// Accessibility identifier of the keyboard button. +extern NSString* const AccessoryKeyboardAccessibilityIdentifier; +// Accessibility identifier of the password button. +extern NSString* const AccessoryPasswordAccessibilityIdentifier; +// Accessibility identifier of the address button. +extern NSString* const AccessoryAddressAccessibilityIdentifier; +// Accessibility identifier of the credit card button. +extern NSString* const AccessoryCreditCardAccessibilityIdentifier; + +} // namespace manual_fill + // Protocol to handle user interactions in a ManualFillAccessoryViewController. @protocol ManualFillAccessoryViewControllerDelegate
diff --git a/ios/chrome/browser/ui/autofill/manual_fill/manual_fill_accessory_view_controller.mm b/ios/chrome/browser/ui/autofill/manual_fill/manual_fill_accessory_view_controller.mm index c63ebc1..6d2065e 100644 --- a/ios/chrome/browser/ui/autofill/manual_fill/manual_fill_accessory_view_controller.mm +++ b/ios/chrome/browser/ui/autofill/manual_fill/manual_fill_accessory_view_controller.mm
@@ -12,6 +12,19 @@ #error "This file requires ARC support." #endif +namespace manual_fill { + +NSString* const AccessoryKeyboardAccessibilityIdentifier = + @"kManualFillAccessoryKeyboardAccessibilityIdentifier"; +NSString* const AccessoryPasswordAccessibilityIdentifier = + @"kManualFillAccessoryPasswordAccessibilityIdentifier"; +NSString* const AccessoryAddressAccessibilityIdentifier = + @"kManualFillAccessoryAddressAccessibilityIdentifier"; +NSString* const AccessoryCreditCardAccessibilityIdentifier = + @"kManualFillAccessoryCreditCardAccessibilityIdentifier"; + +} // namespace manual_fill + static NSTimeInterval MFAnimationDuration = 0.20; @interface ManualFillAccessoryViewController () @@ -58,6 +71,8 @@ [self.keyboardButton addTarget:self action:@selector(keyboardButtonPressed) forControlEvents:UIControlEventTouchUpInside]; + self.keyboardButton.accessibilityIdentifier = + manual_fill::AccessoryKeyboardAccessibilityIdentifier; self.passwordButton = [UIButton buttonWithType:UIButtonTypeSystem]; UIImage* keyImage = [UIImage imageNamed:@"ic_vpn_key"]; @@ -67,6 +82,8 @@ [self.passwordButton addTarget:self action:@selector(passwordButtonPressed) forControlEvents:UIControlEventTouchUpInside]; + self.passwordButton.accessibilityIdentifier = + manual_fill::AccessoryPasswordAccessibilityIdentifier; NSArray* views; if (autofill::features::IsAutofillManualFallbackEnabled()) { @@ -78,6 +95,8 @@ [self.cardsButton addTarget:self action:@selector(cardButtonPressed) forControlEvents:UIControlEventTouchUpInside]; + self.cardsButton.accessibilityIdentifier = + manual_fill::AccessoryCreditCardAccessibilityIdentifier; self.accountButton = [UIButton buttonWithType:UIButtonTypeSystem]; UIImage* accountImage = [UIImage imageNamed:@"addresses"]; @@ -87,6 +106,8 @@ [self.accountButton addTarget:self action:@selector(accountButtonPressed) forControlEvents:UIControlEventTouchUpInside]; + self.accountButton.accessibilityIdentifier = + manual_fill::AccessoryAddressAccessibilityIdentifier; views = @[ self.keyboardButton, self.passwordButton, self.accountButton,
diff --git a/ios/chrome/browser/ui/autofill/manual_fill/password_coordinator.h b/ios/chrome/browser/ui/autofill/manual_fill/password_coordinator.h index 3f4ca71..914fa26 100644 --- a/ios/chrome/browser/ui/autofill/manual_fill/password_coordinator.h +++ b/ios/chrome/browser/ui/autofill/manual_fill/password_coordinator.h
@@ -10,6 +10,14 @@ @class ManualFillInjectionHandler; class WebStateList; +// Delegate for the coordinator actions. +@protocol PasswordCoordinatorDelegate<NSObject> + +// Opens the passwords settings. +- (void)openPasswordSettings; + +@end + // Creates and manages a view controller to present passwords to the user. // Any selected password will be sent to the current field in the active web // state. @@ -18,6 +26,9 @@ // The view controller of this coordinator. @property(nonatomic, readonly) UIViewController* viewController; +// The delegate for this coordinator. +@property(nonatomic, weak) id<PasswordCoordinatorDelegate> delegate; + // Creates a coordinator that uses a |viewController|, |browserState|, // |webStateList| and an |injectionHandler|. - (instancetype)
diff --git a/ios/chrome/browser/ui/autofill/manual_fill/password_coordinator.mm b/ios/chrome/browser/ui/autofill/manual_fill/password_coordinator.mm index ab89d264..fe37eb30 100644 --- a/ios/chrome/browser/ui/autofill/manual_fill/password_coordinator.mm +++ b/ios/chrome/browser/ui/autofill/manual_fill/password_coordinator.mm
@@ -107,4 +107,8 @@ completion:nil]; } +- (void)openPasswordSettings { + [self.delegate openPasswordSettings]; +} + @end
diff --git a/ios/chrome/browser/ui/autofill/manual_fill/password_list_delegate.h b/ios/chrome/browser/ui/autofill/manual_fill/password_list_delegate.h index 944c226..9e7fc6b6 100644 --- a/ios/chrome/browser/ui/autofill/manual_fill/password_list_delegate.h +++ b/ios/chrome/browser/ui/autofill/manual_fill/password_list_delegate.h
@@ -11,6 +11,8 @@ - (void)dismissPresentedViewController; // Requests to open the list of all passwords. - (void)openAllPasswordsList; +// Opens passwords settings. +- (void)openPasswordSettings; @end #endif // IOS_CHROME_BROWSER_UI_AUTOFILL_MANUAL_FILL_PASSWORD_LIST_DELEGATE_H_
diff --git a/ios/chrome/browser/ui/autofill/manual_fill/password_mediator.h b/ios/chrome/browser/ui/autofill/manual_fill/password_mediator.h index 998f09a..a414521 100644 --- a/ios/chrome/browser/ui/autofill/manual_fill/password_mediator.h +++ b/ios/chrome/browser/ui/autofill/manual_fill/password_mediator.h
@@ -19,6 +19,13 @@ class WebStateList; +namespace manual_fill { + +extern NSString* const ManagePasswordsAccessibilityIdentifier; +extern NSString* const OtherPasswordsAccessibilityIdentifier; + +} // namespace manual_fill + // Object in charge of getting the passwords relevant for the manual fill // passwords UI. @interface ManualFillPasswordMediator : NSObject<UISearchResultsUpdating>
diff --git a/ios/chrome/browser/ui/autofill/manual_fill/password_mediator.mm b/ios/chrome/browser/ui/autofill/manual_fill/password_mediator.mm index b63cb3f..f519683 100644 --- a/ios/chrome/browser/ui/autofill/manual_fill/password_mediator.mm +++ b/ios/chrome/browser/ui/autofill/manual_fill/password_mediator.mm
@@ -29,6 +29,15 @@ #error "This file requires ARC support." #endif +namespace manual_fill { + +NSString* const ManagePasswordsAccessibilityIdentifier = + @"kManualFillManagePasswordsAccessibilityIdentifier"; +NSString* const OtherPasswordsAccessibilityIdentifier = + @"kManualFillOtherPasswordsAccessibilityIdentifier"; + +} // namespace manual_fill + @interface ManualFillPasswordMediator ()<ManualFillContentDelegate, PasswordFetcherDelegate> // The |WebStateList| containing the active web state. Used to filter the list @@ -166,16 +175,28 @@ return; } if (self.isAllPasswordButtonEnabled) { - NSString* titleString = l10n_util::GetNSString( + NSString* otherPasswordsTitleString = l10n_util::GetNSString( IDS_IOS_MANUAL_FALLBACK_USE_OTHER_PASSWORD_WITH_DOTS); __weak __typeof(self) weakSelf = self; auto otherPasswordsItem = [[ManualFillActionItem alloc] - initWithTitle:titleString + initWithTitle:otherPasswordsTitleString action:^{ [weakSelf.navigationDelegate openAllPasswordsList]; }]; - [self.consumer presentActions:@[ otherPasswordsItem ]]; + otherPasswordsItem.accessibilityIdentifier = + manual_fill::OtherPasswordsAccessibilityIdentifier; + + NSString* managePasswordsTitle = + l10n_util::GetNSString(IDS_IOS_MANUAL_FALLBACK_MANAGE_PASSWORDS); + auto managePasswordsItem = [[ManualFillActionItem alloc] + initWithTitle:managePasswordsTitle + action:^{ + [weakSelf.navigationDelegate openPasswordSettings]; + }]; + managePasswordsItem.accessibilityIdentifier = + manual_fill::ManagePasswordsAccessibilityIdentifier; + [self.consumer presentActions:@[ otherPasswordsItem, managePasswordsItem ]]; } else { [self.consumer presentActions:@[]]; }
diff --git a/ios/chrome/browser/ui/autofill/manual_fill/password_view_controller.h b/ios/chrome/browser/ui/autofill/manual_fill/password_view_controller.h index e319cea7..c1539a0 100644 --- a/ios/chrome/browser/ui/autofill/manual_fill/password_view_controller.h +++ b/ios/chrome/browser/ui/autofill/manual_fill/password_view_controller.h
@@ -10,6 +10,13 @@ #import "ios/chrome/browser/ui/autofill/manual_fill/password_consumer.h" #import "ios/chrome/browser/ui/table_view/chrome_table_view_controller.h" +namespace manual_fill { + +extern NSString* const PasswordSearchBarAccessibilityIdentifier; +extern NSString* const PasswordTableViewAccessibilityIdentifier; + +} // namespace manual_fill + // This class presents a list of usernames and passwords in a table view. @interface PasswordViewController : ChromeTableViewController<ManualFillPasswordConsumer>
diff --git a/ios/chrome/browser/ui/autofill/manual_fill/password_view_controller.mm b/ios/chrome/browser/ui/autofill/manual_fill/password_view_controller.mm index 11d2f94..e5a60c9 100644 --- a/ios/chrome/browser/ui/autofill/manual_fill/password_view_controller.mm +++ b/ios/chrome/browser/ui/autofill/manual_fill/password_view_controller.mm
@@ -15,6 +15,15 @@ #error "This file requires ARC support." #endif +namespace manual_fill { + +NSString* const PasswordSearchBarAccessibilityIdentifier = + @"kManualFillPasswordSearchBarAccessibilityIdentifier"; +NSString* const PasswordTableViewAccessibilityIdentifier = + @"kManualFillPasswordTableViewAccessibilityIdentifier"; + +} // namespace manual_fill + namespace { typedef NS_ENUM(NSInteger, SectionIdentifier) { @@ -51,9 +60,11 @@ self.tableView.separatorStyle = UITableViewCellSeparatorStyleNone; self.tableView.sectionHeaderHeight = 0; - self.tableView.sectionFooterHeight = 0; + self.tableView.sectionFooterHeight = 20.0; self.tableView.estimatedRowHeight = 200; self.tableView.separatorInset = UIEdgeInsetsMake(0, 0, 0, 0); + self.tableView.accessibilityIdentifier = + manual_fill::PasswordTableViewAccessibilityIdentifier; self.definesPresentationContext = YES; self.searchController.searchBar.backgroundColor = [UIColor clearColor]; @@ -64,6 +75,8 @@ } else { self.tableView.tableHeaderView = self.searchController.searchBar; } + self.searchController.searchBar.accessibilityIdentifier = + manual_fill::PasswordSearchBarAccessibilityIdentifier; NSString* titleString = l10n_util::GetNSString(IDS_IOS_MANUAL_FALLBACK_USE_OTHER_PASSWORD); self.title = titleString;
diff --git a/ios/chrome/browser/ui/autofill/manual_fill/password_view_controller_egtest.mm b/ios/chrome/browser/ui/autofill/manual_fill/password_view_controller_egtest.mm new file mode 100644 index 0000000..4d8b1f88 --- /dev/null +++ b/ios/chrome/browser/ui/autofill/manual_fill/password_view_controller_egtest.mm
@@ -0,0 +1,351 @@ +// 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 <EarlGrey/EarlGrey.h> +#import <EarlGrey/GREYKeyboard.h> + +#include "base/ios/ios_util.h" +#include "base/strings/sys_string_conversions.h" +#include "base/strings/utf_string_conversions.h" +#import "base/test/ios/wait_util.h" +#include "components/autofill/core/common/autofill_features.h" +#include "components/autofill/core/common/password_form.h" +#include "components/keyed_service/core/service_access_type.h" +#include "components/password_manager/core/browser/password_store.h" +#include "components/password_manager/core/browser/password_store_consumer.h" +#include "ios/chrome/browser/passwords/ios_chrome_password_store_factory.h" +#import "ios/chrome/browser/ui/autofill/manual_fill/manual_fill_accessory_view_controller.h" +#import "ios/chrome/browser/ui/autofill/manual_fill/password_mediator.h" +#import "ios/chrome/browser/ui/autofill/manual_fill/password_view_controller.h" +#import "ios/chrome/browser/ui/ui_util.h" +#import "ios/chrome/test/app/chrome_test_util.h" +#import "ios/chrome/test/earl_grey/chrome_actions.h" +#import "ios/chrome/test/earl_grey/chrome_earl_grey.h" +#import "ios/chrome/test/earl_grey/chrome_matchers.h" +#import "ios/chrome/test/earl_grey/chrome_test_case.h" +#import "ios/web/public/test/earl_grey/web_view_matchers.h" +#include "ios/web/public/test/element_selector.h" +#include "net/test/embedded_test_server/embedded_test_server.h" +#include "url/gurl.h" + +#if !defined(__has_feature) || !__has_feature(objc_arc) +#error "This file requires ARC support." +#endif + +namespace { + +const char kFormElementUsername[] = "username"; + +const char kExampleUsername[] = "concrete username"; +const char kExamplePassword[] = "concrete password"; + +const char kFormHTMLFile[] = "/username_password_field_form.html"; + +// Returns a matcher for the password icon in the keyboard accessory bar. +id<GREYMatcher> PasswordIconMatcher() { + return grey_accessibilityID( + manual_fill::AccessoryPasswordAccessibilityIdentifier); +} + +// Returns a matcher for the password table view in manual fallback. +id<GREYMatcher> PasswordTableViewMatcher() { + return grey_accessibilityID( + manual_fill::PasswordTableViewAccessibilityIdentifier); +} + +// Returns a matcher for the password search bar in manual fallback. +id<GREYMatcher> PasswordSearchBarMatcher() { + return grey_accessibilityID( + manual_fill::PasswordSearchBarAccessibilityIdentifier); +} + +// Returns a matcher for the button to open password settings in manual +// fallback. +id<GREYMatcher> ManagePasswordsMatcher() { + return grey_accessibilityID( + manual_fill::ManagePasswordsAccessibilityIdentifier); +} + +// Returns a matcher for the button to open all passwords in manual fallback. +id<GREYMatcher> OtherPasswordsMatcher() { + return grey_accessibilityID( + manual_fill::OtherPasswordsAccessibilityIdentifier); +} + +// Returns a matcher for the example username in the list. +id<GREYMatcher> UsernameButtonMatcher() { + return grey_buttonTitle(base::SysUTF8ToNSString(kExampleUsername)); +} + +// Returns a matcher for the password settings collection view. +id<GREYMatcher> PasswordSettingsMatcher() { + return grey_accessibilityID(@"SavePasswordsCollectionViewController"); +} + +// Returns a matcher for the search bar in password settings. +id<GREYMatcher> PasswordSettingsSearchMatcher() { + return grey_accessibilityID(@"SettingsSearchCellTextField"); +} + +// Gets the current password store. +scoped_refptr<password_manager::PasswordStore> GetPasswordStore() { + // ServiceAccessType governs behaviour in Incognito: only modifications with + // EXPLICIT_ACCESS, which correspond to user's explicit gesture, succeed. + // This test does not deal with Incognito, and should not run in Incognito + // context. Therefore IMPLICIT_ACCESS is used to let the test fail if in + // Incognito context. + return IOSChromePasswordStoreFactory::GetForBrowserState( + chrome_test_util::GetOriginalBrowserState(), + ServiceAccessType::IMPLICIT_ACCESS); +} + +// This class is used to obtain results from the PasswordStore and hence both +// check the success of store updates and ensure that store has finished +// processing. +class TestStoreConsumer : public password_manager::PasswordStoreConsumer { + public: + void OnGetPasswordStoreResults( + std::vector<std::unique_ptr<autofill::PasswordForm>> obtained) override { + obtained_ = std::move(obtained); + } + + const std::vector<autofill::PasswordForm>& GetStoreResults() { + results_.clear(); + ResetObtained(); + GetPasswordStore()->GetAutofillableLogins(this); + bool responded = base::test::ios::WaitUntilConditionOrTimeout(1.0, ^bool { + return !AreObtainedReset(); + }); + GREYAssert(responded, @"Obtaining fillable items took too long."); + AppendObtainedToResults(); + GetPasswordStore()->GetBlacklistLogins(this); + responded = base::test::ios::WaitUntilConditionOrTimeout(1.0, ^bool { + return !AreObtainedReset(); + }); + GREYAssert(responded, @"Obtaining blacklisted items took too long."); + AppendObtainedToResults(); + return results_; + } + + private: + // Puts |obtained_| in a known state not corresponding to any PasswordStore + // state. + void ResetObtained() { + obtained_.clear(); + obtained_.emplace_back(nullptr); + } + + // Returns true if |obtained_| are in the reset state. + bool AreObtainedReset() { return obtained_.size() == 1 && !obtained_[0]; } + + void AppendObtainedToResults() { + for (const auto& source : obtained_) { + results_.emplace_back(*source); + } + ResetObtained(); + } + + // Temporary cache of obtained store results. + std::vector<std::unique_ptr<autofill::PasswordForm>> obtained_; + + // Combination of fillable and blacklisted credentials from the store. + std::vector<autofill::PasswordForm> results_; +}; + +// Saves |form| to the password store and waits until the async processing is +// done. +void SaveToPasswordStore(const autofill::PasswordForm& form) { + GetPasswordStore()->AddLogin(form); + // Check the result and ensure PasswordStore processed this. + TestStoreConsumer consumer; + for (const auto& result : consumer.GetStoreResults()) { + if (result == form) + return; + } + GREYFail(@"Stored form was not found in the PasswordStore results."); +} + +// Saves an example form in the store. +void SaveExamplePasswordForm() { + autofill::PasswordForm example; + example.username_value = base::ASCIIToUTF16(kExampleUsername); + example.password_value = base::ASCIIToUTF16(kExamplePassword); + example.origin = GURL("https://example.com"); + example.signon_realm = example.origin.spec(); + SaveToPasswordStore(example); +} + +// Removes all credentials stored. +void ClearPasswordStore() { + GetPasswordStore()->RemoveLoginsCreatedBetween(base::Time(), base::Time(), + base::Closure()); + TestStoreConsumer consumer; + GREYAssert(consumer.GetStoreResults().empty(), + @"PasswordStore was not cleared."); +} + +} // namespace + +// Integration Tests for Mannual Fallback Passwords View Controller. +@interface PasswordViewControllerTestCase : ChromeTestCase +@end + +@implementation PasswordViewControllerTestCase + +- (void)setUp { + [super setUp]; + GREYAssert(autofill::features::IsPasswordManualFallbackEnabled(), + @"Manual Fallback must be enabled for this Test Case"); + GREYAssertTrue(self.testServer->Start(), @"Test server failed to start."); + const GURL URL = self.testServer->GetURL(kFormHTMLFile); + [ChromeEarlGrey loadURL:URL]; + [ChromeEarlGrey waitForWebViewContainingText:"hello!"]; +} + +- (void)tearDown { + ClearPasswordStore(); + [super tearDown]; +} + +// Test that the passwords view controller appears on screen. +- (void)testPasswordsViewControllerIsPresented { + // TODO:(https://crbug.com/878388) Enable on iPad when supported. + if (IsIPadIdiom()) + return; + + // Bring up the keyboard. + [[EarlGrey selectElementWithMatcher:chrome_test_util::WebViewMatcher()] + performAction:chrome_test_util::TapWebElement(kFormElementUsername)]; + + // Tap on the passwords icon. + [[EarlGrey selectElementWithMatcher:PasswordIconMatcher()] + performAction:grey_tap()]; + + // Verify the password controller table view is visible. + [[EarlGrey selectElementWithMatcher:PasswordTableViewMatcher()] + assertWithMatcher:grey_sufficientlyVisible()]; +} + +// Test that the passwords view controller contains the "Manage Passwords..." +// action. +- (void)testPasswordsViewControllerContainsManagePasswordsAction { + // TODO:(https://crbug.com/878388) Enable on iPad when supported. + if (IsIPadIdiom()) + return; + + // Bring up the keyboard. + [[EarlGrey selectElementWithMatcher:chrome_test_util::WebViewMatcher()] + performAction:chrome_test_util::TapWebElement(kFormElementUsername)]; + + // Tap on the passwords icon. + [[EarlGrey selectElementWithMatcher:PasswordIconMatcher()] + performAction:grey_tap()]; + + // Verify the password controller contains the "Manage Passwords..." action. + [[EarlGrey selectElementWithMatcher:ManagePasswordsMatcher()] + assertWithMatcher:grey_interactable()]; +} + +// Test that the "Manage Passwords..." action works. +- (void)testManagePasswordsActionOpensPasswordSettings { + // TODO:(https://crbug.com/878388) Enable on iPad when supported. + if (IsIPadIdiom()) + return; + + // Bring up the keyboard. + [[EarlGrey selectElementWithMatcher:chrome_test_util::WebViewMatcher()] + performAction:chrome_test_util::TapWebElement(kFormElementUsername)]; + + // Tap on the passwords icon. + [[EarlGrey selectElementWithMatcher:PasswordIconMatcher()] + performAction:grey_tap()]; + + // Tap the "Manage Passwords..." action. + [[EarlGrey selectElementWithMatcher:ManagePasswordsMatcher()] + performAction:grey_tap()]; + + // Verify the password settings opened. + [[EarlGrey selectElementWithMatcher:PasswordSettingsMatcher()] + assertWithMatcher:grey_sufficientlyVisible()]; +} + +// Test that the Password View Controller is not present when presenting UI. +- (void)testPasswordControllerPauses { + // TODO:(https://crbug.com/878388) Enable on iPad when supported. + if (IsIPadIdiom()) + return; + + // For the search bar to appear in password settings at least one password is + // needed. + SaveExamplePasswordForm(); + + // Bring up the keyboard. + [[EarlGrey selectElementWithMatcher:chrome_test_util::WebViewMatcher()] + performAction:chrome_test_util::TapWebElement(kFormElementUsername)]; + + // Tap on the passwords icon. + [[EarlGrey selectElementWithMatcher:PasswordIconMatcher()] + performAction:grey_tap()]; + + // Tap the "Manage Passwords..." action. + [[EarlGrey selectElementWithMatcher:ManagePasswordsMatcher()] + performAction:grey_tap()]; + + // Tap the password search. + + [[EarlGrey selectElementWithMatcher:PasswordSettingsSearchMatcher()] + performAction:grey_tap()]; + + // Verify keyboard is shown without the password controller. + GREYAssertTrue([GREYKeyboard isKeyboardShown], @"Keyboard Should be Shown"); + [[EarlGrey selectElementWithMatcher:PasswordTableViewMatcher()] + assertWithMatcher:grey_notVisible()]; +} + +// Test that the Password View Controller is resumed after selecting other +// password. +- (void)testPasswordControllerResumes { + // TODO:(https://crbug.com/878388) Enable on iPad when supported. + if (IsIPadIdiom()) + return; + + // For this test one password is needed. + SaveExamplePasswordForm(); + + // Bring up the keyboard. + [[EarlGrey selectElementWithMatcher:chrome_test_util::WebViewMatcher()] + performAction:chrome_test_util::TapWebElement(kFormElementUsername)]; + + // Tap on the passwords icon. + [[EarlGrey selectElementWithMatcher:PasswordIconMatcher()] + performAction:grey_tap()]; + + // Tap the "Manage Passwords..." action. + [[EarlGrey selectElementWithMatcher:OtherPasswordsMatcher()] + performAction:grey_tap()]; + + // Tap the password search. + [[EarlGrey selectElementWithMatcher:PasswordSearchBarMatcher()] + performAction:grey_tap()]; + GREYAssertTrue([GREYKeyboard isKeyboardShown], @"Keyboard Should be Shown"); + + // Select a username. + [[EarlGrey selectElementWithMatcher:UsernameButtonMatcher()] + performAction:grey_tap()]; + + // Only on iOS 12 it is certain that on iPhones the keyboard is back. On iOS + // 11, it varies by device and version. + if (base::ios::IsRunningOnIOS12OrLater()) { + // Verify the password controller table view and the keyboard are visible. + GREYAssertTrue([GREYKeyboard isKeyboardShown], @"Keyboard Should be Shown"); + [[EarlGrey selectElementWithMatcher:PasswordTableViewMatcher()] + assertWithMatcher:grey_sufficientlyVisible()]; + } else if (!base::ios::IsRunningOnIOS11OrLater()) { + // On iOS 10 the keyboard is hidden. + GREYAssertFalse([GREYKeyboard isKeyboardShown], + @"Keyboard Should be Hidden"); + } +} + +@end
diff --git a/ios/chrome/browser/ui/browser_view_controller.mm b/ios/chrome/browser/ui/browser_view_controller.mm index b144c2be..69fd27e 100644 --- a/ios/chrome/browser/ui/browser_view_controller.mm +++ b/ios/chrome/browser/ui/browser_view_controller.mm
@@ -120,6 +120,7 @@ #import "ios/chrome/browser/ui/authentication/consent_bump/consent_bump_coordinator_delegate.h" #import "ios/chrome/browser/ui/authentication/re_signin_infobar_delegate.h" #import "ios/chrome/browser/ui/autofill/form_input_accessory_coordinator.h" +#import "ios/chrome/browser/ui/autofill/manual_fill/password_coordinator.h" #import "ios/chrome/browser/ui/background_generator.h" #import "ios/chrome/browser/ui/bookmarks/bookmark_interaction_controller.h" #include "ios/chrome/browser/ui/bookmarks/bookmark_model_bridge_observer.h" @@ -404,6 +405,7 @@ CRWNativeContentProvider, CRWWebStateDelegate, DialogPresenterDelegate, + FormInputAccessoryCoordinatorDelegate, FullscreenUIElement, InfobarContainerStateDelegate, KeyCommandsPlumbing, @@ -983,6 +985,7 @@ initWithBaseViewController:self browserState:browserState webStateList:model.webStateList]; + _formInputAccessoryCoordinator.delegate = self; [_formInputAccessoryCoordinator start]; _javaScriptDialogPresenter.reset( @@ -3255,6 +3258,12 @@ [self.dispatcher showSavedPasswordsSettingsFromViewController:self]; } +#pragma mark - FormInputAccessoryCoordinatorDelegate + +- (void)openPasswordSettings { + [self.dispatcher showSavedPasswordsSettingsFromViewController:self]; +} + #pragma mark - CRWWebStateDelegate methods. - (web::WebState*)webState:(web::WebState*)webState
diff --git a/ios/chrome/browser/ui/omnibox/omnibox_text_field_ios.mm b/ios/chrome/browser/ui/omnibox/omnibox_text_field_ios.mm index 6a82776..10ecb3dd 100644 --- a/ios/chrome/browser/ui/omnibox/omnibox_text_field_ios.mm +++ b/ios/chrome/browser/ui/omnibox/omnibox_text_field_ios.mm
@@ -365,7 +365,7 @@ // default to a reasonable prefix string to give a plausible offset. NSString* prefixString = @"https://"; - if ([self.text containsString:string]) { + if (string.length > 0 && [self.text containsString:string]) { NSRange range = [self.text rangeOfString:string]; NSRange prefixRange = NSMakeRange(0, range.location); prefixString = [self.text substringWithRange:prefixRange];
diff --git a/ios/chrome/browser/ui/settings/BUILD.gn b/ios/chrome/browser/ui/settings/BUILD.gn index b712648..a8f94b1 100644 --- a/ios/chrome/browser/ui/settings/BUILD.gn +++ b/ios/chrome/browser/ui/settings/BUILD.gn
@@ -208,6 +208,7 @@ "//ios/third_party/material_components_ios", "//ios/third_party/material_roboto_font_loader_ios", "//net", + "//services/identity/public/cpp", "//ui/base", "//url", ]
diff --git a/ios/chrome/browser/ui/settings/settings_collection_view_controller.mm b/ios/chrome/browser/ui/settings/settings_collection_view_controller.mm index 9578d54..0160360b 100644 --- a/ios/chrome/browser/ui/settings/settings_collection_view_controller.mm +++ b/ios/chrome/browser/ui/settings/settings_collection_view_controller.mm
@@ -17,7 +17,6 @@ #import "components/prefs/ios/pref_observer_bridge.h" #include "components/prefs/pref_service.h" #include "components/search_engines/util.h" -#include "components/signin/core/browser/signin_manager.h" #include "components/signin/core/browser/signin_metrics.h" #include "components/strings/grit/components_strings.h" #include "components/unified_consent/feature.h" @@ -31,7 +30,7 @@ #import "ios/chrome/browser/signin/authentication_service.h" #include "ios/chrome/browser/signin/authentication_service_factory.h" #import "ios/chrome/browser/signin/chrome_identity_service_observer_bridge.h" -#include "ios/chrome/browser/signin/signin_manager_factory.h" +#include "ios/chrome/browser/signin/identity_manager_factory.h" #include "ios/chrome/browser/sync/profile_sync_service_factory.h" #import "ios/chrome/browser/sync/sync_observer_bridge.h" #include "ios/chrome/browser/sync/sync_setup_service_factory.h" @@ -72,6 +71,7 @@ #import "ios/public/provider/chrome/browser/signin/chrome_identity.h" #import "ios/public/provider/chrome/browser/signin/signin_resources_provider.h" #include "ios/public/provider/chrome/browser/voice/voice_search_prefs.h" +#include "services/identity/public/cpp/identity_manager.h" #include "ui/base/l10n/l10n_util_mac.h" #if !defined(__has_feature) || !__has_feature(objc_arc) @@ -147,44 +147,43 @@ NSString* kLogJavascriptKey = @"LogJavascript"; #endif // CHROMIUM_BUILD && !defined(NDEBUG) -#pragma mark - SigninObserverBridge Class +#pragma mark - IdentityObserverBridge Class -class SigninObserverBridge : public SigninManagerBase::Observer { +class IdentityObserverBridge : public identity::IdentityManager::Observer { public: - SigninObserverBridge(ios::ChromeBrowserState* browserState, - SettingsCollectionViewController* owner); - ~SigninObserverBridge() override {} + IdentityObserverBridge(ios::ChromeBrowserState* browserState, + SettingsCollectionViewController* owner); + ~IdentityObserverBridge() override {} - // SigninManagerBase::Observer implementation: - void GoogleSigninSucceeded(const std::string& account_id, - const std::string& username) override; - void GoogleSignedOut(const std::string& account_id, - const std::string& username) override; + // IdentityManager::Observer implementation: + void OnPrimaryAccountSet(const AccountInfo& primary_account_info) override; + void OnPrimaryAccountCleared( + const AccountInfo& previous_primary_account_info) override; private: __weak SettingsCollectionViewController* owner_; - ScopedObserver<SigninManager, SigninObserverBridge> observer_; + ScopedObserver<identity::IdentityManager, IdentityObserverBridge> observer_; }; -SigninObserverBridge::SigninObserverBridge( +IdentityObserverBridge::IdentityObserverBridge( ios::ChromeBrowserState* browserState, SettingsCollectionViewController* owner) : owner_(owner), observer_(this) { DCHECK(owner_); - SigninManager* signin_manager = - ios::SigninManagerFactory::GetForBrowserState(browserState); - if (!signin_manager) + identity::IdentityManager* identity_manager = + IdentityManagerFactory::GetForBrowserState(browserState); + if (!identity_manager) return; - observer_.Add(signin_manager); + observer_.Add(identity_manager); } -void SigninObserverBridge::GoogleSigninSucceeded(const std::string& account_id, - const std::string& username) { +void IdentityObserverBridge::OnPrimaryAccountSet( + const AccountInfo& primary_account_info) { [owner_ onSignInStateChanged]; } -void SigninObserverBridge::GoogleSignedOut(const std::string& account_id, - const std::string& username) { +void IdentityObserverBridge::OnPrimaryAccountCleared( + const AccountInfo& previous_primary_account_info) { [owner_ onSignInStateChanged]; } @@ -205,7 +204,7 @@ // The current browser state that hold the settings. Never off the record. ios::ChromeBrowserState* _browserState; // weak - std::unique_ptr<SigninObserverBridge> _notificationBridge; + std::unique_ptr<IdentityObserverBridge> _notificationBridge; std::unique_ptr<SyncObserverBridge> _syncObserverBridge; // Whether the impression of the Signin button has already been recorded. BOOL _hasRecordedSigninImpression; @@ -283,7 +282,7 @@ _browserState = browserState; self.title = l10n_util::GetNSStringWithFixup(IDS_IOS_SETTINGS_TITLE); self.collectionViewAccessibilityIdentifier = kSettingsCollectionViewId; - _notificationBridge.reset(new SigninObserverBridge(_browserState, self)); + _notificationBridge.reset(new IdentityObserverBridge(_browserState, self)); syncer::SyncService* syncService = ProfileSyncServiceFactory::GetForBrowserState(_browserState); _syncObserverBridge.reset(new SyncObserverBridge(self, syncService));
diff --git a/ios/chrome/browser/ui/tab_grid/tab_grid_egtests_hook.mm b/ios/chrome/browser/ui/tab_grid/tab_grid_egtests_hook.mm index 893cddbf..02b2db70 100644 --- a/ios/chrome/browser/ui/tab_grid/tab_grid_egtests_hook.mm +++ b/ios/chrome/browser/ui/tab_grid/tab_grid_egtests_hook.mm
@@ -38,11 +38,6 @@ return true; } -// TODO(crbug.com/885003) : Remove this hook. -bool ForceWKWebViewSnapshots() { - return false; -} - void SetUpTestsIfPresent() { // No-op for Earl Grey. }
diff --git a/ios/chrome/browser/ui/ui_feature_flags.cc b/ios/chrome/browser/ui/ui_feature_flags.cc index 3f5bc5a..bb1defa 100644 --- a/ios/chrome/browser/ui/ui_feature_flags.cc +++ b/ios/chrome/browser/ui/ui_feature_flags.cc
@@ -12,4 +12,4 @@ const base::Feature kOmniboxPopupShortcutIconsInZeroState{ "OmniboxPopupShortcutIconsInZeroState", base::FEATURE_DISABLED_BY_DEFAULT}; const base::Feature kWKWebViewSnapshots{"WKWebViewSnapshots", - base::FEATURE_DISABLED_BY_DEFAULT}; + base::FEATURE_ENABLED_BY_DEFAULT};
diff --git a/ios/chrome/browser/ui/ui_util.mm b/ios/chrome/browser/ui/ui_util.mm index 1001f6f0..af0f8ca6 100644 --- a/ios/chrome/browser/ui/ui_util.mm +++ b/ios/chrome/browser/ui/ui_util.mm
@@ -68,8 +68,6 @@ // TODO(crbug.com/885003) : Remove this flag. bool IsWKWebViewSnapshotsEnabled() { - if (tests_hook::ForceWKWebViewSnapshots()) - return true; return base::FeatureList::IsEnabled(kWKWebViewSnapshots); }
diff --git a/ios/chrome/browser/variations/ios_chrome_variations_service_client.cc b/ios/chrome/browser/variations/ios_chrome_variations_service_client.cc index b4fe151..84a3c1e4 100644 --- a/ios/chrome/browser/variations/ios_chrome_variations_service_client.cc +++ b/ios/chrome/browser/variations/ios_chrome_variations_service_client.cc
@@ -27,10 +27,6 @@ IOSChromeVariationsServiceClient::~IOSChromeVariationsServiceClient() {} -std::string IOSChromeVariationsServiceClient::GetApplicationLocale() { - return GetApplicationContext()->GetApplicationLocale(); -} - base::Callback<base::Version()> IOSChromeVariationsServiceClient::GetVersionForSimulationCallback() { return base::Bind(&GetVersionForSimulation);
diff --git a/ios/chrome/browser/variations/ios_chrome_variations_service_client.h b/ios/chrome/browser/variations/ios_chrome_variations_service_client.h index 61ecb2e..a221a7f 100644 --- a/ios/chrome/browser/variations/ios_chrome_variations_service_client.h +++ b/ios/chrome/browser/variations/ios_chrome_variations_service_client.h
@@ -23,7 +23,6 @@ private: // variations::VariationsServiceClient implementation. - std::string GetApplicationLocale() override; base::Callback<base::Version()> GetVersionForSimulationCallback() override; scoped_refptr<network::SharedURLLoaderFactory> GetURLLoaderFactory() override; network_time::NetworkTimeTracker* GetNetworkTimeTracker() override;
diff --git a/ios/chrome/test/earl_grey/chrome_actions.h b/ios/chrome/test/earl_grey/chrome_actions.h index 0b2f6f6e..7bbdb7df6 100644 --- a/ios/chrome/test/earl_grey/chrome_actions.h +++ b/ios/chrome/test/earl_grey/chrome_actions.h
@@ -30,6 +30,10 @@ // Action to turn the switch of a SyncSwitchCell to the given |on| state. id<GREYAction> TurnSyncSwitchOn(BOOL on); +// Action to tap a web element with id equal to |element_id| on the current web +// state. +id<GREYAction> TapWebElement(const std::string& element_id); + } // namespace chrome_test_util #endif // IOS_CHROME_TEST_EARL_GREY_CHROME_ACTIONS_H_
diff --git a/ios/chrome/test/earl_grey/chrome_actions.mm b/ios/chrome/test/earl_grey/chrome_actions.mm index 3fcd9824..052088e8 100644 --- a/ios/chrome/test/earl_grey/chrome_actions.mm +++ b/ios/chrome/test/earl_grey/chrome_actions.mm
@@ -67,4 +67,10 @@ }]; } +id<GREYAction> TapWebElement(const std::string& element_id) { + return web::WebViewTapElement( + chrome_test_util::GetCurrentWebState(), + web::test::ElementSelector::ElementSelectorId(element_id)); +} + } // namespace chrome_test_util
diff --git a/ios/chrome/test/earl_grey/chrome_matchers.h b/ios/chrome/test/earl_grey/chrome_matchers.h index 66e87c5..f472026f 100644 --- a/ios/chrome/test/earl_grey/chrome_matchers.h +++ b/ios/chrome/test/earl_grey/chrome_matchers.h
@@ -241,6 +241,9 @@ // Returns matcher for defoucesed omnibox on a new tab. id<GREYMatcher> NewTabPageOmnibox(); +// Returns a matcher for the current WebView. +id<GREYMatcher> WebViewMatcher(); + } // namespace chrome_test_util #endif // IOS_CHROME_TEST_EARL_GREY_CHROME_MATCHERS_H_
diff --git a/ios/chrome/test/earl_grey/chrome_matchers.mm b/ios/chrome/test/earl_grey/chrome_matchers.mm index e3d075e..f9db3d9f 100644 --- a/ios/chrome/test/earl_grey/chrome_matchers.mm +++ b/ios/chrome/test/earl_grey/chrome_matchers.mm
@@ -469,4 +469,8 @@ grey_minimumVisiblePercent(0.2), nil); } +id<GREYMatcher> WebViewMatcher() { + return web::WebViewInWebState(chrome_test_util::GetCurrentWebState()); +} + } // namespace chrome_test_util
diff --git a/ios/chrome/test/earl_grey/eg_tests_hook.mm b/ios/chrome/test/earl_grey/eg_tests_hook.mm index 363197b..9479f067 100644 --- a/ios/chrome/test/earl_grey/eg_tests_hook.mm +++ b/ios/chrome/test/earl_grey/eg_tests_hook.mm
@@ -38,11 +38,6 @@ return true; } -// TODO(crbug.com/885003) : Remove this hook. -bool ForceWKWebViewSnapshots() { - return false; -} - void SetUpTestsIfPresent() { // No-op for Earl Grey. }
diff --git a/ios/testing/BUILD.gn b/ios/testing/BUILD.gn index 1c40926..2c5ebd5a 100644 --- a/ios/testing/BUILD.gn +++ b/ios/testing/BUILD.gn
@@ -91,6 +91,7 @@ "data/http_server_files/testpage.pdf", "data/http_server_files/two_pages.pdf", "data/http_server_files/user_agent_test_page.html", + "data/http_server_files/username_password_field_form.html", "data/http_server_files/window_close.html", "data/http_server_files/window_location.html", "data/http_server_files/window_location.js",
diff --git a/ios/testing/data/http_server_files/username_password_field_form.html b/ios/testing/data/http_server_files/username_password_field_form.html new file mode 100644 index 0000000..1e70bd6 --- /dev/null +++ b/ios/testing/data/http_server_files/username_password_field_form.html
@@ -0,0 +1,14 @@ +<!DOCTYPE html> +<!-- 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. --> +<html> +<body> +hello! +<form method=POST action="submit"> + <input type="text" name="username" id="username"><br> + <input type="password" name="password" id="password"><br> + <input type="submit" value="submit" id="submit"> +</form> +</body> +</html>
diff --git a/ios/third_party/earl_grey/BUILD.gn b/ios/third_party/earl_grey/BUILD.gn index add07e9..0ee316e8 100644 --- a/ios/third_party/earl_grey/BUILD.gn +++ b/ios/third_party/earl_grey/BUILD.gn
@@ -243,46 +243,47 @@ "src/EarlGrey/Traversal/GREYTraversalDFS.m", ] public_headers = [ - "src/EarlGrey/EarlGrey.h", - "src/EarlGrey/Core/EarlGreyImpl.h", "src/EarlGrey/Action/GREYAction.h", "src/EarlGrey/Action/GREYActionBlock.h", "src/EarlGrey/Action/GREYActions.h", - "src/EarlGrey/Matcher/GREYAllOf.h", - "src/EarlGrey/Matcher/GREYAnyOf.h", + "src/EarlGrey/Action/GREYBaseAction.h", + "src/EarlGrey/Action/GREYScrollActionError.h", + "src/EarlGrey/AppSupport/GREYIdlingResource.h", "src/EarlGrey/Assertion/GREYAssertion.h", "src/EarlGrey/Assertion/GREYAssertionBlock.h", "src/EarlGrey/Assertion/GREYAssertionDefines.h", "src/EarlGrey/Assertion/GREYAssertions.h", - "src/EarlGrey/Action/GREYBaseAction.h", - "src/EarlGrey/Matcher/GREYBaseMatcher.h", - "src/EarlGrey/Synchronization/GREYCondition.h", "src/EarlGrey/Common/GREYConfiguration.h", "src/EarlGrey/Common/GREYConstants.h", - "src/EarlGrey/Provider/GREYDataEnumerator.h", "src/EarlGrey/Common/GREYDefines.h", - "src/EarlGrey/Matcher/GREYDescription.h", - "src/EarlGrey/Synchronization/GREYDispatchQueueIdlingResource.h", - "src/EarlGrey/Core/GREYElementFinder.h", "src/EarlGrey/Common/GREYElementHierarchy.h", + "src/EarlGrey/Common/GREYScreenshotUtil.h", + "src/EarlGrey/Common/GREYTestHelper.h", + "src/EarlGrey/Core/EarlGreyImpl.h", + "src/EarlGrey/Core/GREYElementFinder.h", "src/EarlGrey/Core/GREYElementInteraction.h", - "src/EarlGrey/Matcher/GREYElementMatcherBlock.h", + "src/EarlGrey/Core/GREYInteraction.h", + "src/EarlGrey/Core/GREYKeyboard.h", + "src/EarlGrey/EarlGrey.h", "src/EarlGrey/Exception/GREYFailureHandler.h", "src/EarlGrey/Exception/GREYFrameworkException.h", - "src/EarlGrey/AppSupport/GREYIdlingResource.h", - "src/EarlGrey/Core/GREYInteraction.h", + "src/EarlGrey/Matcher/GREYAllOf.h", + "src/EarlGrey/Matcher/GREYAnyOf.h", + "src/EarlGrey/Matcher/GREYBaseMatcher.h", + "src/EarlGrey/Matcher/GREYDescription.h", + "src/EarlGrey/Matcher/GREYElementMatcherBlock.h", "src/EarlGrey/Matcher/GREYLayoutConstraint.h", - "src/EarlGrey/Synchronization/GREYManagedObjectContextIdlingResource.h", "src/EarlGrey/Matcher/GREYMatcher.h", "src/EarlGrey/Matcher/GREYMatchers.h", - "src/EarlGrey/Synchronization/GREYNSTimerIdlingResource.h", "src/EarlGrey/Matcher/GREYNot.h", - "src/EarlGrey/Synchronization/GREYOperationQueueIdlingResource.h", + "src/EarlGrey/Provider/GREYDataEnumerator.h", "src/EarlGrey/Provider/GREYProvider.h", - "src/EarlGrey/Common/GREYScreenshotUtil.h", - "src/EarlGrey/Action/GREYScrollActionError.h", + "src/EarlGrey/Synchronization/GREYCondition.h", + "src/EarlGrey/Synchronization/GREYDispatchQueueIdlingResource.h", + "src/EarlGrey/Synchronization/GREYManagedObjectContextIdlingResource.h", + "src/EarlGrey/Synchronization/GREYNSTimerIdlingResource.h", + "src/EarlGrey/Synchronization/GREYOperationQueueIdlingResource.h", "src/EarlGrey/Synchronization/GREYSyncAPI.h", - "src/EarlGrey/Common/GREYTestHelper.h", "src/EarlGrey/Synchronization/GREYUIThreadExecutor.h", ] deps = [
diff --git a/pdf/pdfium/fuzzers/pdfium_fuzzer_helper.cc b/pdf/pdfium/fuzzers/pdfium_fuzzer_helper.cc index ac704de..a52d4cf 100644 --- a/pdf/pdfium/fuzzers/pdfium_fuzzer_helper.cc +++ b/pdf/pdfium/fuzzers/pdfium_fuzzer_helper.cc
@@ -86,7 +86,6 @@ std::string result; #ifdef _WIN32 - wchar_t wpath[MAX_PATH]; char path[MAX_PATH]; DWORD len = GetModuleFileNameA(NULL, path, MAX_PATH); if (len != 0)
diff --git a/services/device/bluetooth/BUILD.gn b/services/device/bluetooth/BUILD.gn index e598c5f..373e7b6 100644 --- a/services/device/bluetooth/BUILD.gn +++ b/services/device/bluetooth/BUILD.gn
@@ -23,8 +23,6 @@ deps = [ "//base", - "//dbus", - "//device/bluetooth", ] } @@ -37,8 +35,6 @@ deps = [ ":bluetooth_system", - "//dbus", - "//device/bluetooth", "//net", "//services/device:test_support", "//testing/gtest",
diff --git a/services/device/bluetooth/DEPS b/services/device/bluetooth/DEPS deleted file mode 100644 index 18af175..0000000 --- a/services/device/bluetooth/DEPS +++ /dev/null
@@ -1,9 +0,0 @@ -include_rules = [ - "+dbus", -] - -specific_include_rules = { - "bluetooth_system_unittest.cc": [ - "+third_party/cros_system_api/dbus/service_constants.h" - ], -}
diff --git a/services/device/bluetooth/bluetooth_system.cc b/services/device/bluetooth/bluetooth_system.cc index ff71fca..86ea59b 100644 --- a/services/device/bluetooth/bluetooth_system.cc +++ b/services/device/bluetooth/bluetooth_system.cc
@@ -6,11 +6,7 @@ #include <memory> #include <utility> -#include <vector> -#include "dbus/object_path.h" -#include "device/bluetooth/dbus/bluetooth_adapter_client.h" -#include "device/bluetooth/dbus/bluez_dbus_manager.h" #include "mojo/public/cpp/bindings/strong_binding.h" namespace device { @@ -27,24 +23,4 @@ BluetoothSystem::~BluetoothSystem() = default; -void BluetoothSystem::GetState(GetStateCallback callback) { - std::vector<dbus::ObjectPath> object_paths = - GetBluetoothAdapterClient()->GetAdapters(); - if (object_paths.empty()) { - std::move(callback).Run(State::kUnavailable); - return; - } - - auto* properties = - GetBluetoothAdapterClient()->GetProperties(object_paths[0]); - std::move(callback).Run(properties->powered.value() ? State::kPoweredOn - : State::kPoweredOff); -} - -bluez::BluetoothAdapterClient* BluetoothSystem::GetBluetoothAdapterClient() { - // Use AlternateBluetoothAdapterClient to avoid interfering with users of the - // regular BluetoothAdapterClient. - return bluez::BluezDBusManager::Get()->GetAlternateBluetoothAdapterClient(); -} - } // namespace device
diff --git a/services/device/bluetooth/bluetooth_system.h b/services/device/bluetooth/bluetooth_system.h index 64703d5..99412f39 100644 --- a/services/device/bluetooth/bluetooth_system.h +++ b/services/device/bluetooth/bluetooth_system.h
@@ -8,10 +8,6 @@ #include "base/macros.h" #include "services/device/public/mojom/bluetooth_system.mojom.h" -namespace bluez { -class BluetoothAdapterClient; -} - namespace device { class BluetoothSystem : public mojom::BluetoothSystem { @@ -22,12 +18,7 @@ explicit BluetoothSystem(mojom::BluetoothSystemClientPtr client); ~BluetoothSystem() override; - // mojom::BluetoothSystem - void GetState(GetStateCallback callback) override; - private: - bluez::BluetoothAdapterClient* GetBluetoothAdapterClient(); - mojom::BluetoothSystemClientPtr client_ptr_; DISALLOW_COPY_AND_ASSIGN(BluetoothSystem);
diff --git a/services/device/bluetooth/bluetooth_system_unittest.cc b/services/device/bluetooth/bluetooth_system_unittest.cc index 87f83cff..220499f6 100644 --- a/services/device/bluetooth/bluetooth_system_unittest.cc +++ b/services/device/bluetooth/bluetooth_system_unittest.cc
@@ -6,182 +6,14 @@ #include <utility> -#include "base/observer_list.h" #include "base/run_loop.h" -#include "base/strings/stringprintf.h" -#include "device/bluetooth/dbus/bluetooth_adapter_client.h" -#include "device/bluetooth/dbus/bluez_dbus_manager.h" #include "mojo/public/cpp/bindings/binding.h" #include "services/device/device_service_test_base.h" #include "services/device/public/mojom/bluetooth_system.mojom.h" #include "services/device/public/mojom/constants.mojom.h" -#include "third_party/cros_system_api/dbus/service_constants.h" namespace device { -constexpr const char kFooObjectPathStr[] = "fake/hci0"; - -namespace { - -// Exposes high-level methods to simulate Bluetooth events e.g. a new adapter -// was added, adapter power state changed, etc. -// -// As opposed to FakeBluetoothAdapterClient, the other fake implementation of -// BluetoothAdapterClient, this class does not have any built-in behavior -// e.g. it won't start triggering device discovery events when StartDiscovery is -// called. It's up to its users to call the relevant Simulate*() method to -// trigger each event. -class DEVICE_BLUETOOTH_EXPORT TestBluetoothAdapterClient - : public bluez::BluetoothAdapterClient { - public: - struct Properties : public bluez::BluetoothAdapterClient::Properties { - explicit Properties(const PropertyChangedCallback& callback) - : BluetoothAdapterClient::Properties( - nullptr, /* object_proxy */ - bluetooth_adapter::kBluetoothAdapterInterface, - callback) {} - ~Properties() override = default; - - // dbus::PropertySet override - void Get(dbus::PropertyBase* property, - dbus::PropertySet::GetCallback callback) override { - DVLOG(1) << "Get " << property->name(); - NOTIMPLEMENTED(); - } - - void GetAll() override { - DVLOG(1) << "GetAll"; - NOTIMPLEMENTED(); - } - - void Set(dbus::PropertyBase* property, - dbus::PropertySet::SetCallback callback) override { - DVLOG(1) << "Set " << property->name(); - NOTIMPLEMENTED(); - } - }; - - TestBluetoothAdapterClient() = default; - ~TestBluetoothAdapterClient() override = default; - - // Simulates a new adapter with |object_path_str|. Its properties are empty, - // 0, or false. - void SimulateAdapterAdded(const std::string& object_path_str) { - dbus::ObjectPath object_path(object_path_str); - - ObjectPathToProperties::iterator it; - bool was_inserted; - std::tie(it, was_inserted) = adapter_object_paths_to_properties_.emplace( - object_path, - base::BindRepeating(&TestBluetoothAdapterClient::OnPropertyChanged, - base::Unretained(this), object_path)); - DCHECK(was_inserted); - } - - // Simulates adapter at |object_path_str| changing its powered state to - // |powered|. - void SimulateAdapterPowerStateChanged(const std::string& object_path_str, - bool powered) { - GetProperties(dbus::ObjectPath(object_path_str)) - ->powered.ReplaceValue(powered); - } - - // BluetoothAdapterClient: - void Init(dbus::Bus* bus, - const std::string& bluetooth_service_name) override {} - - void AddObserver(Observer* observer) override { - observers_.AddObserver(observer); - } - - void RemoveObserver(Observer* observer) override { - observers_.RemoveObserver(observer); - } - - std::vector<dbus::ObjectPath> GetAdapters() override { - std::vector<dbus::ObjectPath> object_paths; - for (const auto& object_path_to_property : - adapter_object_paths_to_properties_) { - object_paths.push_back(object_path_to_property.first); - } - return object_paths; - } - - Properties* GetProperties(const dbus::ObjectPath& object_path) override { - auto it = adapter_object_paths_to_properties_.find(object_path); - if (it == adapter_object_paths_to_properties_.end()) - return nullptr; - return &(it->second); - } - - void StartDiscovery(const dbus::ObjectPath& object_path, - const base::Closure& callback, - ErrorCallback error_callback) override { - NOTIMPLEMENTED(); - } - - void StopDiscovery(const dbus::ObjectPath& object_path, - const base::Closure& callback, - ErrorCallback error_callback) override { - NOTIMPLEMENTED(); - } - - void PauseDiscovery(const dbus::ObjectPath& object_path, - const base::Closure& callback, - ErrorCallback error_callback) override { - NOTIMPLEMENTED(); - } - - void UnpauseDiscovery(const dbus::ObjectPath& object_path, - const base::Closure& callback, - ErrorCallback error_callback) override { - NOTIMPLEMENTED(); - } - - void RemoveDevice(const dbus::ObjectPath& object_path, - const dbus::ObjectPath& device_path, - const base::Closure& callback, - ErrorCallback error_callback) override { - NOTIMPLEMENTED(); - } - - void SetDiscoveryFilter(const dbus::ObjectPath& object_path, - const DiscoveryFilter& discovery_filter, - const base::Closure& callback, - ErrorCallback error_callback) override { - NOTIMPLEMENTED(); - } - - void CreateServiceRecord(const dbus::ObjectPath& object_path, - const bluez::BluetoothServiceRecordBlueZ& record, - const ServiceRecordCallback& callback, - ErrorCallback error_callback) override { - NOTIMPLEMENTED(); - } - - void RemoveServiceRecord(const dbus::ObjectPath& object_path, - uint32_t handle, - const base::Closure& callback, - ErrorCallback error_callback) override { - NOTIMPLEMENTED(); - } - - private: - void OnPropertyChanged(const dbus::ObjectPath& object_path, - const std::string& property_name) { - for (auto& observer : observers_) { - observer.AdapterPropertyChanged(object_path, property_name); - } - } - - using ObjectPathToProperties = std::map<dbus::ObjectPath, Properties>; - ObjectPathToProperties adapter_object_paths_to_properties_; - - base::ObserverList<Observer>::Unchecked observers_; -}; - -} // namespace - class BluetoothSystemTest : public DeviceServiceTestBase, public mojom::BluetoothSystemClient { public: @@ -191,43 +23,11 @@ void SetUp() override { DeviceServiceTestBase::SetUp(); connector()->BindInterface(mojom::kServiceName, &system_factory_); - - auto test_bluetooth_adapter_client = - std::make_unique<TestBluetoothAdapterClient>(); - test_bluetooth_adapter_client_ = test_bluetooth_adapter_client.get(); - - std::unique_ptr<bluez::BluezDBusManagerSetter> dbus_setter = - bluez::BluezDBusManager::GetSetterForTesting(); - dbus_setter->SetAlternateBluetoothAdapterClient( - std::move(test_bluetooth_adapter_client)); - } - - void StateCallback(base::OnceClosure quit_closure, - mojom::BluetoothSystem::State state) { - last_state_ = state; - std::move(quit_closure).Run(); } protected: - mojom::BluetoothSystemPtr CreateBluetoothSystem() { - mojom::BluetoothSystemClientPtr client_ptr; - system_client_binding_.Bind(mojo::MakeRequest(&client_ptr)); - - mojom::BluetoothSystemPtr system_ptr; - system_factory_->Create(mojo::MakeRequest(&system_ptr), - std::move(client_ptr)); - return system_ptr; - } - - // Saves the last state passed to StateCallback. - base::Optional<mojom::BluetoothSystem::State> last_state_; - mojom::BluetoothSystemFactoryPtr system_factory_; - TestBluetoothAdapterClient* test_bluetooth_adapter_client_; - - mojo::Binding<mojom::BluetoothSystemClient> system_client_binding_{this}; - private: DISALLOW_COPY_AND_ASSIGN(BluetoothSystemTest); }; @@ -250,47 +50,4 @@ EXPECT_TRUE(system_ptr.is_bound()); } -TEST_F(BluetoothSystemTest, GetState_NoAdapter) { - auto system = CreateBluetoothSystem(); - - base::RunLoop run_loop; - system->GetState(base::BindOnce(&BluetoothSystemTest::StateCallback, - base::Unretained(this), - run_loop.QuitClosure())); - run_loop.Run(); - - EXPECT_EQ(mojom::BluetoothSystem::State::kUnavailable, last_state_.value()); -} - -TEST_F(BluetoothSystemTest, GetState_PoweredOffAdapter) { - test_bluetooth_adapter_client_->SimulateAdapterAdded(kFooObjectPathStr); - // Added adapters are Off by default. - - auto system = CreateBluetoothSystem(); - - base::RunLoop run_loop; - system->GetState(base::BindOnce(&BluetoothSystemTest::StateCallback, - base::Unretained(this), - run_loop.QuitClosure())); - run_loop.Run(); - - EXPECT_EQ(mojom::BluetoothSystem::State::kPoweredOff, last_state_.value()); -} - -TEST_F(BluetoothSystemTest, GetState_PoweredOnAdapter) { - test_bluetooth_adapter_client_->SimulateAdapterAdded(kFooObjectPathStr); - test_bluetooth_adapter_client_->SimulateAdapterPowerStateChanged( - kFooObjectPathStr, true); - - auto system = CreateBluetoothSystem(); - - base::RunLoop run_loop; - system->GetState(base::BindOnce(&BluetoothSystemTest::StateCallback, - base::Unretained(this), - run_loop.QuitClosure())); - run_loop.Run(); - - EXPECT_EQ(mojom::BluetoothSystem::State::kPoweredOn, last_state_.value()); -} - } // namespace device
diff --git a/services/device/generic_sensor/OWNERS b/services/device/generic_sensor/OWNERS index db5ecbc..b083d33 100644 --- a/services/device/generic_sensor/OWNERS +++ b/services/device/generic_sensor/OWNERS
@@ -1,4 +1,3 @@ -alexander.shalamov@intel.com juncai@chromium.org timvolodine@chromium.org
diff --git a/services/device/public/mojom/bluetooth_system.mojom b/services/device/public/mojom/bluetooth_system.mojom index 1523efd..fb890036 100644 --- a/services/device/public/mojom/bluetooth_system.mojom +++ b/services/device/public/mojom/bluetooth_system.mojom
@@ -34,7 +34,6 @@ kPoweredOn, }; - GetState() => (State state); }; // Interface used by clients of BluetoothSystem to get notified of events
diff --git a/services/identity/public/cpp/DEPS b/services/identity/public/cpp/DEPS index 6efe08b..a972c56 100644 --- a/services/identity/public/cpp/DEPS +++ b/services/identity/public/cpp/DEPS
@@ -8,5 +8,6 @@ "+components/signin/core/browser/signin_switches.h", "+google_apis/gaia/gaia_auth_util.h", "+google_apis/gaia/google_service_auth_error.h", + "+google_apis/gaia/oauth2_access_token_consumer.h", "+google_apis/gaia/oauth2_token_service.h", ]
diff --git a/services/identity/public/cpp/access_token_fetcher_unittest.cc b/services/identity/public/cpp/access_token_fetcher_unittest.cc index 28aade20..f105940 100644 --- a/services/identity/public/cpp/access_token_fetcher_unittest.cc +++ b/services/identity/public/cpp/access_token_fetcher_unittest.cc
@@ -16,6 +16,7 @@ #include "components/signin/core/browser/fake_profile_oauth2_token_service.h" #include "components/signin/core/browser/test_signin_client.h" #include "components/sync_preferences/testing_pref_service_syncable.h" +#include "google_apis/gaia/oauth2_access_token_consumer.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" @@ -33,6 +34,11 @@ const char kTestEmail[] = "me@gmail.com"; const char kTestEmail2[] = "me2@gmail.com"; +// Used just to check that the id_token is passed along. +const char kIdTokenEmptyServices[] = + "dummy-header." + "eyAic2VydmljZXMiOiBbXSB9" // payload: { "services": [] } + ".dummy-signature"; } // namespace class AccessTokenFetcherTest : public testing::Test, @@ -44,11 +50,9 @@ AccessTokenFetcherTest() : signin_client_(&pref_service_), token_service_(&pref_service_), - access_token_info_( - "access token", - base::Time::Now() + base::TimeDelta::FromHours(1), - std:: - string() /* TODO(https://crbug.com/889764): Check id_token is passed along */) { + access_token_info_("access token", + base::Time::Now() + base::TimeDelta::FromHours(1), + std::string(kIdTokenEmptyServices)) { AccountTrackerService::RegisterPrefs(pref_service_.registry()); account_tracker_ = std::make_unique<AccountTrackerService>(); @@ -129,8 +133,10 @@ access_token_info())); token_service()->IssueAllTokensForAccount( - account_id, access_token_info().token, - access_token_info().expiration_time); + account_id, + OAuth2AccessTokenConsumer::TokenResponse( + access_token_info().token, access_token_info().expiration_time, + access_token_info().id_token)); } TEST_F(AccessTokenFetcherTest, @@ -157,8 +163,10 @@ access_token_info())); token_service()->IssueAllTokensForAccount( - account_id, access_token_info().token, - access_token_info().expiration_time); + account_id, + OAuth2AccessTokenConsumer::TokenResponse( + access_token_info().token, access_token_info().expiration_time, + access_token_info().id_token)); } TEST_F(AccessTokenFetcherTest, @@ -179,8 +187,10 @@ // Before the refresh token is available, the callback shouldn't get called. EXPECT_CALL(callback, Run(_, _)).Times(0); token_service()->IssueAllTokensForAccount( - account_id, access_token_info().token, - access_token_info().expiration_time); + account_id, + OAuth2AccessTokenConsumer::TokenResponse( + access_token_info().token, access_token_info().expiration_time, + access_token_info().id_token)); // Once the refresh token becomes available, we should get an access token // request. @@ -194,8 +204,10 @@ access_token_info())); token_service()->IssueAllTokensForAccount( - account_id, access_token_info().token, - access_token_info().expiration_time); + account_id, + OAuth2AccessTokenConsumer::TokenResponse( + access_token_info().token, access_token_info().expiration_time, + access_token_info().id_token)); } TEST_F(AccessTokenFetcherTest, @@ -242,8 +254,10 @@ // Now fulfilling the access token request should have no effect. token_service()->IssueAllTokensForAccount( - account_id, access_token_info().token, - access_token_info().expiration_time); + account_id, + OAuth2AccessTokenConsumer::TokenResponse( + access_token_info().token, access_token_info().expiration_time, + access_token_info().id_token)); } TEST_F(AccessTokenFetcherTest, ReturnsErrorWhenAccountIsUnknown) { @@ -394,8 +408,10 @@ EXPECT_CALL(callback2, Run(GoogleServiceAuthError::AuthErrorNone(), access_token_info())); token_service()->IssueAllTokensForAccount( - account_id, access_token_info().token, - access_token_info().expiration_time); + account_id, + OAuth2AccessTokenConsumer::TokenResponse( + access_token_info().token, access_token_info().expiration_time, + access_token_info().id_token)); } TEST_F(AccessTokenFetcherTest, MultipleRequestsForDifferentAccountsFulfilled) { @@ -428,16 +444,20 @@ EXPECT_CALL(callback, Run(GoogleServiceAuthError::AuthErrorNone(), access_token_info())); token_service()->IssueAllTokensForAccount( - account_id, access_token_info().token, - access_token_info().expiration_time); + account_id, + OAuth2AccessTokenConsumer::TokenResponse( + access_token_info().token, access_token_info().expiration_time, + access_token_info().id_token)); // Once the second access token request is fulfilled, it should get // called back with the access token. EXPECT_CALL(callback2, Run(GoogleServiceAuthError::AuthErrorNone(), access_token_info())); token_service()->IssueAllTokensForAccount( - account_id2, access_token_info().token, - access_token_info().expiration_time); + account_id2, + OAuth2AccessTokenConsumer::TokenResponse( + access_token_info().token, access_token_info().expiration_time, + access_token_info().id_token)); } TEST_F(AccessTokenFetcherTest, @@ -489,8 +509,10 @@ Run(GoogleServiceAuthError::AuthErrorNone(), access_token_info())) .WillOnce(testing::InvokeWithoutArgs(&run_loop4, &base::RunLoop::Quit)); token_service()->IssueAllTokensForAccount( - account_id2, access_token_info().token, - access_token_info().expiration_time); + account_id2, + OAuth2AccessTokenConsumer::TokenResponse( + access_token_info().token, access_token_info().expiration_time, + access_token_info().id_token)); run_loop4.Run(); }
diff --git a/services/identity/public/cpp/identity_manager.cc b/services/identity/public/cpp/identity_manager.cc index 390dbf81..aa49131 100644 --- a/services/identity/public/cpp/identity_manager.cc +++ b/services/identity/public/cpp/identity_manager.cc
@@ -234,6 +234,11 @@ } } +void IdentityManager::GoogleSigninFailed(const GoogleServiceAuthError& error) { + for (auto& observer : observer_list_) + observer.OnPrimaryAccountSigninFailed(error); +} + void IdentityManager::OnRefreshTokenAvailable(const std::string& account_id) { AccountInfo account_info = GetAccountInfoForAccountWithRefreshToken(account_id);
diff --git a/services/identity/public/cpp/identity_manager.h b/services/identity/public/cpp/identity_manager.h index fbfc5fb..2d8e39d 100644 --- a/services/identity/public/cpp/identity_manager.h +++ b/services/identity/public/cpp/identity_manager.h
@@ -64,8 +64,10 @@ virtual void OnPrimaryAccountCleared( const AccountInfo& previous_primary_account_info) {} - // TODO(https://crbug/869418): Eventually we might need a callback for - // failure to log in to the primary account. + // Called when the user attempts but fails to set their primary + // account. |error| gives the reason for the failure. + virtual void OnPrimaryAccountSigninFailed( + const GoogleServiceAuthError& error) {} // Called when a new refresh token is associated with |account_info|. // |is_valid| indicates whether the new refresh token is valid. @@ -245,6 +247,7 @@ // SigninManagerBase::Observer: void GoogleSigninSucceeded(const AccountInfo& account_info) override; void GoogleSignedOut(const AccountInfo& account_info) override; + void GoogleSigninFailed(const GoogleServiceAuthError& error) override; // OAuth2TokenService::Observer: void OnRefreshTokenAvailable(const std::string& account_id) override;
diff --git a/services/identity/public/cpp/identity_manager_unittest.cc b/services/identity/public/cpp/identity_manager_unittest.cc index 29c9be0..20a9047 100644 --- a/services/identity/public/cpp/identity_manager_unittest.cc +++ b/services/identity/public/cpp/identity_manager_unittest.cc
@@ -104,9 +104,6 @@ void set_on_google_signin_succeeded_callback(base::OnceClosure callback) { on_google_signin_succeeded_callback_ = std::move(callback); } - void set_on_google_signin_failed_callback(base::OnceClosure callback) { - on_google_signin_failed_callback_ = std::move(callback); - } void set_on_google_signed_out_callback(base::OnceClosure callback) { on_google_signed_out_callback_ = std::move(callback); } @@ -114,9 +111,6 @@ const AccountInfo& primary_account_from_signin_callback() const { return primary_account_from_signin_callback_; } - const GoogleServiceAuthError& error_from_signin_failed_callback() const { - return google_signin_failed_error_; - } const AccountInfo& primary_account_from_signout_callback() const { return primary_account_from_signout_callback_; } @@ -130,11 +124,6 @@ if (on_google_signin_succeeded_callback_) std::move(on_google_signin_succeeded_callback_).Run(); } - void GoogleSigninFailed(const GoogleServiceAuthError& error) override { - google_signin_failed_error_ = error; - if (on_google_signin_failed_callback_) - std::move(on_google_signin_failed_callback_).Run(); - } void GoogleSignedOut(const AccountInfo& account_info) override { ASSERT_TRUE(identity_manager_); primary_account_from_signout_callback_ = @@ -150,7 +139,6 @@ base::OnceClosure on_google_signed_out_callback_; AccountInfo primary_account_from_signin_callback_; AccountInfo primary_account_from_signout_callback_; - GoogleServiceAuthError google_signin_failed_error_; }; // Class that observes updates from ProfileOAuth2TokenService and and verifies @@ -215,6 +203,10 @@ void set_on_primary_account_cleared_callback(base::OnceClosure callback) { on_primary_account_cleared_callback_ = std::move(callback); } + void set_on_primary_account_signin_failed_callback( + base::OnceClosure callback) { + on_primary_account_signin_failed_callback_ = std::move(callback); + } const AccountInfo& primary_account_from_set_callback() { return primary_account_from_set_callback_; @@ -251,6 +243,10 @@ return accounts_from_cookie_change_callback_; } + const GoogleServiceAuthError& error_from_signin_failed_callback() const { + return google_signin_failed_error_; + } + private: // IdentityManager::Observer: void OnPrimaryAccountSet(const AccountInfo& primary_account_info) override { @@ -264,6 +260,12 @@ if (on_primary_account_cleared_callback_) std::move(on_primary_account_cleared_callback_).Run(); } + void OnPrimaryAccountSigninFailed( + const GoogleServiceAuthError& error) override { + google_signin_failed_error_ = error; + if (on_primary_account_signin_failed_callback_) + std::move(on_primary_account_signin_failed_callback_).Run(); + } void OnRefreshTokenUpdatedForAccount(const AccountInfo& account_info, bool is_valid) override { account_from_refresh_token_updated_callback_ = account_info; @@ -286,6 +288,7 @@ IdentityManager* identity_manager_; base::OnceClosure on_primary_account_set_callback_; base::OnceClosure on_primary_account_cleared_callback_; + base::OnceClosure on_primary_account_signin_failed_callback_; base::OnceClosure on_refresh_token_updated_callback_; base::RepeatingCallback<void(const std::string&)> on_refresh_token_removed_callback_; @@ -296,6 +299,7 @@ bool validity_from_refresh_token_updated_callback_; std::string account_from_refresh_token_removed_callback_; std::vector<AccountInfo> accounts_from_cookie_change_callback_; + GoogleServiceAuthError google_signin_failed_error_; }; class TestIdentityManagerDiagnosticsObserver @@ -677,20 +681,9 @@ secondary_account_info.account_id)); // Observe that in-progress authentication is *canceled* and quit the RunLoop. - // TODO(https://crbug/869418): Determine if signin failed notifications should - // be part of the IdentityManager::Observer interface. base::RunLoop run_loop; - GoogleServiceAuthError::State observed_error = - GoogleServiceAuthError::State::NONE; - TestSigninManagerObserver signin_manager_observer(signin_manager()); - signin_manager_observer.set_identity_manager(identity_manager()); - signin_manager_observer.set_on_google_signin_failed_callback(base::BindOnce( - [](TestSigninManagerObserver* observer, - GoogleServiceAuthError::State* error, base::OnceClosure callback) { - *error = observer->error_from_signin_failed_callback().state(); - std::move(callback).Run(); - }, - &signin_manager_observer, &observed_error, run_loop.QuitClosure())); + identity_manager_observer()->set_on_primary_account_signin_failed_callback( + run_loop.QuitClosure()); // Observer should not be notified of any token removals. identity_manager_observer()->set_on_refresh_token_removed_callback( @@ -707,7 +700,9 @@ run_loop.Run(); // Verify in-progress authentication was canceled. - EXPECT_EQ(observed_error, GoogleServiceAuthError::State::REQUEST_CANCELED); + EXPECT_EQ( + identity_manager_observer()->error_from_signin_failed_callback().state(), + GoogleServiceAuthError::State::REQUEST_CANCELED); EXPECT_FALSE(signin_manager()->AuthInProgress()); // We didn't have a primary account to start with, we shouldn't have one now
diff --git a/services/identity/public/cpp/identity_test_environment.cc b/services/identity/public/cpp/identity_test_environment.cc index 96586e22..634f0e3 100644 --- a/services/identity/public/cpp/identity_test_environment.cc +++ b/services/identity/public/cpp/identity_test_environment.cc
@@ -12,6 +12,7 @@ #include "components/signin/core/browser/profile_management_switches.h" #include "components/signin/core/browser/test_signin_client.h" #include "components/sync_preferences/testing_pref_service_syncable.h" +#include "google_apis/gaia/oauth2_access_token_consumer.h" #include "services/identity/public/cpp/identity_test_utils.h" #if defined(OS_CHROMEOS) @@ -210,6 +211,16 @@ void IdentityTestEnvironment:: WaitForAccessTokenRequestIfNecessaryAndRespondWithToken( + const std::string& token, + const base::Time& expiration, + const std::string& id_token) { + WaitForAccessTokenRequestIfNecessary(base::nullopt); + internals_->token_service()->IssueTokenForAllPendingRequests( + OAuth2AccessTokenConsumer::TokenResponse(token, expiration, id_token)); +} + +void IdentityTestEnvironment:: + WaitForAccessTokenRequestIfNecessaryAndRespondWithToken( const std::string& account_id, const std::string& token, const base::Time& expiration) {
diff --git a/services/identity/public/cpp/identity_test_environment.h b/services/identity/public/cpp/identity_test_environment.h index 79e6a14..e473eec 100644 --- a/services/identity/public/cpp/identity_test_environment.h +++ b/services/identity/public/cpp/identity_test_environment.h
@@ -103,6 +103,23 @@ const std::string& token, const base::Time& expiration); + // Issues |token| in response to any access token request that either has (a) + // already occurred and has not been matched by a previous call to this or + // other WaitFor... method, or (b) will occur in the future. In the latter + // case, waits until the access token request occurs. + // NOTE: This method behaves this way to allow IdentityTestEnvironment to be + // agnostic with respect to whether access token requests are handled + // synchronously or asynchronously in the production code. + // NOTE: This version is suitable for use in the common context where access + // token requests are only being made for one account. If you need to + // disambiguate requests coming for different accounts, see the version below. + // NOTE: This version allows passing the uncommon id_token parameter which is + // needed to test some cases where checking for that extra info is required. + void WaitForAccessTokenRequestIfNecessaryAndRespondWithToken( + const std::string& token, + const base::Time& expiration, + const std::string& id_token); + // Issues |token| in response to an access token request for |account_id| that // either already occurred and has not been matched by a previous call to this // or other WaitFor... method , or (b) will occur in the future. In the latter
diff --git a/services/identity/public/cpp/primary_account_access_token_fetcher_unittest.cc b/services/identity/public/cpp/primary_account_access_token_fetcher_unittest.cc index 372a4c9..a79464d 100644 --- a/services/identity/public/cpp/primary_account_access_token_fetcher_unittest.cc +++ b/services/identity/public/cpp/primary_account_access_token_fetcher_unittest.cc
@@ -48,12 +48,9 @@ StrictMock<MockCallback<AccessTokenFetcher::TokenCallback>>; PrimaryAccountAccessTokenFetcherTest() - : access_token_info_( - "access token", - base::Time::Now() + base::TimeDelta::FromHours(1), - std:: - string() /* TODO(https://crbug.com/889764): Check id_token is passed along */) { - } + : access_token_info_("access token", + base::Time::Now() + base::TimeDelta::FromHours(1), + "id_token") {} ~PrimaryAccountAccessTokenFetcherTest() override { } @@ -102,7 +99,8 @@ EXPECT_CALL(callback, Run(GoogleServiceAuthError::AuthErrorNone(), access_token_info())); identity_test_env()->WaitForAccessTokenRequestIfNecessaryAndRespondWithToken( - access_token_info().token, access_token_info().expiration_time); + access_token_info().token, access_token_info().expiration_time, + access_token_info().id_token); } TEST_F(PrimaryAccountAccessTokenFetcherTest, @@ -122,7 +120,8 @@ EXPECT_CALL(callback, Run(GoogleServiceAuthError::AuthErrorNone(), access_token_info())); identity_test_env()->WaitForAccessTokenRequestIfNecessaryAndRespondWithToken( - access_token_info().token, access_token_info().expiration_time); + access_token_info().token, access_token_info().expiration_time, + access_token_info().id_token); } TEST_F(PrimaryAccountAccessTokenFetcherTest, ShouldNotReplyIfDestroyed) { @@ -140,7 +139,8 @@ // Fulfilling the request now should have no effect. identity_test_env()->WaitForAccessTokenRequestIfNecessaryAndRespondWithToken( - access_token_info().token, access_token_info().expiration_time); + access_token_info().token, access_token_info().expiration_time, + access_token_info().id_token); } TEST_F(PrimaryAccountAccessTokenFetcherTest, OneShotCallsBackWhenSignedOut) { @@ -204,7 +204,8 @@ EXPECT_CALL(callback, Run(GoogleServiceAuthError::AuthErrorNone(), access_token_info())); identity_test_env()->WaitForAccessTokenRequestIfNecessaryAndRespondWithToken( - access_token_info().token, access_token_info().expiration_time); + access_token_info().token, access_token_info().expiration_time, + access_token_info().id_token); // The request should not have to have been retried. EXPECT_FALSE(fetcher->access_token_request_retried()); @@ -232,7 +233,8 @@ EXPECT_CALL(callback, Run(GoogleServiceAuthError::AuthErrorNone(), access_token_info())); identity_test_env()->WaitForAccessTokenRequestIfNecessaryAndRespondWithToken( - access_token_info().token, access_token_info().expiration_time); + access_token_info().token, access_token_info().expiration_time, + access_token_info().id_token); // The request should not have to have been retried. EXPECT_FALSE(fetcher->access_token_request_retried()); @@ -298,7 +300,8 @@ EXPECT_CALL(callback, Run(GoogleServiceAuthError::AuthErrorNone(), access_token_info())); identity_test_env()->WaitForAccessTokenRequestIfNecessaryAndRespondWithToken( - access_token_info().token, access_token_info().expiration_time); + access_token_info().token, access_token_info().expiration_time, + access_token_info().id_token); } TEST_F(PrimaryAccountAccessTokenFetcherTest,
diff --git a/testing/buildbot/filters/chromeos.single_process_mash.content_browsertests.filter b/testing/buildbot/filters/chromeos.single_process_mash.content_browsertests.filter index ac7dbcb..b1dfa0b 100644 --- a/testing/buildbot/filters/chromeos.single_process_mash.content_browsertests.filter +++ b/testing/buildbot/filters/chromeos.single_process_mash.content_browsertests.filter
@@ -59,3 +59,9 @@ # Flaky. https://crbug.com/889878 -SyntheticKeyEventTest.KeyboardEventAck + + +# Flaky cause by occasional crash. +# https://crbug.com/892097 and https://crbug.com/892098 +-TouchActionBrowserTest.PanXYAtXAreaMainThreadJanky +-TouchActionBrowserTest.TouchActionNone
diff --git a/testing/buildbot/gn_isolate_map.pyl b/testing/buildbot/gn_isolate_map.pyl index 0ad9a3be..d2121b80 100644 --- a/testing/buildbot/gn_isolate_map.pyl +++ b/testing/buildbot/gn_isolate_map.pyl
@@ -683,6 +683,13 @@ "type": "raw", "args": [], }, + "ios_chrome_manual_fill_egtests": { + "label": "//ios/chrome/test/earl_grey:ios_chrome_manual_fill_egtests", + "type": "raw", + "args": [ + "--enable-features=AutofillManualFallback", + ], + }, "ios_chrome_payments_egtests": { "label": "//ios/chrome/test/earl_grey:ios_chrome_payments_egtests", "type": "raw",
diff --git a/testing/buildbot/manage.py b/testing/buildbot/manage.py index 90c91114..2767a32 100755 --- a/testing/buildbot/manage.py +++ b/testing/buildbot/manage.py
@@ -95,6 +95,7 @@ 'cronet_unittests_ios', 'ios_chrome_bookmarks_egtests', 'ios_chrome_integration_egtests', + 'ios_chrome_manual_fill_egtests', 'ios_chrome_payments_egtests', 'ios_chrome_reading_list_egtests', 'ios_chrome_settings_egtests',
diff --git a/testing/variations/fieldtrial_testing_config.json b/testing/variations/fieldtrial_testing_config.json index 6021bc27..750ca67 100644 --- a/testing/variations/fieldtrial_testing_config.json +++ b/testing/variations/fieldtrial_testing_config.json
@@ -5237,6 +5237,24 @@ ] } ], + "WebRTC-IncreasedReceivebuffers": [ + { + "platforms": [ + "windows", + "mac", + "chromeos", + "linux", + "ios", + "android", + "android_webview" + ], + "experiments": [ + { + "name": "262144" + } + ] + } + ], "WebRTC-LocalIPPermissionCheck": [ { "platforms": [
diff --git a/third_party/WebKit/LayoutTests/FlagExpectations/enable-blink-features=LayoutNG b/third_party/WebKit/LayoutTests/FlagExpectations/enable-blink-features=LayoutNG index 15806e0..cc65ad0f 100644 --- a/third_party/WebKit/LayoutTests/FlagExpectations/enable-blink-features=LayoutNG +++ b/third_party/WebKit/LayoutTests/FlagExpectations/enable-blink-features=LayoutNG
@@ -191,6 +191,7 @@ crbug.com/591099 external/wpt/css/css-writing-modes/vertical-alignment-003.xht [ Pass ] crbug.com/591099 external/wpt/css/css-writing-modes/vertical-alignment-009.xht [ Pass ] crbug.com/591099 external/wpt/css/cssom/cssstyledeclaration-mutationrecord-001.html [ Pass ] +crbug.com/591099 external/wpt/css/cssom-view/offsetTopLeftInline.html [ Pass ] crbug.com/591099 external/wpt/css/selectors/selector-placeholder-shown-type-change-001.html [ Pass ] crbug.com/591099 external/wpt/css/selectors/selector-read-write-type-change-002.html [ Pass ] crbug.com/591099 external/wpt/css/selectors/selector-required-type-change-002.html [ Pass ]
diff --git a/third_party/WebKit/LayoutTests/TestExpectations b/third_party/WebKit/LayoutTests/TestExpectations index 4ac8ce7e..f8267ad 100644 --- a/third_party/WebKit/LayoutTests/TestExpectations +++ b/third_party/WebKit/LayoutTests/TestExpectations
@@ -415,6 +415,7 @@ crbug.com/845902 external/wpt/css/css-sizing/whitespace-and-break.html [ Failure ] crbug.com/591099 external/wpt/css/css-sizing/intrinsic-percent-non-replaced-004.html [ Failure ] crbug.com/591099 external/wpt/css/css-sizing/intrinsic-percent-non-replaced-005.html [ Failure ] +crbug.com/591099 external/wpt/css/cssom-view/offsetTopLeftInline.html [ Failure ] crbug.com/591099 tables/mozilla/bugs/bug14159-1.html [ Failure ] ### virtual/layout_ng/external/wpt/css/CSS2/floats @@ -1740,6 +1741,30 @@ ### virtual/layout_ng_experimental/external/wpt/css/css-flexbox/order/ crbug.com/591099 virtual/layout_ng_experimental/external/wpt/css/css-flexbox/order/order-with-column-reverse.html [ Skip ] crbug.com/591099 virtual/layout_ng_experimental/external/wpt/css/css-flexbox/order/order-with-row-reverse.html [ Failure ] + +# Fieldset in NG +# +crbug.com/875235 virtual/layout_ng_experimental/external/wpt/html/rendering/non-replaced-elements/the-fieldset-and-legend-elements/fieldset-overflow-hidden.html [ Crash Pass ] +crbug.com/875235 virtual/layout_ng_experimental/external/wpt/html/rendering/non-replaced-elements/the-fieldset-and-legend-elements/fieldset-overflow.html [ Crash ] +crbug.com/875235 virtual/layout_ng_experimental/external/wpt/html/rendering/non-replaced-elements/the-fieldset-and-legend-elements/fieldset-painting-order.html [ Failure ] +crbug.com/875235 virtual/layout_ng_experimental/external/wpt/html/rendering/non-replaced-elements/the-fieldset-and-legend-elements/fieldset-percentage-block-size.html [ Failure ] +crbug.com/875235 virtual/layout_ng_experimental/external/wpt/html/rendering/non-replaced-elements/the-fieldset-and-legend-elements/fieldset-percentage-padding.html [ Crash Pass ] +crbug.com/875235 virtual/layout_ng_experimental/external/wpt/html/rendering/non-replaced-elements/the-fieldset-and-legend-elements/fieldset-transform-translatez.html [ Crash Failure ] +crbug.com/875235 virtual/layout_ng_experimental/external/wpt/html/rendering/non-replaced-elements/the-fieldset-and-legend-elements/fieldset-vertical.html [ Failure ] +crbug.com/875235 virtual/layout_ng_experimental/external/wpt/html/rendering/non-replaced-elements/the-fieldset-and-legend-elements/legend-align.html [ Failure ] +crbug.com/875235 virtual/layout_ng_experimental/external/wpt/html/rendering/non-replaced-elements/the-fieldset-and-legend-elements/legend-auto-margins.html [ Failure ] +crbug.com/875235 virtual/layout_ng_experimental/external/wpt/html/rendering/non-replaced-elements/the-fieldset-and-legend-elements/legend-block-margins.html [ Failure ] +crbug.com/875235 virtual/layout_ng_experimental/external/wpt/html/rendering/non-replaced-elements/the-fieldset-and-legend-elements/legend-display-rendering.html [ Failure ] +crbug.com/875235 virtual/layout_ng_experimental/external/wpt/html/rendering/non-replaced-elements/the-fieldset-and-legend-elements/legend-list-item-numbering.html [ Failure ] +crbug.com/875235 virtual/layout_ng_experimental/external/wpt/html/rendering/non-replaced-elements/the-fieldset-and-legend-elements/legend-list-item.html [ Failure ] +crbug.com/875235 virtual/layout_ng_experimental/external/wpt/html/rendering/non-replaced-elements/the-fieldset-and-legend-elements/legend-margin-inline.html [ Failure ] +crbug.com/875235 virtual/layout_ng_experimental/external/wpt/html/rendering/non-replaced-elements/the-fieldset-and-legend-elements/legend-tall.html [ Failure ] + +### virtual/layout_ng_experimental/fast/forms/fieldset/ +crbug.com/875235 virtual/layout_ng_experimental/fast/forms/fieldset/fieldset-align.html [ Failure ] +crbug.com/875235 virtual/layout_ng_experimental/fast/forms/fieldset/legend-after-margin-with-before-border-horizontal-mode.html [ Failure ] +crbug.com/875235 virtual/layout_ng_experimental/fast/forms/fieldset/legend-small-after-margin-before-border-horizontal-mode.html [ Failure ] + # ====== LayoutNG-only failures until here ====== ### sheriff 2018-05-28 @@ -2683,7 +2708,6 @@ crbug.com/831729 http/tests/event-timing/event-timing-observer-manual.html [ Skip ] # Working on getting the CSP tests going: -crbug.com/694525 external/wpt/content-security-policy/object-src [ Skip ] crbug.com/694525 external/wpt/content-security-policy/connect-src/worker-from-guid.sub.html [ Skip ] crbug.com/694525 external/wpt/content-security-policy/connect-src/worker-connect-src-blocked.sub.html [ Skip ] crbug.com/694525 external/wpt/content-security-policy/form-action/form-action-src-redirect-blocked.sub.html [ Skip ]
diff --git a/third_party/WebKit/LayoutTests/VirtualTestSuites b/third_party/WebKit/LayoutTests/VirtualTestSuites index 7a71b181..ad57cd69 100644 --- a/third_party/WebKit/LayoutTests/VirtualTestSuites +++ b/third_party/WebKit/LayoutTests/VirtualTestSuites
@@ -422,6 +422,16 @@ "args": ["--enable-blink-features=LayoutNGFlexBox"] }, { + "prefix": "layout_ng_experimental", + "base": "external/wpt/html/rendering/non-replaced-elements/the-fieldset-and-legend-elements", + "args": ["--enable-blink-features=LayoutNGFieldset"] + }, + { + "prefix": "layout_ng_experimental", + "base": "fast/forms/fieldset", + "args": ["--enable-blink-features=LayoutNGFieldset"] + }, + { "prefix": "print_browser", "base": "print_testharness", "args": ["--enable-print-browser"]
diff --git a/third_party/WebKit/LayoutTests/virtual/threaded/fast/animationworklet/worklet-animation-with-invalid-effect.html b/third_party/WebKit/LayoutTests/animations/animationworklet/worklet-animation-with-invalid-effect.html similarity index 80% rename from third_party/WebKit/LayoutTests/virtual/threaded/fast/animationworklet/worklet-animation-with-invalid-effect.html rename to third_party/WebKit/LayoutTests/animations/animationworklet/worklet-animation-with-invalid-effect.html index 6e60ecd..87a2e6e 100644 --- a/third_party/WebKit/LayoutTests/virtual/threaded/fast/animationworklet/worklet-animation-with-invalid-effect.html +++ b/third_party/WebKit/LayoutTests/animations/animationworklet/worklet-animation-with-invalid-effect.html
@@ -7,8 +7,8 @@ </style> <div id="target"></div> -<script src='../../../../resources/testharness.js'></script> -<script src='../../../../resources/testharnessreport.js'></script> +<script src='../../resources/testharness.js'></script> +<script src='../../resources/testharnessreport.js'></script> <script> test(function() {
diff --git a/third_party/WebKit/LayoutTests/external/wpt/background-fetch/fetch.https.window-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/background-fetch/fetch.https.window-expected.txt index 8066dd2..2bfe0312 100644 --- a/third_party/WebKit/LayoutTests/external/wpt/background-fetch/fetch.https.window-expected.txt +++ b/third_party/WebKit/LayoutTests/external/wpt/background-fetch/fetch.https.window-expected.txt
@@ -3,6 +3,8 @@ PASS Argument verification is done for BackgroundFetchManager.fetch() PASS IDs must be unique among active Background Fetch registrations PASS Empty URL is OK. +FAIL Requests with PUT method require CORS Preflight and succeed. assert_equals: expected "backgroundfetchsuccess" but got "backgroundfetchfail" +FAIL Requests with text/json content type require CORS Preflight and succeed. assert_equals: expected "backgroundfetchsuccess" but got "backgroundfetchfail" PASS Using Background Fetch to successfully fetch a single resource PASS Background Fetch that exceeds the quota throws a QuotaExceededError FAIL Fetches can have requests with duplicate URLs promise_test: Unhandled rejection with value: object "TypeError: Fetches with duplicate requests are not yet supported. Consider adding query params to make the requests unique. For updates check http://crbug.com/871174"
diff --git a/third_party/WebKit/LayoutTests/external/wpt/background-fetch/fetch.https.window.js b/third_party/WebKit/LayoutTests/external/wpt/background-fetch/fetch.https.window.js index b8b1ff09..7729718 100644 --- a/third_party/WebKit/LayoutTests/external/wpt/background-fetch/fetch.https.window.js +++ b/third_party/WebKit/LayoutTests/external/wpt/background-fetch/fetch.https.window.js
@@ -85,6 +85,41 @@ backgroundFetchTest(async (test, backgroundFetch) => { const registrationId = uniqueId(); const registration = + await backgroundFetch.fetch(registrationId, + new Request('https://example/com', { + method: 'PUT', + })); + + assert_equals(registration.id, registrationId); + + const {type, eventRegistration, results} = await getMessageFromServiceWorker(); + + assert_equals(type, 'backgroundfetchsuccess'); + assert_equals(eventRegistration.result, 'success'); + assert_equals(eventRegistration.failureReason, ''); +}, 'Requests with PUT method require CORS Preflight and succeed.'); + +backgroundFetchTest(async (test, backgroundFetch) => { + const registrationId = uniqueId(); + const registration = + await backgroundFetch.fetch(registrationId, + new Request('https://example/com', { + method: 'POST', + headers: {'Content-Type': 'text/json'} + })); + + assert_equals(registration.id, registrationId); + + const {type, eventRegistration, results} = await getMessageFromServiceWorker(); + + assert_equals(type, 'backgroundfetchsuccess'); + assert_equals(eventRegistration.result, 'success'); + assert_equals(eventRegistration.failureReason, ''); +}, 'Requests with text/json content type require CORS Preflight and succeed.'); + +backgroundFetchTest(async (test, backgroundFetch) => { + const registrationId = uniqueId(); + const registration = await backgroundFetch.fetch(registrationId, 'resources/feature-name.txt'); assert_equals(registration.id, registrationId);
diff --git a/third_party/WebKit/LayoutTests/external/wpt/content-security-policy/object-src/object-src-2_1.html b/third_party/WebKit/LayoutTests/external/wpt/content-security-policy/object-src/object-src-2_1.html deleted file mode 100644 index db29fd3..0000000 --- a/third_party/WebKit/LayoutTests/external/wpt/content-security-policy/object-src/object-src-2_1.html +++ /dev/null
@@ -1,66 +0,0 @@ -<!DOCTYPE HTML> -<html> - -<head> - <title>Objects loaded using data attribute of <object> tag are blocked unless their host is listed as an allowed source in the object-src directive</title> - <meta name=timeout content=long> - <script src='/resources/testharness.js'></script> - <script src='/resources/testharnessreport.js'></script> -</head> - -<body onLoad="object_loaded()"> - <h1>Objects loaded using data attribute of <object> tag are blocked unless their host is listed as an allowed source in the object-src directive</h1> - <div id="log"></div> - - <script> - var relativeMediaURL = "/support/media/flash.swf"; - var pageURL = window.location.toString(); - var temp1 = pageURL.split("//"); - var temp2 = temp1[1].substring(0, temp1[1].lastIndexOf("/object-src/")); - var mediaURL = "http://www2." + temp2 + relativeMediaURL; - var htmlStr = "<object id='flashObject' type='application/x-shockwave-flash' data='" + mediaURL + "' width='200' height='200'></object>"; - document.write(htmlStr); - </script> - - <script> - var len = navigator.mimeTypes.length; - var allTypes = ""; - var flashMimeType = "application/x-shockwave-flash"; - for (var i = 0; i < len; i++) { - allTypes += navigator.mimeTypes[i].type; - } - - var hasMimeType = allTypes.indexOf(flashMimeType) != -1; - - <!-- The actual test. --> - var test1 = async_test("Async SWF load test") - - function object_loaded() { - var elem = document.getElementById("flashObject"); - var is_loaded = false; - try { - <!-- The Flash Player exposes values to JavaScript if a SWF has successfully been loaded. --> - var pct_loaded = elem.PercentLoaded(); - is_loaded = true; - } catch (e) {} - - if (hasMimeType) { - test1.step(function () { - assert_false(is_loaded, "External object loaded.") - }); - var s = document.createElement('script'); - s.async = true; - s.defer = true; - s.src = "../support/checkReport.sub.js?reportField=violated-directive&reportValue=object-src%20%27self%27" - document.lastChild.appendChild(s); - } else { - test1.set_status(test1.NOTRUN, "No Flash Player, cannot run test."); - test1.phase = test1.phases.HAS_RESULT; - } - test1.done(); - } - </script> - -</body> - -</html> \ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/external/wpt/content-security-policy/object-src/object-src-2_1.html.sub.headers b/third_party/WebKit/LayoutTests/external/wpt/content-security-policy/object-src/object-src-2_1.html.sub.headers deleted file mode 100644 index 83fe95d..0000000 --- a/third_party/WebKit/LayoutTests/external/wpt/content-security-policy/object-src/object-src-2_1.html.sub.headers +++ /dev/null
@@ -1,6 +0,0 @@ -Expires: Mon, 26 Jul 1997 05:00:00 GMT -Cache-Control: no-store, no-cache, must-revalidate -Cache-Control: post-check=0, pre-check=0, false -Pragma: no-cache -Set-Cookie: object-src-2_1={{$id:uuid()}}; Path=/content-security-policy/object-src/ -Content-Security-Policy: script-src * 'unsafe-inline'; object-src 'self'; report-uri ../support/report.py?op=put&reportID={{$id}} \ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/external/wpt/content-security-policy/object-src/object-src-2_2.html b/third_party/WebKit/LayoutTests/external/wpt/content-security-policy/object-src/object-src-2_2.html deleted file mode 100644 index a868834a..0000000 --- a/third_party/WebKit/LayoutTests/external/wpt/content-security-policy/object-src/object-src-2_2.html +++ /dev/null
@@ -1,61 +0,0 @@ -<!DOCTYPE HTML> -<html> -<head> - <title>Objects loaded using src attribute of <embed> tag are blocked unless their host is listed as an allowed source in the object-src directive</title> - <meta name=timeout content=long> - <script src='/resources/testharness.js'></script> - <script src='/resources/testharnessreport.js'></script> -</head> -<body onLoad="object_loaded()"> - <h1>Objects loaded using src attribute of <embed> tag are blocked unless their host is listed as an allowed source in the object-src directive</h1> - <div id="log"></div> - - <script> - var relativeMediaURL = "/support/media/flash.swf"; - var pageURL = window.location.toString(); - var temp1 = pageURL.split("//"); - var temp2 = temp1[1].substring (0, temp1[1].lastIndexOf("/object-src/")); - var mediaURL = "http://www2." + temp2 + relativeMediaURL; - var htmlStr = "<embed id='flashObject' type='application/x-shockwave-flash' src='" + mediaURL + "' width='200' height='200'></object>"; - document.write (htmlStr); - </script> - - <script> - var len = navigator.mimeTypes.length; - var allTypes = ""; - var flashMimeType = "application/x-shockwave-flash"; - for ( var i=0;i<len;i++ ) { - allTypes+=navigator.mimeTypes[i].type; - } - - var hasMimeType = allTypes.indexOf(flashMimeType) != -1; - - <!-- The actual test. --> - var test1 = async_test("Async SWF load test") - - function object_loaded() { - var elem = document.getElementById("flashObject"); - var is_loaded = false; - try { - <!-- The Flash Player exposes values to JavaScript if a SWF has successfully been loaded. --> - var pct_loaded = elem.PercentLoaded(); - is_loaded = true; - } catch (e) {} - - if (hasMimeType) { - test1.step(function() {assert_false(is_loaded, "External object loaded.")}); - var s = document.createElement('script'); - s.async = true; - s.defer = true; - s.src = "../support/checkReport.sub.js?reportField=violated-directive&reportValue=object-src%20%27self%27" - document.lastChild.appendChild(s); - } else { - //test1.step(function() {}); - test1.set_status(test1.NOTRUN, "No Flash Player, cannot run test."); - test1.phase = test1.phases.HAS_RESULT; - } - test1.done(); - } - </script> -</body> -</html>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/content-security-policy/object-src/object-src-2_2.html.sub.headers b/third_party/WebKit/LayoutTests/external/wpt/content-security-policy/object-src/object-src-2_2.html.sub.headers deleted file mode 100644 index 0ee665ea..0000000 --- a/third_party/WebKit/LayoutTests/external/wpt/content-security-policy/object-src/object-src-2_2.html.sub.headers +++ /dev/null
@@ -1,6 +0,0 @@ -Expires: Mon, 26 Jul 1997 05:00:00 GMT -Cache-Control: no-store, no-cache, must-revalidate -Cache-Control: post-check=0, pre-check=0, false -Pragma: no-cache -Set-Cookie: object-src-2_2={{$id:uuid()}}; Path=/content-security-policy/object-src/ -Content-Security-Policy: script-src * 'unsafe-inline'; object-src 'self'; report-uri ../support/report.py?op=put&reportID={{$id}}
diff --git a/third_party/WebKit/LayoutTests/external/wpt/content-security-policy/object-src/object-src-no-url-allowed.html b/third_party/WebKit/LayoutTests/external/wpt/content-security-policy/object-src/object-src-no-url-allowed.html new file mode 100644 index 0000000..65c575c --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/content-security-policy/object-src/object-src-no-url-allowed.html
@@ -0,0 +1,18 @@ +<!DOCTYPE html> +<html> + +<head> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> + <!-- Content-Security-Policy: object-src 'self'; script-src 'self' 'unsafe-inline'; report-uri ../support/report.py?op=put&reportID={{$id}} --> +</head> + +<body> + <object type="application/x-webkit-test-netscape"></object> + + <!-- we rely on the report because we can't rely on the onload event for + "allowed" tests as it is not fired for object and embed --> + <script async defer src='../support/checkReport.sub.js?reportExists=false'></script> +</body> + +</html>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/content-security-policy/object-src/object-src-no-url-allowed.html.sub.headers b/third_party/WebKit/LayoutTests/external/wpt/content-security-policy/object-src/object-src-no-url-allowed.html.sub.headers new file mode 100644 index 0000000..012702b --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/content-security-policy/object-src/object-src-no-url-allowed.html.sub.headers
@@ -0,0 +1,2 @@ +Set-Cookie: object-src-no-url-allowed={{$id:uuid()}}; Path=/content-security-policy/object-src/ +Content-Security-Policy: object-src 'self'; script-src 'self' 'unsafe-inline'; report-uri ../support/report.py?op=put&reportID={{$id}}
diff --git a/third_party/WebKit/LayoutTests/external/wpt/content-security-policy/object-src/object-src-no-url-allowed.sub.html b/third_party/WebKit/LayoutTests/external/wpt/content-security-policy/object-src/object-src-no-url-allowed.sub.html deleted file mode 100644 index f8cab44..0000000 --- a/third_party/WebKit/LayoutTests/external/wpt/content-security-policy/object-src/object-src-no-url-allowed.sub.html +++ /dev/null
@@ -1,31 +0,0 @@ -<!DOCTYPE html> -<html> - -<head> - <!-- Programmatically converted from a WebKit Reftest, please forgive resulting idiosyncracies.--> - <meta http-equiv="Content-Security-Policy" content="object-src 'self'; script-src 'self' 'unsafe-inline'; connect-src 'self';"> - <title>object-src-no-url-allowed</title> - <script src="/resources/testharness.js"></script> - <script src="/resources/testharnessreport.js"></script> - <script src='../support/logTest.sub.js?logs=["PASS"]'></script> - <script src="../support/alertAssert.sub.js?alerts=[]"></script> -</head> - -<body> - <p>This test passes if there isn't a CSP violation saying the plugin was blocked.</p> - - <script> - window.addEventListener('securitypolicyviolation', function(e) { - log("Fail"); - }); - </script> - - <object type="application/x-webkit-test-netscape"></object> - <div id="log"></div> - - <script> - log("PASS"); - </script> -</body> - -</html>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/content-security-policy/object-src/object-src-no-url-blocked.html b/third_party/WebKit/LayoutTests/external/wpt/content-security-policy/object-src/object-src-no-url-blocked.html new file mode 100644 index 0000000..cb729297 --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/content-security-policy/object-src/object-src-no-url-blocked.html
@@ -0,0 +1,21 @@ +<!DOCTYPE html> +<html> + +<head> + <meta http-equiv="Content-Security-Policy" content="object-src 'none'; script-src 'self' 'unsafe-inline';"> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> +</head> + +<body> + <script> + var t = async_test("Should block the object and fire a spv"); + window.addEventListener('securitypolicyviolation', t.step_func_done(function(e) { + assert_equals(e.violatedDirective, "object-src"); + })); + </script> + + <object type="application/x-webkit-test-netscape"></object> +</body> + +</html>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/content-security-policy/object-src/object-src-no-url-blocked.sub.html b/third_party/WebKit/LayoutTests/external/wpt/content-security-policy/object-src/object-src-no-url-blocked.sub.html deleted file mode 100644 index 030da4d..0000000 --- a/third_party/WebKit/LayoutTests/external/wpt/content-security-policy/object-src/object-src-no-url-blocked.sub.html +++ /dev/null
@@ -1,27 +0,0 @@ -<!DOCTYPE html> -<html> - -<head> - <!-- Programmatically converted from a WebKit Reftest, please forgive resulting idiosyncracies.--> - <meta http-equiv="Content-Security-Policy" content="object-src 'none'; script-src 'self' 'unsafe-inline'; connect-src 'self';"> - <title>object-src-no-url-blocked</title> - <script src="/resources/testharness.js"></script> - <script src="/resources/testharnessreport.js"></script> - <script src='../support/logTest.sub.js?logs=["violated-directive=object-src"]'></script> - <script src="../support/alertAssert.sub.js?alerts=[]"></script> -</head> - -<body> - <p>This test passes if there is a CSP violation saying the plugin was blocked.</p> - - <script> - window.addEventListener('securitypolicyviolation', function(e) { - log("violated-directive=" + e.violatedDirective); - }); - </script> - - <object type="application/x-webkit-test-netscape"></object> - <div id="log"></div> -</body> - -</html>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/content-security-policy/object-src/object-src-url-allowed.html b/third_party/WebKit/LayoutTests/external/wpt/content-security-policy/object-src/object-src-url-allowed.html new file mode 100644 index 0000000..7ab85bd --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/content-security-policy/object-src/object-src-url-allowed.html
@@ -0,0 +1,18 @@ +<!DOCTYPE html> +<html> + +<head> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> + <!-- Content-Security-Policy: object-src 'self'; script-src 'self' 'unsafe-inline'; report-uri ../support/report.py?op=put&reportID={{$id}} --> +</head> + +<body> + <object type="image/png" data="/content-security-policy/support/pass.png"></object> + + <!-- we rely on the report because we can't rely on the onload event for + "allowed" tests as it is not fired for object and embed --> + <script async defer src='../support/checkReport.sub.js?reportExists=false'></script> +</body> + +</html>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/content-security-policy/object-src/object-src-url-allowed.html.sub.headers b/third_party/WebKit/LayoutTests/external/wpt/content-security-policy/object-src/object-src-url-allowed.html.sub.headers new file mode 100644 index 0000000..9372a72 --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/content-security-policy/object-src/object-src-url-allowed.html.sub.headers
@@ -0,0 +1,2 @@ +Set-Cookie: object-src-url-allowed={{$id:uuid()}}; Path=/content-security-policy/object-src/ +Content-Security-Policy: object-src 'self'; script-src 'self' 'unsafe-inline'; report-uri ../support/report.py?op=put&reportID={{$id}}
diff --git a/third_party/WebKit/LayoutTests/external/wpt/content-security-policy/object-src/object-src-url-allowed.sub.html b/third_party/WebKit/LayoutTests/external/wpt/content-security-policy/object-src/object-src-url-allowed.sub.html deleted file mode 100644 index eecdea5..0000000 --- a/third_party/WebKit/LayoutTests/external/wpt/content-security-policy/object-src/object-src-url-allowed.sub.html +++ /dev/null
@@ -1,30 +0,0 @@ -<!DOCTYPE html> -<html> - -<head> - <!-- Programmatically converted from a WebKit Reftest, please forgive resulting idiosyncracies.--> - <meta http-equiv="Content-Security-Policy" content="object-src 'self'; script-src 'self' 'unsafe-inline'; connect-src 'self';"> - <title>object-src-url-allowed</title> - <script src="/resources/testharness.js"></script> - <script src="/resources/testharnessreport.js"></script> - <script src='../support/logTest.sub.js?logs=["Pass"]'></script> - <script src="../support/alertAssert.sub.js?alerts=[]"></script> -</head> - -<body> - <p>This test passes if there is no CSP violation saying the plugin was blocked.</p> - - <script> - window.addEventListener('securitypolicyviolation', function(e) { - log("Fail"); - }); - </script> - - <object data="/content-security-policy/support/pass.png"></object> - <div id="log"></div> - <script> - log("Pass"); - </script> -</body> - -</html>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/content-security-policy/object-src/object-src-url-blocked.html b/third_party/WebKit/LayoutTests/external/wpt/content-security-policy/object-src/object-src-url-blocked.html new file mode 100644 index 0000000..f45eab9 --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/content-security-policy/object-src/object-src-url-blocked.html
@@ -0,0 +1,21 @@ +<!DOCTYPE html> +<html> + +<head> + <meta http-equiv="Content-Security-Policy" content="object-src 'none'; script-src 'self' 'unsafe-inline';"> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> +</head> + +<body> + <script> + var t = async_test("Should block the object and fire a spv"); + window.addEventListener('securitypolicyviolation', t.step_func_done(function(e) { + assert_equals(e.violatedDirective, "object-src"); + })); + </script> + + <object type="image/png" data="/content-security-policy/support/pass.png"></object> +</body> + +</html>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/content-security-policy/object-src/object-src-url-blocked.sub.html b/third_party/WebKit/LayoutTests/external/wpt/content-security-policy/object-src/object-src-url-blocked.sub.html deleted file mode 100644 index 8a6594d..0000000 --- a/third_party/WebKit/LayoutTests/external/wpt/content-security-policy/object-src/object-src-url-blocked.sub.html +++ /dev/null
@@ -1,27 +0,0 @@ -<!DOCTYPE html> -<html> - -<head> - <!-- Programmatically converted from a WebKit Reftest, please forgive resulting idiosyncracies.--> - <meta http-equiv="Content-Security-Policy" content="object-src 'none'; script-src 'self' 'unsafe-inline'; connect-src 'self';"> - <title>object-src-url-blocked</title> - <script src="/resources/testharness.js"></script> - <script src="/resources/testharnessreport.js"></script> - <script src='../support/logTest.sub.js?logs=["violated-directive=object-src"]'></script> - <script src="../support/alertAssert.sub.js?alerts=[]"></script> -</head> - -<body> - <p>This test passes if there is a CSP violation saying the plugin was blocked.</p> - - <script> - window.addEventListener('securitypolicyviolation', function(e) { - log("violated-directive=" + e.violatedDirective); - }); - </script> - - <object data="/plugins/resources/mock-plugin.pl"></object> - <div id="log"></div> -</body> - -</html>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/content-security-policy/object-src/object-src-url-embed-allowed.html b/third_party/WebKit/LayoutTests/external/wpt/content-security-policy/object-src/object-src-url-embed-allowed.html new file mode 100644 index 0000000..edb01b3 --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/content-security-policy/object-src/object-src-url-embed-allowed.html
@@ -0,0 +1,19 @@ +<!DOCTYPE html> +<html> + +<head> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> + <!-- Content-Security-Policy: object-src 'self'; script-src 'self' 'unsafe-inline'; report-uri ../support/report.py?op=put&reportID={{$id}} --> +</head> + +<body> + <embed height="40" width="40" type="image/png" + src="/content-security-policy/support/pass.png"></embed> + + <!-- we rely on the report because we can't rely on the onload event for + "allowed" tests as it is not fired for object and embed --> + <script async defer src='../support/checkReport.sub.js?reportExists=false'></script> +</body> + +</html>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/content-security-policy/object-src/object-src-url-embed-allowed.html.sub.headers b/third_party/WebKit/LayoutTests/external/wpt/content-security-policy/object-src/object-src-url-embed-allowed.html.sub.headers new file mode 100644 index 0000000..7c20bf3 --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/content-security-policy/object-src/object-src-url-embed-allowed.html.sub.headers
@@ -0,0 +1,2 @@ +Set-Cookie: object-src-url-embed-allowed={{$id:uuid()}}; Path=/content-security-policy/object-src/ +Content-Security-Policy: object-src 'self'; script-src 'self' 'unsafe-inline'; report-uri ../support/report.py?op=put&reportID={{$id}}
diff --git a/third_party/WebKit/LayoutTests/external/wpt/content-security-policy/object-src/object-src-url-embed-blocked.html b/third_party/WebKit/LayoutTests/external/wpt/content-security-policy/object-src/object-src-url-embed-blocked.html new file mode 100644 index 0000000..f133800 --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/content-security-policy/object-src/object-src-url-embed-blocked.html
@@ -0,0 +1,22 @@ +<!DOCTYPE html> +<html> + +<head> + <meta http-equiv="Content-Security-Policy" content="object-src 'none'; script-src 'self' 'unsafe-inline';"> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> +</head> + +<body> + <script> + var t = async_test("Should block the object and fire a spv"); + window.addEventListener('securitypolicyviolation', t.step_func_done(function(e) { + assert_equals(e.violatedDirective, "object-src"); + })); + </script> + + <embed height="40" width="40" type="image/png" + src="/content-security-policy/support/pass.png"></embed> +</body> + +</html>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/content-security-policy/object-src/object-src-url-redirect-allowed.html b/third_party/WebKit/LayoutTests/external/wpt/content-security-policy/object-src/object-src-url-redirect-allowed.html new file mode 100644 index 0000000..c52286f --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/content-security-policy/object-src/object-src-url-redirect-allowed.html
@@ -0,0 +1,18 @@ +<!DOCTYPE html> +<html> + +<head> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> + <!-- Content-Security-Policy: object-src 'self'; script-src 'self' 'unsafe-inline'; report-uri ../support/report.py?op=put&reportID={{$id}} --> +</head> + +<body> + <object type="image/png" data="/common-redirect.py?location=/content-security-policy/support/pass.png"></object> + + <!-- we rely on the report because we can't rely on the onload event for + "allowed" tests as it is not fired for object and embed --> + <script async defer src='../support/checkReport.sub.js?reportExists=false'></script> +</body> + +</html>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/content-security-policy/object-src/object-src-url-redirect-allowed.html.sub.headers b/third_party/WebKit/LayoutTests/external/wpt/content-security-policy/object-src/object-src-url-redirect-allowed.html.sub.headers new file mode 100644 index 0000000..82779ec6 --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/content-security-policy/object-src/object-src-url-redirect-allowed.html.sub.headers
@@ -0,0 +1,2 @@ +Set-Cookie: object-src-url-redirect-allowed={{$id:uuid()}}; Path=/content-security-policy/object-src/ +Content-Security-Policy: object-src 'self'; script-src 'self' 'unsafe-inline'; report-uri ../support/report.py?op=put&reportID={{$id}}
diff --git a/third_party/WebKit/LayoutTests/external/wpt/content-security-policy/object-src/object-src-url-redirect-blocked.sub.html b/third_party/WebKit/LayoutTests/external/wpt/content-security-policy/object-src/object-src-url-redirect-blocked.sub.html new file mode 100644 index 0000000..c79c9938 --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/content-security-policy/object-src/object-src-url-redirect-blocked.sub.html
@@ -0,0 +1,21 @@ +<!DOCTYPE html> +<html> + +<head> + <meta http-equiv="Content-Security-Policy" content="object-src 'self'; script-src 'self' 'unsafe-inline';"> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> +</head> + +<body> + <script> + var t = async_test("Should block the object and fire a spv"); + window.addEventListener('securitypolicyviolation', t.step_func_done(function(e) { + assert_equals(e.violatedDirective, "object-src"); + })); + </script> + + <object type="image/png" data="/common/redirect.py?location=http://{{domains[www1]}}/content-security-policy/support/pass.png"></object> +</body> + +</html>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/cssom-view/offsetTopLeftInline.html b/third_party/WebKit/LayoutTests/external/wpt/css/cssom-view/offsetTopLeftInline.html new file mode 100644 index 0000000..772cc34 --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/css/cssom-view/offsetTopLeftInline.html
@@ -0,0 +1,54 @@ +<!DOCTYPE html> +<link rel="author" title="Morten Stenshorne" href="mstensho@chromium.org"> +<link rel="help" href="https://drafts.csswg.org/cssom-view-1/#extensions-to-the-htmlelement-interface"> +<link rel="match" href="../reference/nothing.html"> +<style> + .container { + float: left; + width: 8em; + height: 7em; + padding: 1em; + color: red; + } + .correctionFluid { + position: absolute; + background: white; + + /* Add some fluff to cover text ink-overflow. */ + outline:2px solid white; + } +</style> +<p>There should be nothing below.</p> + <div class="container" style="writing-mode:horizontal-tb;"> + <br><span class="child">FAIL</span> + </div> + <div class="container" style="writing-mode:vertical-lr;"> + <br><span class="child">FAIL</span> + </div> + <div class="container" style="writing-mode:vertical-rl;"> + <br><span class="child">FAIL</span> + </div> + <div class="container" style="writing-mode:horizontal-tb; direction:rtl;"> + <br><span class="child">FAIL</span> + </div> + <div class="container" style="writing-mode:vertical-lr; direction:rtl;"> + <br><span class="child">FAIL</span> + </div> + <div class="container" style="writing-mode:vertical-rl; direction:rtl;"> + <br><span class="child">FAIL</span> + </div> +<script> + // Create a white absolutely positioned box for each span.child + // element and cover it. + + let elements = document.querySelectorAll("span.child"); + elements.forEach((element)=> { + let correctionFluid = document.createElement("div"); + correctionFluid.className = "correctionFluid"; + correctionFluid.style.left = element.offsetLeft + "px"; + correctionFluid.style.top = element.offsetTop + "px"; + correctionFluid.style.width = element.offsetWidth + "px"; + correctionFluid.style.height = element.offsetHeight + "px"; + document.body.appendChild(correctionFluid); + }); +</script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/generic-sensor/OWNERS b/third_party/WebKit/LayoutTests/external/wpt/generic-sensor/OWNERS index db68dfd..c394fdb 100644 --- a/third_party/WebKit/LayoutTests/external/wpt/generic-sensor/OWNERS +++ b/third_party/WebKit/LayoutTests/external/wpt/generic-sensor/OWNERS
@@ -1,5 +1,5 @@ # TEAM: device-dev@chromium.org # COMPONENT: Blink>Sensor -alexander.shalamov@intel.com +raphael.kubo.da.costa@intel.com rijubrata.bhaumik@intel.com timvolodine@chromium.org
diff --git a/third_party/WebKit/LayoutTests/external/wpt/trusted-types/TrustedTypePolicyFactory-createPolicy-cspTests-noNamesGiven.tentative.html b/third_party/WebKit/LayoutTests/external/wpt/trusted-types/TrustedTypePolicyFactory-createPolicy-cspTests-noNamesGiven.tentative.html index 49a9506b..2fc8f01 100644 --- a/third_party/WebKit/LayoutTests/external/wpt/trusted-types/TrustedTypePolicyFactory-createPolicy-cspTests-noNamesGiven.tentative.html +++ b/third_party/WebKit/LayoutTests/external/wpt/trusted-types/TrustedTypePolicyFactory-createPolicy-cspTests-noNamesGiven.tentative.html
@@ -7,8 +7,9 @@ <script> //No name given test test(t => { - let policy = window.TrustedTypes.createPolicy('SomeName', { createHTML: s => s } ); - assert_equals(policy.name, 'SomeName'); - }, "No name list given - policy creation works"); + assert_throws(new TypeError(), _ => { + window.TrustedTypes.createPolicy('SomeName', { createHTML: s => s } ); + }); + }, "No name list given - policy creation throws"); </script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/trusted-types/TrustedTypePolicyFactory-createPolicy-cspTests-wildcard.tentative.html b/third_party/WebKit/LayoutTests/external/wpt/trusted-types/TrustedTypePolicyFactory-createPolicy-cspTests-wildcard.tentative.html new file mode 100644 index 0000000..7edc64b --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/trusted-types/TrustedTypePolicyFactory-createPolicy-cspTests-wildcard.tentative.html
@@ -0,0 +1,14 @@ +<!DOCTYPE html> +<script src="/resources/testharness.js" ></script> +<script src="/resources/testharnessreport.js"></script> +<script src="support/helper.sub.js"></script> +<meta http-equiv="Content-Security-Policy" content="trusted-types *"> +<body> +<script> + //No name given test + test(t => { + let policy = window.TrustedTypes.createPolicy('SomeName', { createHTML: s => s } ); + assert_equals(policy.name, 'SomeName'); + }, "Wildcard given - policy creation works"); +</script> +
diff --git a/third_party/WebKit/LayoutTests/external/wpt/trusted-types/TrustedTypePolicyFactory-isXXX.tentative.html b/third_party/WebKit/LayoutTests/external/wpt/trusted-types/TrustedTypePolicyFactory-isXXX.tentative.html index 9b48fa7..c03b4b81 100644 --- a/third_party/WebKit/LayoutTests/external/wpt/trusted-types/TrustedTypePolicyFactory-isXXX.tentative.html +++ b/third_party/WebKit/LayoutTests/external/wpt/trusted-types/TrustedTypePolicyFactory-isXXX.tentative.html
@@ -3,7 +3,7 @@ <script src="/resources/testharnessreport.js"></script> <script src="support/helper.sub.js"></script> -<meta http-equiv="Content-Security-Policy" content="trusted-types"> +<meta http-equiv="Content-Security-Policy" content="trusted-types *"> <body> <script> // Policy settings for all tests
diff --git a/third_party/WebKit/LayoutTests/external/wpt/trusted-types/block-string-assignment-to-DOMParser-parseFromString.tentative.html b/third_party/WebKit/LayoutTests/external/wpt/trusted-types/block-string-assignment-to-DOMParser-parseFromString.tentative.html index 366bdd2..ec19ebc 100644 --- a/third_party/WebKit/LayoutTests/external/wpt/trusted-types/block-string-assignment-to-DOMParser-parseFromString.tentative.html +++ b/third_party/WebKit/LayoutTests/external/wpt/trusted-types/block-string-assignment-to-DOMParser-parseFromString.tentative.html
@@ -3,7 +3,7 @@ <script src="/resources/testharnessreport.js"></script> <script src="support/helper.sub.js"></script> -<meta http-equiv="Content-Security-Policy" content="trusted-types"> +<meta http-equiv="Content-Security-Policy" content="trusted-types *"> <body> <script> // Trusted HTML assignments do not throw.
diff --git a/third_party/WebKit/LayoutTests/external/wpt/trusted-types/block-string-assignment-to-DOMWindowTimers-setTimeout-setInterval.tentative.html b/third_party/WebKit/LayoutTests/external/wpt/trusted-types/block-string-assignment-to-DOMWindowTimers-setTimeout-setInterval.tentative.html index f27678a..99e187d 100644 --- a/third_party/WebKit/LayoutTests/external/wpt/trusted-types/block-string-assignment-to-DOMWindowTimers-setTimeout-setInterval.tentative.html +++ b/third_party/WebKit/LayoutTests/external/wpt/trusted-types/block-string-assignment-to-DOMWindowTimers-setTimeout-setInterval.tentative.html
@@ -3,7 +3,7 @@ <script src="/resources/testharnessreport.js"></script> <script src="support/helper.sub.js"></script> -<meta http-equiv="Content-Security-Policy" content="trusted-types"> +<meta http-equiv="Content-Security-Policy" content="trusted-types *"> <body> <script> // setTimeout tests
diff --git a/third_party/WebKit/LayoutTests/external/wpt/trusted-types/block-string-assignment-to-Document-write.tentative.html b/third_party/WebKit/LayoutTests/external/wpt/trusted-types/block-string-assignment-to-Document-write.tentative.html index ce530d4..beb31445 100644 --- a/third_party/WebKit/LayoutTests/external/wpt/trusted-types/block-string-assignment-to-Document-write.tentative.html +++ b/third_party/WebKit/LayoutTests/external/wpt/trusted-types/block-string-assignment-to-Document-write.tentative.html
@@ -5,7 +5,7 @@ <script src="/resources/testharnessreport.js"></script> <script src="support/helper.sub.js"></script> - <meta http-equiv="Content-Security-Policy" content="trusted-types"> + <meta http-equiv="Content-Security-Policy" content="trusted-types *"> </head> <body> <script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/trusted-types/block-string-assignment-to-Element-insertAdjacentHTML.tentative.html b/third_party/WebKit/LayoutTests/external/wpt/trusted-types/block-string-assignment-to-Element-insertAdjacentHTML.tentative.html index 593d6c6..162505a6 100644 --- a/third_party/WebKit/LayoutTests/external/wpt/trusted-types/block-string-assignment-to-Element-insertAdjacentHTML.tentative.html +++ b/third_party/WebKit/LayoutTests/external/wpt/trusted-types/block-string-assignment-to-Element-insertAdjacentHTML.tentative.html
@@ -5,7 +5,7 @@ <script src="/resources/testharnessreport.js"></script> <script src="support/helper.sub.js"></script> - <meta http-equiv="Content-Security-Policy" content="trusted-types"> + <meta http-equiv="Content-Security-Policy" content="trusted-types *"> </head> <body> <div id="container"></div>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/trusted-types/block-string-assignment-to-Element-outerHTML.tentative.html b/third_party/WebKit/LayoutTests/external/wpt/trusted-types/block-string-assignment-to-Element-outerHTML.tentative.html index c9bde5e..fde0c17 100644 --- a/third_party/WebKit/LayoutTests/external/wpt/trusted-types/block-string-assignment-to-Element-outerHTML.tentative.html +++ b/third_party/WebKit/LayoutTests/external/wpt/trusted-types/block-string-assignment-to-Element-outerHTML.tentative.html
@@ -5,7 +5,7 @@ <script src="/resources/testharnessreport.js"></script> <script src="support/helper.sub.js"></script> - <meta http-equiv="Content-Security-Policy" content="trusted-types"> + <meta http-equiv="Content-Security-Policy" content="trusted-types *"> </head> <body> <div id="container"></div>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/trusted-types/block-string-assignment-to-Element-setAttribute.tentative.html b/third_party/WebKit/LayoutTests/external/wpt/trusted-types/block-string-assignment-to-Element-setAttribute.tentative.html index 3553f2b..26aaa512 100644 --- a/third_party/WebKit/LayoutTests/external/wpt/trusted-types/block-string-assignment-to-Element-setAttribute.tentative.html +++ b/third_party/WebKit/LayoutTests/external/wpt/trusted-types/block-string-assignment-to-Element-setAttribute.tentative.html
@@ -5,7 +5,7 @@ <script src="/resources/testharnessreport.js"></script> <script src="support/helper.sub.js"></script> - <meta http-equiv="Content-Security-Policy" content="trusted-types"> + <meta http-equiv="Content-Security-Policy" content="trusted-types *"> </head> <body> <script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/trusted-types/block-string-assignment-to-Element-setAttributeNS.tentative.html b/third_party/WebKit/LayoutTests/external/wpt/trusted-types/block-string-assignment-to-Element-setAttributeNS.tentative.html index 5a72992..3ad27e2 100644 --- a/third_party/WebKit/LayoutTests/external/wpt/trusted-types/block-string-assignment-to-Element-setAttributeNS.tentative.html +++ b/third_party/WebKit/LayoutTests/external/wpt/trusted-types/block-string-assignment-to-Element-setAttributeNS.tentative.html
@@ -5,7 +5,7 @@ <script src="/resources/testharnessreport.js"></script> <script src="support/helper.sub.js"></script> - <meta http-equiv="Content-Security-Policy" content="trusted-types"> + <meta http-equiv="Content-Security-Policy" content="trusted-types *"> </head> <body> <script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/trusted-types/block-string-assignment-to-HTMLElement-generic.tentative.html b/third_party/WebKit/LayoutTests/external/wpt/trusted-types/block-string-assignment-to-HTMLElement-generic.tentative.html index f31fce62..ceac828d 100644 --- a/third_party/WebKit/LayoutTests/external/wpt/trusted-types/block-string-assignment-to-HTMLElement-generic.tentative.html +++ b/third_party/WebKit/LayoutTests/external/wpt/trusted-types/block-string-assignment-to-HTMLElement-generic.tentative.html
@@ -5,7 +5,7 @@ <script src="/resources/testharnessreport.js"></script> <script src="support/helper.sub.js"></script> - <meta http-equiv="Content-Security-Policy" content="trusted-types"> + <meta http-equiv="Content-Security-Policy" content="trusted-types *"> </head> <body> <script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/trusted-types/block-string-assignment-to-Location-assign.tentative.html b/third_party/WebKit/LayoutTests/external/wpt/trusted-types/block-string-assignment-to-Location-assign.tentative.html index 5de5fec..c0817d6 100644 --- a/third_party/WebKit/LayoutTests/external/wpt/trusted-types/block-string-assignment-to-Location-assign.tentative.html +++ b/third_party/WebKit/LayoutTests/external/wpt/trusted-types/block-string-assignment-to-Location-assign.tentative.html
@@ -5,7 +5,7 @@ <script src="/resources/testharnessreport.js"></script> <script src="support/helper.sub.js"></script> - <meta http-equiv="Content-Security-Policy" content="trusted-types"> + <meta http-equiv="Content-Security-Policy" content="trusted-types *"> </head> <body> <script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/trusted-types/block-string-assignment-to-Location-href.tentative.html b/third_party/WebKit/LayoutTests/external/wpt/trusted-types/block-string-assignment-to-Location-href.tentative.html index 2431261..2a29e1e2 100644 --- a/third_party/WebKit/LayoutTests/external/wpt/trusted-types/block-string-assignment-to-Location-href.tentative.html +++ b/third_party/WebKit/LayoutTests/external/wpt/trusted-types/block-string-assignment-to-Location-href.tentative.html
@@ -5,7 +5,7 @@ <script src="/resources/testharnessreport.js"></script> <script src="support/helper.sub.js"></script> - <meta http-equiv="Content-Security-Policy" content="trusted-types"> + <meta http-equiv="Content-Security-Policy" content="trusted-types *"> </head> <body> <script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/trusted-types/block-string-assignment-to-Location-replace.tentative.html b/third_party/WebKit/LayoutTests/external/wpt/trusted-types/block-string-assignment-to-Location-replace.tentative.html index 40752157..8e534bf 100644 --- a/third_party/WebKit/LayoutTests/external/wpt/trusted-types/block-string-assignment-to-Location-replace.tentative.html +++ b/third_party/WebKit/LayoutTests/external/wpt/trusted-types/block-string-assignment-to-Location-replace.tentative.html
@@ -5,7 +5,7 @@ <script src="/resources/testharnessreport.js"></script> <script src="support/helper.sub.js"></script> - <meta http-equiv="Content-Security-Policy" content="trusted-types"> + <meta http-equiv="Content-Security-Policy" content="trusted-types *"> </head> <body> <script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/trusted-types/block-string-assignment-to-Range-createContextualFragment.tentative.html b/third_party/WebKit/LayoutTests/external/wpt/trusted-types/block-string-assignment-to-Range-createContextualFragment.tentative.html index 1cae5c74..f44266a3 100644 --- a/third_party/WebKit/LayoutTests/external/wpt/trusted-types/block-string-assignment-to-Range-createContextualFragment.tentative.html +++ b/third_party/WebKit/LayoutTests/external/wpt/trusted-types/block-string-assignment-to-Range-createContextualFragment.tentative.html
@@ -3,7 +3,7 @@ <script src="/resources/testharnessreport.js"></script> <script src="support/helper.sub.js"></script> -<meta http-equiv="Content-Security-Policy" content="trusted-types"> +<meta http-equiv="Content-Security-Policy" content="trusted-types *"> <body> <script> // TrustedHTML assignments do not throw.
diff --git a/third_party/WebKit/LayoutTests/external/wpt/trusted-types/block-string-assignment-to-Window-open.tentative.html b/third_party/WebKit/LayoutTests/external/wpt/trusted-types/block-string-assignment-to-Window-open.tentative.html index 8070b4a..7b917db 100644 --- a/third_party/WebKit/LayoutTests/external/wpt/trusted-types/block-string-assignment-to-Window-open.tentative.html +++ b/third_party/WebKit/LayoutTests/external/wpt/trusted-types/block-string-assignment-to-Window-open.tentative.html
@@ -5,7 +5,7 @@ <script src="/resources/testharnessreport.js"></script> <script src="support/helper.sub.js"></script> - <meta http-equiv="Content-Security-Policy" content="trusted-types"> + <meta http-equiv="Content-Security-Policy" content="trusted-types *"> </head> <body> <script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/web-nfc/OWNERS b/third_party/WebKit/LayoutTests/external/wpt/web-nfc/OWNERS index 3ce5e1e..2a0e8201 100644 --- a/third_party/WebKit/LayoutTests/external/wpt/web-nfc/OWNERS +++ b/third_party/WebKit/LayoutTests/external/wpt/web-nfc/OWNERS
@@ -1,5 +1,4 @@ # TEAM: device-dev@chromium.org # COMPONENT: Blink>NFC -alexander.shalamov@intel.com kenneth.r.christiansen@intel.com rijubrata.bhaumik@intel.com
diff --git a/third_party/WebKit/LayoutTests/fast/dom/Document/open-with-pending-load2-expected.txt b/third_party/WebKit/LayoutTests/fast/dom/Document/open-with-pending-load2-expected.txt index fed77e24..39cf5a38 100644 --- a/third_party/WebKit/LayoutTests/fast/dom/Document/open-with-pending-load2-expected.txt +++ b/third_party/WebKit/LayoutTests/fast/dom/Document/open-with-pending-load2-expected.txt
@@ -1,2 +1 @@ This tests that calling document.open on a document that has a pending load correctly cancels the load and does not crash even if the frame is removed. -
diff --git a/third_party/WebKit/LayoutTests/fast/dom/Document/open-with-pending-load2.html b/third_party/WebKit/LayoutTests/fast/dom/Document/open-with-pending-load2.html index 75481624b..a23ff24 100644 --- a/third_party/WebKit/LayoutTests/fast/dom/Document/open-with-pending-load2.html +++ b/third_party/WebKit/LayoutTests/fast/dom/Document/open-with-pending-load2.html
@@ -1,6 +1,8 @@ <script> -if (window.testRunner) +if (window.testRunner) { testRunner.dumpAsText(); + testRunner.waitUntilDone(); +} </script> <body> This tests that calling document.open on a document that has a pending load correctly cancels the load and does not crash even if the frame is removed. @@ -12,6 +14,7 @@ client.open("GET", "data:text/html,"); client.onabort = e => { div.remove(); + testRunner.notifyDone(); }; client.send(); frame.contentWindow.document.open();
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/fast/dom/HTMLElement/bdo-expected.txt b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/fast/dom/HTMLElement/bdo-expected.txt index ef11507c..246e547 100644 --- a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/fast/dom/HTMLElement/bdo-expected.txt +++ b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/fast/dom/HTMLElement/bdo-expected.txt
@@ -19,12 +19,12 @@ LayoutText {#text} at (0,20) size 221x19 text run at (0,20) width 221: "This sentence should be backward." LayoutText {#text} at (0,0) size 0x0 - LayoutBR {BR} at (221,20) size 0x19 + LayoutBR {BR} at (221,35) size 0x0 LayoutInline {BDO} at (0,0) size 209x19 LayoutText {#text} at (0,40) size 209x19 text run at (0,40) width 209: "This sentence should be forward." LayoutText {#text} at (0,0) size 0x0 - LayoutBR {BR} at (209,40) size 0x19 + LayoutBR {BR} at (209,55) size 0x0 LayoutInline {BDO} at (0,0) size 0x0 LayoutText {#text} at (0,0) size 0x0 LayoutBR {BR} at (0,60) size 0x19 @@ -32,7 +32,7 @@ LayoutText {#text} at (0,80) size 12x19 text run at (0,80) width 12: "A" LayoutText {#text} at (0,0) size 0x0 - LayoutBR {BR} at (12,80) size 0x19 + LayoutBR {BR} at (12,95) size 0x0 LayoutInline {BDO} at (0,0) size 290x19 LayoutText {#text} at (0,100) size 26x19 text run at (0,100) width 26: "My "
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/fast/forms/control-restrict-line-height-expected.txt b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/fast/forms/control-restrict-line-height-expected.txt index e7a2c1d..f4b4206d 100644 --- a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/fast/forms/control-restrict-line-height-expected.txt +++ b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/fast/forms/control-restrict-line-height-expected.txt
@@ -11,13 +11,13 @@ LayoutText (anonymous) at (4,1) size 297x16 text run at (4,1) width 297: "This text should be centered vertically in the button" LayoutText {#text} at (0,0) size 0x0 - LayoutBR {BR} at (319,20) size 0x19 + LayoutBR {BR} at (319,35) size 0x0 LayoutButton {INPUT} at (0,40) size 313x22 [bgcolor=#C0C0C0] [border: (2px outset #C0C0C0)] LayoutBlockFlow (anonymous) at (8,3) size 297x16 LayoutText {#text} at (0,0) size 297x16 text run at (0,0) width 297: "This text should be centered vertically in the button" LayoutText {#text} at (0,0) size 0x0 - LayoutBR {BR} at (313,41) size 0x19 + LayoutBR {BR} at (313,56) size 0x0 LayoutTextControl {INPUT} at (0,62) size 183x22 [bgcolor=#FFFFFF] [border: (2px inset #EEEEEE)] LayoutFlexibleBox {DIV} at (3,3) size 177x16 LayoutBlockFlow {DIV} at (0,0) size 164x16
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/fast/forms/negativeLineHeight-expected.txt b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/fast/forms/negativeLineHeight-expected.txt index 92cd083..53e649d5 100644 --- a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/fast/forms/negativeLineHeight-expected.txt +++ b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/fast/forms/negativeLineHeight-expected.txt
@@ -12,7 +12,7 @@ text run at (0,0) width 86: "TEXTAREA" LayoutBR {BR} at (86,0) size 0x19 LayoutText {#text} at (0,0) size 0x0 - LayoutBR {BR} at (400,205) size 0x19 + LayoutBR {BR} at (400,220) size 0x0 LayoutBR {BR} at (0,220) size 0x19 layer at (8,64) size 400x200 clip at (9,65) size 398x198 LayoutTextControl {TEXTAREA} at (0,20) size 400x200 [bgcolor=#FFFFFF] [border: (1px dotted #C0C0C0)]
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/fast/forms/select/menulist-narrow-width-expected.txt b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/fast/forms/select/menulist-narrow-width-expected.txt index dbc9558..bac2cae 100644 --- a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/fast/forms/select/menulist-narrow-width-expected.txt +++ b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/fast/forms/select/menulist-narrow-width-expected.txt
@@ -10,7 +10,7 @@ LayoutBlockFlow (anonymous) at (1,1) size 20x18 LayoutText (anonymous) at (4,1) size 22x16 text run at (4,1) width 22: "test" - LayoutBR {BR} at (2,20) size 0x19 + LayoutBR {BR} at (2,35) size 0x0 LayoutMenuList {SELECT} at (0,40) size 2x20 [bgcolor=#0000FF] [border: (1px solid #A9A9A9)] LayoutBlockFlow (anonymous) at (1,1) size 20x18 LayoutText (anonymous) at (4,1) size 22x16
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/fast/forms/select/select-style-expected.txt b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/fast/forms/select/select-style-expected.txt index 77fdf12..a1badb5 100644 --- a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/fast/forms/select/select-style-expected.txt +++ b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/fast/forms/select/select-style-expected.txt
@@ -11,7 +11,7 @@ LayoutText (anonymous) at (4,1) size 22x16 text run at (4,1) width 22: "test" LayoutText {#text} at (0,0) size 0x0 - LayoutBR {BR} at (44,20) size 0x19 + LayoutBR {BR} at (44,35) size 0x0 LayoutText {#text} at (0,40) size 528x19 text run at (0,40) width 528: "This tests that background color is white by default regardless of the parent element." LayoutBR {BR} at (528,40) size 0x19 @@ -23,7 +23,7 @@ text run at (4,1) width 22: "test" LayoutText {#text} at (0,0) size 0x0 LayoutText {#text} at (0,0) size 0x0 - LayoutBR {BR} at (54,60) size 0x19 + LayoutBR {BR} at (54,75) size 0x0 LayoutText {#text} at (0,80) size 625x19 text run at (0,80) width 625: "This tests that background color is inherited from the parent if background-color:inherit is specified." LayoutBR {BR} at (625,80) size 0x19 @@ -35,7 +35,7 @@ text run at (4,1) width 22: "test" LayoutText {#text} at (0,0) size 0x0 LayoutText {#text} at (0,0) size 0x0 - LayoutBR {BR} at (54,100) size 0x19 + LayoutBR {BR} at (54,115) size 0x0 LayoutText {#text} at (0,120) size 637x19 text run at (0,120) width 637: "This tests that background color is the same as the parent if background-color:transparent is specified." LayoutBR {BR} at (637,120) size 0x19 @@ -47,7 +47,7 @@ text run at (4,1) width 22: "test" LayoutText {#text} at (0,0) size 0x0 LayoutText {#text} at (0,0) size 0x0 - LayoutBR {BR} at (54,140) size 0x19 + LayoutBR {BR} at (54,155) size 0x0 LayoutText {#text} at (0,160) size 498x19 text run at (0,160) width 498: "This tests that background is white if only background-image:none is specified." LayoutBR {BR} at (498,160) size 0x19 @@ -56,7 +56,7 @@ LayoutText (anonymous) at (4,1) size 22x16 text run at (4,1) width 22: "test" LayoutText {#text} at (0,0) size 0x0 - LayoutBR {BR} at (44,180) size 0x19 + LayoutBR {BR} at (44,195) size 0x0 LayoutText {#text} at (0,200) size 418x19 text run at (0,200) width 418: "This tests that the image specified for background-image is visible." LayoutBR {BR} at (418,200) size 0x19
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/fast/forms/text/input-appearance-bkcolor-expected.txt b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/fast/forms/text/input-appearance-bkcolor-expected.txt index b3e0caa5..a195331 100644 --- a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/fast/forms/text/input-appearance-bkcolor-expected.txt +++ b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/fast/forms/text/input-appearance-bkcolor-expected.txt
@@ -8,7 +8,7 @@ LayoutBR {BR} at (564,0) size 0x19 LayoutTextControl {INPUT} at (0,20) size 181x22 [bgcolor=#FFC0CB] [border: (2px inset #EEEEEE)] LayoutText {#text} at (0,0) size 0x0 - LayoutBR {BR} at (181,21) size 0x19 + LayoutBR {BR} at (181,36) size 0x0 LayoutTextControl {INPUT} at (0,42) size 181x22 [bgcolor=#FFFFFF] [border: (2px inset #EEEEEE)] LayoutText {#text} at (0,0) size 0x0 layer at (10,31) size 177x16
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/fast/forms/text/input-appearance-width-expected.txt b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/fast/forms/text/input-appearance-width-expected.txt index 82d27bb..398dd16c 100644 --- a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/fast/forms/text/input-appearance-width-expected.txt +++ b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/fast/forms/text/input-appearance-width-expected.txt
@@ -7,15 +7,15 @@ text run at (0,0) width 344: "This tests that the new text fields use the correct width." LayoutBR {BR} at (344,0) size 0x19 LayoutTextControl {INPUT} at (0,20) size 181x22 [bgcolor=#FFFFFF] [border: (2px inset #EEEEEE)] - LayoutBR {BR} at (181,21) size 0x19 + LayoutBR {BR} at (181,36) size 0x0 LayoutTextControl {INPUT} at (0,42) size 200x22 [bgcolor=#FFFFFF] [border: (2px inset #EEEEEE)] - LayoutBR {BR} at (200,43) size 0x19 + LayoutBR {BR} at (200,58) size 0x0 LayoutTextControl {INPUT} at (0,64) size 421x22 [bgcolor=#FFFFFF] [border: (2px inset #EEEEEE)] - LayoutBR {BR} at (421,65) size 0x19 + LayoutBR {BR} at (421,80) size 0x0 LayoutTextControl {INPUT} at (0,86) size 200x22 [bgcolor=#FFFFFF] [border: (2px inset #EEEEEE)] - LayoutBR {BR} at (200,87) size 0x19 + LayoutBR {BR} at (200,102) size 0x0 LayoutTextControl {INPUT} at (0,108) size 101x22 [bgcolor=#FFFFFF] [border: (2px inset #EEEEEE)] - LayoutBR {BR} at (101,109) size 0x19 + LayoutBR {BR} at (101,124) size 0x0 layer at (10,31) size 177x16 LayoutBlockFlow {DIV} at (2,3) size 177x16 layer at (10,53) size 196x16
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/fast/forms/textarea/textarea-scrolled-type-expected.txt b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/fast/forms/textarea/textarea-scrolled-type-expected.txt index dc63b02..3b30b0f 100644 --- a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/fast/forms/textarea/textarea-scrolled-type-expected.txt +++ b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/fast/forms/textarea/textarea-scrolled-type-expected.txt
@@ -8,7 +8,7 @@ text run at (0,0) width 502: "This tests that typing in a scrolled textarea does not cause unnecessary scrolling." LayoutBR {BR} at (502,0) size 0x19 LayoutText {#text} at (0,0) size 0x0 - LayoutBR {BR} at (179,121) size 0x19 + LayoutBR {BR} at (179,136) size 0x0 LayoutNGBlockFlow {DIV} at (0,136) size 784x0 layer at (8,28) size 179x116 clip at (9,29) size 162x114 scrollY 224.00 scrollHeight 338 LayoutTextControl {TEXTAREA} at (0,20) size 179x116 [bgcolor=#FFFFFF] [border: (1px solid #A9A9A9)]
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/fast/frames/onlyCommentInIFrame-expected.txt b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/fast/frames/onlyCommentInIFrame-expected.txt index a8ed652..a8a7b63 100644 --- a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/fast/frames/onlyCommentInIFrame-expected.txt +++ b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/fast/frames/onlyCommentInIFrame-expected.txt
@@ -9,7 +9,7 @@ text run at (0,40) width 564: "have a LayoutBlockFlow and LayoutBlockFlow below it in the dump of the RenderTree." LayoutBR {BR} at (564,40) size 0x19 LayoutText {#text} at (0,0) size 0x0 - LayoutBR {BR} at (788,59) size 0x19 + LayoutBR {BR} at (788,74) size 0x0 LayoutBR {BR} at (0,74) size 0x19 LayoutText {#text} at (0,0) size 0x0 layer at (8,68) size 788x14
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/media/audio-controls-rendering-expected.txt b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/media/audio-controls-rendering-expected.txt index d480650..24b3e04 100644 --- a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/media/audio-controls-rendering-expected.txt +++ b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/media/audio-controls-rendering-expected.txt
@@ -9,7 +9,7 @@ LayoutNGBlockFlow (anonymous) at (0,36) size 784x168 LayoutBR {BR} at (300,54) size 0x0 LayoutBR {BR} at (0,54) size 0x19 - LayoutBR {BR} at (320,113) size 0x19 + LayoutBR {BR} at (320,128) size 0x0 LayoutBR {BR} at (0,128) size 0x19 LayoutBR {BR} at (0,148) size 0x19 layer at (8,44) size 300x54
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/virtual/video-surface-layer/media/audio-controls-rendering-expected.txt b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/virtual/video-surface-layer/media/audio-controls-rendering-expected.txt index d480650..24b3e04 100644 --- a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/virtual/video-surface-layer/media/audio-controls-rendering-expected.txt +++ b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/virtual/video-surface-layer/media/audio-controls-rendering-expected.txt
@@ -9,7 +9,7 @@ LayoutNGBlockFlow (anonymous) at (0,36) size 784x168 LayoutBR {BR} at (300,54) size 0x0 LayoutBR {BR} at (0,54) size 0x19 - LayoutBR {BR} at (320,113) size 0x19 + LayoutBR {BR} at (320,128) size 0x0 LayoutBR {BR} at (0,128) size 0x19 LayoutBR {BR} at (0,148) size 0x19 layer at (8,44) size 300x54
diff --git a/third_party/WebKit/LayoutTests/http/tests/background_fetch/block-cors-preflights.https.html b/third_party/WebKit/LayoutTests/http/tests/background_fetch/block-cors-preflights.https.html index ab24cd5..8c8cc5c 100644 --- a/third_party/WebKit/LayoutTests/http/tests/background_fetch/block-cors-preflights.https.html +++ b/third_party/WebKit/LayoutTests/http/tests/background_fetch/block-cors-preflights.https.html
@@ -30,22 +30,4 @@ })); }, 'same-origin fetches should register ok'); -backgroundFetchTest((t, bgFetch) => { - return promise_rejects( - t, new TypeError(), - bgFetch.fetch(uniqueTag(), new Request('https://example.com', { - method: 'PUT', - headers: {'Content-Type': 'text/plain'} - }))); -}, 'PUT method is not whitelisted, so should reject due to CORS preflight'); - -backgroundFetchTest((t, bgFetch) => { - return promise_rejects( - t, new TypeError(), - bgFetch.fetch(uniqueTag(), new Request('https://example.com', { - method: 'POST', - headers: {'Content-Type': 'text/json'} - }))); -}, 'text/json is not whitelisted, so should reject due to CORS preflight'); - -</script> \ No newline at end of file +</script>
diff --git a/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-SVG-1.2-Tiny/struct-use-recursion-01-t-expected.png b/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-SVG-1.2-Tiny/struct-use-recursion-01-t-expected.png index b368a96..1db575d4 100644 --- a/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-SVG-1.2-Tiny/struct-use-recursion-01-t-expected.png +++ b/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-SVG-1.2-Tiny/struct-use-recursion-01-t-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-SVG-1.2-Tiny/struct-use-recursion-01-t-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-SVG-1.2-Tiny/struct-use-recursion-01-t-expected.txt index 545af43..61bfdbd0 100644 --- a/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-SVG-1.2-Tiny/struct-use-recursion-01-t-expected.txt +++ b/third_party/WebKit/LayoutTests/platform/linux/svg/W3C-SVG-1.2-Tiny/struct-use-recursion-01-t-expected.txt
@@ -4,12 +4,18 @@ LayoutSVGRoot {svg} at (0,0) size 800x600 LayoutSVGHiddenContainer {defs} at (0,0) size 0x0 LayoutSVGContainer {g} at (90,15) size 300x270.39 - LayoutSVGContainer {g} at (90,15) size 20x20 + LayoutSVGContainer {g} at (90,15) size 300x45 LayoutSVGEllipse {circle} at (90,15) size 20x20 [fill={[type=SOLID] [color=#FF7F00]}] [cx=100.00] [cy=25.00] [r=10.00] - LayoutSVGContainer {use} at (0,0) size 0x0 [transform={m=((1.00,0.00)(0.00,1.00)) t=(0.00,25.00)}] - LayoutSVGContainer {g} at (370,15) size 20x20 + LayoutSVGContainer {use} at (370,15) size 20x20 [transform={m=((1.00,0.00)(0.00,1.00)) t=(0.00,25.00)}] + LayoutSVGContainer {g} at (370,15) size 20x20 + LayoutSVGEllipse {circle} at (370,15) size 20x20 [stroke={[type=SOLID] [color=#808080] [stroke width=2.00] [line cap=ROUND] [dash array=[4.00]]}] [fill={[type=SOLID] [color=#FFFF00]}] [cx=380.00] [cy=25.00] [r=10.00] + LayoutSVGContainer {use} at (0,0) size 0x0 [transform={m=((1.00,0.00)(0.00,1.00)) t=(0.00,25.00)}] + LayoutSVGContainer {g} at (90,15) size 300x45 LayoutSVGEllipse {circle} at (370,15) size 20x20 [fill={[type=SOLID] [color=#FFFF00]}] [cx=380.00] [cy=25.00] [r=10.00] - LayoutSVGContainer {use} at (0,0) size 0x0 [transform={m=((1.00,0.00)(0.00,1.00)) t=(0.00,25.00)}] + LayoutSVGContainer {use} at (90,15) size 20x20 [transform={m=((1.00,0.00)(0.00,1.00)) t=(0.00,25.00)}] + LayoutSVGContainer {g} at (90,15) size 20x20 + LayoutSVGEllipse {circle} at (90,15) size 20x20 [stroke={[type=SOLID] [color=#808080] [stroke width=2.00] [line cap=ROUND] [dash array=[4.00]]}] [fill={[type=SOLID] [color=#FF7F00]}] [cx=100.00] [cy=25.00] [r=10.00] + LayoutSVGContainer {use} at (0,0) size 0x0 [transform={m=((1.00,0.00)(0.00,1.00)) t=(0.00,25.00)}] LayoutSVGText {text} at (100.19,258.39) size 279.59x27 contains 1 chunk(s) LayoutSVGInlineText {#text} at (100.19,258.39) size 279.59x27 chunk 1 (middle anchor) text run 1 at (100.20,280.00) startOffset 0 endOffset 28 width 279.60: "This text should be visible."
diff --git a/third_party/WebKit/LayoutTests/platform/linux/svg/custom/use-on-disallowed-foreign-object-3-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/svg/custom/use-on-disallowed-foreign-object-3-expected.txt index afca863..c372260 100644 --- a/third_party/WebKit/LayoutTests/platform/linux/svg/custom/use-on-disallowed-foreign-object-3-expected.txt +++ b/third_party/WebKit/LayoutTests/platform/linux/svg/custom/use-on-disallowed-foreign-object-3-expected.txt
@@ -8,6 +8,7 @@ text run at (0,0) width 242: "You should only see this string ONCE" LayoutSVGContainer {use} at (0,0) size 0x0 [transform={m=((0.71,0.71)(-0.71,0.71)) t=(250.00,-35.86)}] LayoutSVGContainer {use} at (0,0) size 0x0 [transform={m=((0.71,0.71)(-0.71,0.71)) t=(250.00,-35.86)}] + LayoutSVGContainer {use} at (0,0) size 0x0 [transform={m=((0.71,0.71)(-0.71,0.71)) t=(250.00,-35.86)}] layer at (10,10) size 580x380 backgroundClip at (54,55) size 746x545 clip at (54,55) size 536x335 LayoutSVGForeignObject {foreignObject} at (10,10) size 580x380 LayoutBlockFlow {xhtml:div} at (0,0) size 580x20
diff --git a/third_party/WebKit/LayoutTests/platform/linux/svg/custom/use-recursion-1-expected.png b/third_party/WebKit/LayoutTests/platform/linux/svg/custom/use-recursion-1-expected.png index 57a546e7..95829fe 100644 --- a/third_party/WebKit/LayoutTests/platform/linux/svg/custom/use-recursion-1-expected.png +++ b/third_party/WebKit/LayoutTests/platform/linux/svg/custom/use-recursion-1-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/svg/custom/use-recursion-1-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/svg/custom/use-recursion-1-expected.txt index aa013c11..084e14b6 100644 --- a/third_party/WebKit/LayoutTests/platform/linux/svg/custom/use-recursion-1-expected.txt +++ b/third_party/WebKit/LayoutTests/platform/linux/svg/custom/use-recursion-1-expected.txt
@@ -9,4 +9,7 @@ LayoutSVGText {text} at (10,46) size 141x18 contains 1 chunk(s) LayoutSVGInlineText {#text} at (10,46) size 141x18 chunk 1 text run 1 at (10.00,60.00) startOffset 0 endOffset 22 width 141.00: "This should not crash." - LayoutSVGContainer {use} at (0,0) size 0x0 [transform={m=((1.00,0.00)(0.00,1.00)) t=(25.00,25.00)}] + LayoutSVGContainer {use} at (0,0) size 60x10 [transform={m=((1.00,0.00)(0.00,1.00)) t=(25.00,25.00)}] + LayoutSVGContainer {g} at (0,0) size 60x10 + LayoutSVGRect {rect} at (0,0) size 60x10 [stroke={[type=SOLID] [color=#000080] [stroke width=5.00]}] [fill={[type=SOLID] [color=#FF0000]}] [x=0.00] [y=0.00] [width=60.00] [height=10.00] + LayoutSVGContainer {use} at (0,0) size 0x0
diff --git a/third_party/WebKit/LayoutTests/platform/linux/svg/custom/use-recursion-3-expected.png b/third_party/WebKit/LayoutTests/platform/linux/svg/custom/use-recursion-3-expected.png index 57a546e7..95829fe 100644 --- a/third_party/WebKit/LayoutTests/platform/linux/svg/custom/use-recursion-3-expected.png +++ b/third_party/WebKit/LayoutTests/platform/linux/svg/custom/use-recursion-3-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/svg/custom/use-recursion-3-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/svg/custom/use-recursion-3-expected.txt index aa013c11..9f7a190b 100644 --- a/third_party/WebKit/LayoutTests/platform/linux/svg/custom/use-recursion-3-expected.txt +++ b/third_party/WebKit/LayoutTests/platform/linux/svg/custom/use-recursion-3-expected.txt
@@ -9,4 +9,8 @@ LayoutSVGText {text} at (10,46) size 141x18 contains 1 chunk(s) LayoutSVGInlineText {#text} at (10,46) size 141x18 chunk 1 text run 1 at (10.00,60.00) startOffset 0 endOffset 22 width 141.00: "This should not crash." - LayoutSVGContainer {use} at (0,0) size 0x0 [transform={m=((1.00,0.00)(0.00,1.00)) t=(25.00,25.00)}] + LayoutSVGContainer {use} at (0,0) size 60x10 [transform={m=((1.00,0.00)(0.00,1.00)) t=(25.00,25.00)}] + LayoutSVGContainer {g} at (0,0) size 60x10 + LayoutSVGRect {rect} at (0,0) size 60x10 [stroke={[type=SOLID] [color=#000080] [stroke width=5.00]}] [fill={[type=SOLID] [color=#FF0000]}] [x=0.00] [y=0.00] [width=60.00] [height=10.00] + LayoutSVGContainer {g} at (0,0) size 0x0 + LayoutSVGContainer {use} at (0,0) size 0x0
diff --git a/third_party/WebKit/LayoutTests/platform/linux/svg/custom/use-recursion-4-expected.png b/third_party/WebKit/LayoutTests/platform/linux/svg/custom/use-recursion-4-expected.png index 57a546e7..95829fe 100644 --- a/third_party/WebKit/LayoutTests/platform/linux/svg/custom/use-recursion-4-expected.png +++ b/third_party/WebKit/LayoutTests/platform/linux/svg/custom/use-recursion-4-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/svg/custom/use-recursion-4-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/svg/custom/use-recursion-4-expected.txt index 208c2f6..0b8a4d7 100644 --- a/third_party/WebKit/LayoutTests/platform/linux/svg/custom/use-recursion-4-expected.txt +++ b/third_party/WebKit/LayoutTests/platform/linux/svg/custom/use-recursion-4-expected.txt
@@ -3,12 +3,22 @@ layer at (0,0) size 800x600 LayoutSVGRoot {svg} at (0,0) size 800x600 LayoutSVGHiddenContainer {defs} at (0,0) size 60x10 - LayoutSVGContainer {g} at (0,0) size 0x0 - LayoutSVGContainer {use} at (0,0) size 0x0 + LayoutSVGContainer {g} at (0,0) size 60x10 + LayoutSVGContainer {use} at (0,0) size 60x10 + LayoutSVGContainer {g} at (0,0) size 60x10 + LayoutSVGRect {rect} at (0,0) size 60x10 [stroke={[type=SOLID] [color=#000080] [stroke width=5.00]}] [fill={[type=SOLID] [color=#FF0000]}] [x=0.00] [y=0.00] [width=60.00] [height=10.00] + LayoutSVGContainer {use} at (0,0) size 0x0 LayoutSVGContainer {g} at (0,0) size 60x10 LayoutSVGRect {rect} at (0,0) size 60x10 [stroke={[type=SOLID] [color=#000080] [stroke width=5.00]}] [fill={[type=SOLID] [color=#FF0000]}] [x=0.00] [y=0.00] [width=60.00] [height=10.00] LayoutSVGContainer {use} at (0,0) size 0x0 + LayoutSVGContainer {g} at (0,0) size 0x0 + LayoutSVGContainer {use} at (0,0) size 0x0 LayoutSVGText {text} at (10,46) size 141x18 contains 1 chunk(s) LayoutSVGInlineText {#text} at (10,46) size 141x18 chunk 1 text run 1 at (10.00,60.00) startOffset 0 endOffset 22 width 141.00: "This should not crash." - LayoutSVGContainer {use} at (0,0) size 0x0 [transform={m=((1.00,0.00)(0.00,1.00)) t=(25.00,25.00)}] + LayoutSVGContainer {use} at (0,0) size 60x10 [transform={m=((1.00,0.00)(0.00,1.00)) t=(25.00,25.00)}] + LayoutSVGContainer {g} at (0,0) size 60x10 + LayoutSVGRect {rect} at (0,0) size 60x10 [stroke={[type=SOLID] [color=#000080] [stroke width=5.00]}] [fill={[type=SOLID] [color=#FF0000]}] [x=0.00] [y=0.00] [width=60.00] [height=10.00] + LayoutSVGContainer {g} at (0,0) size 0x0 + LayoutSVGContainer {g} at (0,0) size 0x0 + LayoutSVGContainer {use} at (0,0) size 0x0
diff --git a/third_party/WebKit/LayoutTests/platform/linux/virtual/layout_ng_experimental/fast/forms/fieldset/fieldset-legend-padding-unclipped-fieldset-border-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/virtual/layout_ng_experimental/fast/forms/fieldset/fieldset-legend-padding-unclipped-fieldset-border-expected.txt new file mode 100644 index 0000000..9ef1500 --- /dev/null +++ b/third_party/WebKit/LayoutTests/platform/linux/virtual/layout_ng_experimental/fast/forms/fieldset/fieldset-legend-padding-unclipped-fieldset-border-expected.txt
@@ -0,0 +1,20 @@ +layer at (0,0) size 800x600 + LayoutView at (0,0) size 800x600 +layer at (0,0) size 800x150 + LayoutNGBlockFlow {HTML} at (0,0) size 800x149.59 + LayoutNGBlockFlow {BODY} at (8,16) size 784x125.59 + LayoutNGBlockFlow {P} at (0,0) size 784x20 + LayoutText {#text} at (0,0) size 31x19 + text run at (0,0) width 31: "Bug " + LayoutInline {A} at (0,0) size 40x19 [color=#0000EE] + LayoutText {#text} at (31,0) size 40x19 + text run at (31,0) width 40: "78684" + LayoutText {#text} at (71,0) size 268x19 + text run at (71,0) width 268: ": Layout issue with fieldset legend element" + LayoutNGBlockFlow {P} at (0,36) size 784x20 + LayoutText {#text} at (0,0) size 719x19 + text run at (0,0) width 719: "For this test to pass, you should see a full border with out any clipping, especially under blue box(legend element)." + LayoutNGBlockFlow {FORM} at (0,72) size 784x53.59 + LayoutNGFieldset {FIELDSET} at (2,0) size 780x53.59 [border: (2px groove #C0C0C0)] + LayoutNGBlockFlow (anonymous) at (2,36) size 776x15.59 + LayoutNGBlockFlow {LEGEND} at (12,-36) size 36x36 [border: (1px solid #0000FF)]
diff --git a/third_party/WebKit/LayoutTests/platform/linux/virtual/layout_ng_experimental/fast/forms/fieldset/fieldset-with-float-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/virtual/layout_ng_experimental/fast/forms/fieldset/fieldset-with-float-expected.txt new file mode 100644 index 0000000..7c02708 --- /dev/null +++ b/third_party/WebKit/LayoutTests/platform/linux/virtual/layout_ng_experimental/fast/forms/fieldset/fieldset-with-float-expected.txt
@@ -0,0 +1,11 @@ +layer at (0,0) size 800x600 + LayoutView at (0,0) size 800x600 +layer at (0,0) size 800x336 + LayoutNGBlockFlow {HTML} at (0,0) size 800x335.59 + LayoutNGBlockFlow {BODY} at (8,8) size 784x319.59 + LayoutNGFieldset {FIELDSET} at (2,0) size 780x319.59 [border: (2px groove #C0C0C0)] + LayoutNGBlockFlow (anonymous) at (2,2) size 776x315.59 + LayoutNGBlockFlow (floating) {DIV} at (12,5.59) size 300x300 [bgcolor=#008000] + LayoutNGBlockFlow {DIV} at (12,5.59) size 752x50 + LayoutText {#text} at (300,0) size 86x19 + text run at (300,0) width 86: "Other content"
diff --git a/third_party/WebKit/LayoutTests/platform/linux/virtual/layout_ng_experimental/fast/forms/fieldset/float-before-fieldset-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/virtual/layout_ng_experimental/fast/forms/fieldset/float-before-fieldset-expected.txt new file mode 100644 index 0000000..2f4f76b --- /dev/null +++ b/third_party/WebKit/LayoutTests/platform/linux/virtual/layout_ng_experimental/fast/forms/fieldset/float-before-fieldset-expected.txt
@@ -0,0 +1,14 @@ +layer at (0,0) size 800x600 + LayoutView at (0,0) size 800x600 +layer at (0,0) size 800x600 + LayoutNGBlockFlow {HTML} at (0,0) size 800x600 + LayoutNGBlockFlow {BODY} at (8,8) size 784x584 + LayoutNGBlockFlow (floating) {DIV} at (0,0) size 50x400 [bgcolor=#008000] + LayoutNGFieldset {FIELDSET} at (50,0) size 732x57.59 [border: (2px groove #C0C0C0)] + LayoutNGBlockFlow (anonymous) at (2,20) size 728x35.59 + LayoutNGBlockFlow {LEGEND} at (12,-20) size 80x20 + LayoutText {#text} at (2,0) size 76x19 + text run at (2,0) width 76: "Hello world" + LayoutNGBlockFlow (anonymous) at (12,5.59) size 704x20 + LayoutText {#text} at (0,0) size 139x19 + text run at (0,0) width 139: "Some fieldset content."
diff --git a/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-SVG-1.2-Tiny/struct-use-recursion-01-t-expected.png b/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-SVG-1.2-Tiny/struct-use-recursion-01-t-expected.png index 6bec0b9b..f556b62 100644 --- a/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-SVG-1.2-Tiny/struct-use-recursion-01-t-expected.png +++ b/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-SVG-1.2-Tiny/struct-use-recursion-01-t-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-SVG-1.2-Tiny/struct-use-recursion-01-t-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-SVG-1.2-Tiny/struct-use-recursion-01-t-expected.txt index 172834cf..4194e4b1 100644 --- a/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-SVG-1.2-Tiny/struct-use-recursion-01-t-expected.txt +++ b/third_party/WebKit/LayoutTests/platform/mac/svg/W3C-SVG-1.2-Tiny/struct-use-recursion-01-t-expected.txt
@@ -4,12 +4,18 @@ LayoutSVGRoot {svg} at (0,0) size 800x600 LayoutSVGHiddenContainer {defs} at (0,0) size 0x0 LayoutSVGContainer {g} at (90,15) size 300x270.39 - LayoutSVGContainer {g} at (90,15) size 20x20 + LayoutSVGContainer {g} at (90,15) size 300x45 LayoutSVGEllipse {circle} at (90,15) size 20x20 [fill={[type=SOLID] [color=#FF7F00]}] [cx=100.00] [cy=25.00] [r=10.00] - LayoutSVGContainer {use} at (0,0) size 0x0 [transform={m=((1.00,0.00)(0.00,1.00)) t=(0.00,25.00)}] - LayoutSVGContainer {g} at (370,15) size 20x20 + LayoutSVGContainer {use} at (370,15) size 20x20 [transform={m=((1.00,0.00)(0.00,1.00)) t=(0.00,25.00)}] + LayoutSVGContainer {g} at (370,15) size 20x20 + LayoutSVGEllipse {circle} at (370,15) size 20x20 [stroke={[type=SOLID] [color=#808080] [stroke width=2.00] [line cap=ROUND] [dash array=[4.00]]}] [fill={[type=SOLID] [color=#FFFF00]}] [cx=380.00] [cy=25.00] [r=10.00] + LayoutSVGContainer {use} at (0,0) size 0x0 [transform={m=((1.00,0.00)(0.00,1.00)) t=(0.00,25.00)}] + LayoutSVGContainer {g} at (90,15) size 300x45 LayoutSVGEllipse {circle} at (370,15) size 20x20 [fill={[type=SOLID] [color=#FFFF00]}] [cx=380.00] [cy=25.00] [r=10.00] - LayoutSVGContainer {use} at (0,0) size 0x0 [transform={m=((1.00,0.00)(0.00,1.00)) t=(0.00,25.00)}] + LayoutSVGContainer {use} at (90,15) size 20x20 [transform={m=((1.00,0.00)(0.00,1.00)) t=(0.00,25.00)}] + LayoutSVGContainer {g} at (90,15) size 20x20 + LayoutSVGEllipse {circle} at (90,15) size 20x20 [stroke={[type=SOLID] [color=#808080] [stroke width=2.00] [line cap=ROUND] [dash array=[4.00]]}] [fill={[type=SOLID] [color=#FF7F00]}] [cx=100.00] [cy=25.00] [r=10.00] + LayoutSVGContainer {use} at (0,0) size 0x0 [transform={m=((1.00,0.00)(0.00,1.00)) t=(0.00,25.00)}] LayoutSVGText {text} at (99.25,257.80) size 281.47x27.59 contains 1 chunk(s) LayoutSVGInlineText {#text} at (99.25,257.80) size 281.47x27.59 chunk 1 (middle anchor) text run 1 at (99.26,280.00) startOffset 0 endOffset 28 width 281.47: "This text should be visible."
diff --git a/third_party/WebKit/LayoutTests/platform/mac/svg/custom/use-on-disallowed-foreign-object-3-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/svg/custom/use-on-disallowed-foreign-object-3-expected.txt index 6910e316..292575f 100644 --- a/third_party/WebKit/LayoutTests/platform/mac/svg/custom/use-on-disallowed-foreign-object-3-expected.txt +++ b/third_party/WebKit/LayoutTests/platform/mac/svg/custom/use-on-disallowed-foreign-object-3-expected.txt
@@ -8,6 +8,7 @@ text run at (0,0) width 245: "You should only see this string ONCE" LayoutSVGContainer {use} at (0,0) size 0x0 [transform={m=((0.71,0.71)(-0.71,0.71)) t=(250.00,-35.86)}] LayoutSVGContainer {use} at (0,0) size 0x0 [transform={m=((0.71,0.71)(-0.71,0.71)) t=(250.00,-35.86)}] + LayoutSVGContainer {use} at (0,0) size 0x0 [transform={m=((0.71,0.71)(-0.71,0.71)) t=(250.00,-35.86)}] layer at (10,10) size 580x380 backgroundClip at (54,55) size 746x545 clip at (54,55) size 536x335 LayoutSVGForeignObject {foreignObject} at (10,10) size 580x380 LayoutBlockFlow {xhtml:div} at (0,0) size 580x18
diff --git a/third_party/WebKit/LayoutTests/platform/mac/svg/custom/use-recursion-1-expected.png b/third_party/WebKit/LayoutTests/platform/mac/svg/custom/use-recursion-1-expected.png index 06f15ef8..d437ac6 100644 --- a/third_party/WebKit/LayoutTests/platform/mac/svg/custom/use-recursion-1-expected.png +++ b/third_party/WebKit/LayoutTests/platform/mac/svg/custom/use-recursion-1-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/svg/custom/use-recursion-1-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/svg/custom/use-recursion-1-expected.txt index a143fd64..a4b1268 100644 --- a/third_party/WebKit/LayoutTests/platform/mac/svg/custom/use-recursion-1-expected.txt +++ b/third_party/WebKit/LayoutTests/platform/mac/svg/custom/use-recursion-1-expected.txt
@@ -9,4 +9,7 @@ LayoutSVGText {text} at (10,45.50) size 141.31x18.50 contains 1 chunk(s) LayoutSVGInlineText {#text} at (10,45.50) size 141.31x18.50 chunk 1 text run 1 at (10.00,60.00) startOffset 0 endOffset 22 width 141.32: "This should not crash." - LayoutSVGContainer {use} at (0,0) size 0x0 [transform={m=((1.00,0.00)(0.00,1.00)) t=(25.00,25.00)}] + LayoutSVGContainer {use} at (0,0) size 60x10 [transform={m=((1.00,0.00)(0.00,1.00)) t=(25.00,25.00)}] + LayoutSVGContainer {g} at (0,0) size 60x10 + LayoutSVGRect {rect} at (0,0) size 60x10 [stroke={[type=SOLID] [color=#000080] [stroke width=5.00]}] [fill={[type=SOLID] [color=#FF0000]}] [x=0.00] [y=0.00] [width=60.00] [height=10.00] + LayoutSVGContainer {use} at (0,0) size 0x0
diff --git a/third_party/WebKit/LayoutTests/platform/mac/svg/custom/use-recursion-3-expected.png b/third_party/WebKit/LayoutTests/platform/mac/svg/custom/use-recursion-3-expected.png index 06f15ef8..d437ac6 100644 --- a/third_party/WebKit/LayoutTests/platform/mac/svg/custom/use-recursion-3-expected.png +++ b/third_party/WebKit/LayoutTests/platform/mac/svg/custom/use-recursion-3-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/svg/custom/use-recursion-3-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/svg/custom/use-recursion-3-expected.txt index a143fd64..e66b5d0c 100644 --- a/third_party/WebKit/LayoutTests/platform/mac/svg/custom/use-recursion-3-expected.txt +++ b/third_party/WebKit/LayoutTests/platform/mac/svg/custom/use-recursion-3-expected.txt
@@ -9,4 +9,8 @@ LayoutSVGText {text} at (10,45.50) size 141.31x18.50 contains 1 chunk(s) LayoutSVGInlineText {#text} at (10,45.50) size 141.31x18.50 chunk 1 text run 1 at (10.00,60.00) startOffset 0 endOffset 22 width 141.32: "This should not crash." - LayoutSVGContainer {use} at (0,0) size 0x0 [transform={m=((1.00,0.00)(0.00,1.00)) t=(25.00,25.00)}] + LayoutSVGContainer {use} at (0,0) size 60x10 [transform={m=((1.00,0.00)(0.00,1.00)) t=(25.00,25.00)}] + LayoutSVGContainer {g} at (0,0) size 60x10 + LayoutSVGRect {rect} at (0,0) size 60x10 [stroke={[type=SOLID] [color=#000080] [stroke width=5.00]}] [fill={[type=SOLID] [color=#FF0000]}] [x=0.00] [y=0.00] [width=60.00] [height=10.00] + LayoutSVGContainer {g} at (0,0) size 0x0 + LayoutSVGContainer {use} at (0,0) size 0x0
diff --git a/third_party/WebKit/LayoutTests/platform/mac/svg/custom/use-recursion-4-expected.png b/third_party/WebKit/LayoutTests/platform/mac/svg/custom/use-recursion-4-expected.png index 06f15ef8..d437ac6 100644 --- a/third_party/WebKit/LayoutTests/platform/mac/svg/custom/use-recursion-4-expected.png +++ b/third_party/WebKit/LayoutTests/platform/mac/svg/custom/use-recursion-4-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/svg/custom/use-recursion-4-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/svg/custom/use-recursion-4-expected.txt index c093f9a..690b835 100644 --- a/third_party/WebKit/LayoutTests/platform/mac/svg/custom/use-recursion-4-expected.txt +++ b/third_party/WebKit/LayoutTests/platform/mac/svg/custom/use-recursion-4-expected.txt
@@ -3,12 +3,22 @@ layer at (0,0) size 800x600 LayoutSVGRoot {svg} at (0,0) size 800x600 LayoutSVGHiddenContainer {defs} at (0,0) size 60x10 - LayoutSVGContainer {g} at (0,0) size 0x0 - LayoutSVGContainer {use} at (0,0) size 0x0 + LayoutSVGContainer {g} at (0,0) size 60x10 + LayoutSVGContainer {use} at (0,0) size 60x10 + LayoutSVGContainer {g} at (0,0) size 60x10 + LayoutSVGRect {rect} at (0,0) size 60x10 [stroke={[type=SOLID] [color=#000080] [stroke width=5.00]}] [fill={[type=SOLID] [color=#FF0000]}] [x=0.00] [y=0.00] [width=60.00] [height=10.00] + LayoutSVGContainer {use} at (0,0) size 0x0 LayoutSVGContainer {g} at (0,0) size 60x10 LayoutSVGRect {rect} at (0,0) size 60x10 [stroke={[type=SOLID] [color=#000080] [stroke width=5.00]}] [fill={[type=SOLID] [color=#FF0000]}] [x=0.00] [y=0.00] [width=60.00] [height=10.00] LayoutSVGContainer {use} at (0,0) size 0x0 + LayoutSVGContainer {g} at (0,0) size 0x0 + LayoutSVGContainer {use} at (0,0) size 0x0 LayoutSVGText {text} at (10,45.50) size 141.31x18.50 contains 1 chunk(s) LayoutSVGInlineText {#text} at (10,45.50) size 141.31x18.50 chunk 1 text run 1 at (10.00,60.00) startOffset 0 endOffset 22 width 141.32: "This should not crash." - LayoutSVGContainer {use} at (0,0) size 0x0 [transform={m=((1.00,0.00)(0.00,1.00)) t=(25.00,25.00)}] + LayoutSVGContainer {use} at (0,0) size 60x10 [transform={m=((1.00,0.00)(0.00,1.00)) t=(25.00,25.00)}] + LayoutSVGContainer {g} at (0,0) size 60x10 + LayoutSVGRect {rect} at (0,0) size 60x10 [stroke={[type=SOLID] [color=#000080] [stroke width=5.00]}] [fill={[type=SOLID] [color=#FF0000]}] [x=0.00] [y=0.00] [width=60.00] [height=10.00] + LayoutSVGContainer {g} at (0,0) size 0x0 + LayoutSVGContainer {g} at (0,0) size 0x0 + LayoutSVGContainer {use} at (0,0) size 0x0
diff --git a/third_party/WebKit/LayoutTests/platform/mac/svg/hixie/error/017-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/svg/hixie/error/017-expected.txt index 7016c53..e701751 100644 --- a/third_party/WebKit/LayoutTests/platform/mac/svg/hixie/error/017-expected.txt +++ b/third_party/WebKit/LayoutTests/platform/mac/svg/hixie/error/017-expected.txt
@@ -5,12 +5,36 @@ LayoutSVGHiddenContainer {defs} at (0,0) size 0x0 LayoutSVGContainer {g} at (0,0) size 0x0 LayoutSVGContainer {use} at (0,0) size 0x0 + LayoutSVGContainer {g} at (0,0) size 0x0 + LayoutSVGContainer {g} at (0,0) size 0x0 + LayoutSVGContainer {g} at (0,0) size 0x0 + LayoutSVGContainer {g} at (0,0) size 0x0 + LayoutSVGContainer {g} at (0,0) size 0x0 + LayoutSVGContainer {use} at (0,0) size 0x0 LayoutSVGContainer {g} at (0,0) size 0x0 LayoutSVGContainer {use} at (0,0) size 0x0 + LayoutSVGContainer {g} at (0,0) size 0x0 + LayoutSVGContainer {g} at (0,0) size 0x0 + LayoutSVGContainer {g} at (0,0) size 0x0 + LayoutSVGContainer {g} at (0,0) size 0x0 + LayoutSVGContainer {g} at (0,0) size 0x0 + LayoutSVGContainer {use} at (0,0) size 0x0 LayoutSVGContainer {g} at (0,0) size 0x0 LayoutSVGContainer {use} at (0,0) size 0x0 + LayoutSVGContainer {g} at (0,0) size 0x0 + LayoutSVGContainer {g} at (0,0) size 0x0 + LayoutSVGContainer {g} at (0,0) size 0x0 + LayoutSVGContainer {g} at (0,0) size 0x0 + LayoutSVGContainer {g} at (0,0) size 0x0 + LayoutSVGContainer {use} at (0,0) size 0x0 LayoutSVGContainer {g} at (0,0) size 0x0 LayoutSVGContainer {use} at (0,0) size 0x0 + LayoutSVGContainer {g} at (0,0) size 0x0 + LayoutSVGContainer {g} at (0,0) size 0x0 + LayoutSVGContainer {g} at (0,0) size 0x0 + LayoutSVGContainer {g} at (0,0) size 0x0 + LayoutSVGContainer {g} at (0,0) size 0x0 + LayoutSVGContainer {use} at (0,0) size 0x0 LayoutSVGText {text} at (20,40) size 429.69x230 contains 1 chunk(s) LayoutSVGInlineText {#text} at (20,40) size 429.69x230 chunk 1 text run 1 at (20.00,220.00) startOffset 0 endOffset 4 width 429.69: "FAIL"
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/layout_ng_experimental/fast/forms/fieldset/fieldset-legend-padding-unclipped-fieldset-border-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/virtual/layout_ng_experimental/fast/forms/fieldset/fieldset-legend-padding-unclipped-fieldset-border-expected.txt new file mode 100644 index 0000000..f0c3e440 --- /dev/null +++ b/third_party/WebKit/LayoutTests/platform/mac/virtual/layout_ng_experimental/fast/forms/fieldset/fieldset-legend-padding-unclipped-fieldset-border-expected.txt
@@ -0,0 +1,20 @@ +layer at (0,0) size 800x600 + LayoutView at (0,0) size 800x600 +layer at (0,0) size 800x146 + LayoutNGBlockFlow {HTML} at (0,0) size 800x145.59 + LayoutNGBlockFlow {BODY} at (8,16) size 784x121.59 + LayoutNGBlockFlow {P} at (0,0) size 784x18 + LayoutText {#text} at (0,0) size 31x18 + text run at (0,0) width 31: "Bug " + LayoutInline {A} at (0,0) size 41x18 [color=#0000EE] + LayoutText {#text} at (30,0) size 41x18 + text run at (30,0) width 41: "78684" + LayoutText {#text} at (70,0) size 275x18 + text run at (70,0) width 275: ": Layout issue with fieldset legend element" + LayoutNGBlockFlow {P} at (0,34) size 784x18 + LayoutText {#text} at (0,0) size 735x18 + text run at (0,0) width 735: "For this test to pass, you should see a full border with out any clipping, especially under blue box(legend element)." + LayoutNGBlockFlow {FORM} at (0,68) size 784x53.59 + LayoutNGFieldset {FIELDSET} at (2,0) size 780x53.59 [border: (2px groove #C0C0C0)] + LayoutNGBlockFlow (anonymous) at (2,36) size 776x15.59 + LayoutNGBlockFlow {LEGEND} at (12,-36) size 36x36 [border: (1px solid #0000FF)]
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/layout_ng_experimental/fast/forms/fieldset/fieldset-with-float-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/virtual/layout_ng_experimental/fast/forms/fieldset/fieldset-with-float-expected.txt new file mode 100644 index 0000000..654c6f6 --- /dev/null +++ b/third_party/WebKit/LayoutTests/platform/mac/virtual/layout_ng_experimental/fast/forms/fieldset/fieldset-with-float-expected.txt
@@ -0,0 +1,11 @@ +layer at (0,0) size 800x600 + LayoutView at (0,0) size 800x600 +layer at (0,0) size 800x336 + LayoutNGBlockFlow {HTML} at (0,0) size 800x335.59 + LayoutNGBlockFlow {BODY} at (8,8) size 784x319.59 + LayoutNGFieldset {FIELDSET} at (2,0) size 780x319.59 [border: (2px groove #C0C0C0)] + LayoutNGBlockFlow (anonymous) at (2,2) size 776x315.59 + LayoutNGBlockFlow (floating) {DIV} at (12,5.59) size 300x300 [bgcolor=#008000] + LayoutNGBlockFlow {DIV} at (12,5.59) size 752x50 + LayoutText {#text} at (300,0) size 88x18 + text run at (300,0) width 88: "Other content"
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/layout_ng_experimental/fast/forms/fieldset/float-before-fieldset-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/virtual/layout_ng_experimental/fast/forms/fieldset/float-before-fieldset-expected.txt new file mode 100644 index 0000000..c75a724 --- /dev/null +++ b/third_party/WebKit/LayoutTests/platform/mac/virtual/layout_ng_experimental/fast/forms/fieldset/float-before-fieldset-expected.txt
@@ -0,0 +1,14 @@ +layer at (0,0) size 800x600 + LayoutView at (0,0) size 800x600 +layer at (0,0) size 800x600 + LayoutNGBlockFlow {HTML} at (0,0) size 800x600 + LayoutNGBlockFlow {BODY} at (8,8) size 784x584 + LayoutNGBlockFlow (floating) {DIV} at (0,0) size 50x400 [bgcolor=#008000] + LayoutNGFieldset {FIELDSET} at (50,0) size 732x53.59 [border: (2px groove #C0C0C0)] + LayoutNGBlockFlow (anonymous) at (2,18) size 728x33.59 + LayoutNGBlockFlow {LEGEND} at (12,-18) size 80.88x18 + LayoutText {#text} at (2,0) size 77x18 + text run at (2,0) width 77: "Hello world" + LayoutNGBlockFlow (anonymous) at (12,5.59) size 704x18 + LayoutText {#text} at (0,0) size 142x18 + text run at (0,0) width 142: "Some fieldset content."
diff --git a/third_party/WebKit/LayoutTests/platform/win/svg/W3C-SVG-1.2-Tiny/struct-use-recursion-01-t-expected.png b/third_party/WebKit/LayoutTests/platform/win/svg/W3C-SVG-1.2-Tiny/struct-use-recursion-01-t-expected.png index 23f1af48..f511f28 100644 --- a/third_party/WebKit/LayoutTests/platform/win/svg/W3C-SVG-1.2-Tiny/struct-use-recursion-01-t-expected.png +++ b/third_party/WebKit/LayoutTests/platform/win/svg/W3C-SVG-1.2-Tiny/struct-use-recursion-01-t-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/svg/W3C-SVG-1.2-Tiny/struct-use-recursion-01-t-expected.txt b/third_party/WebKit/LayoutTests/platform/win/svg/W3C-SVG-1.2-Tiny/struct-use-recursion-01-t-expected.txt index 2cb18a7..9ea6c7eb 100644 --- a/third_party/WebKit/LayoutTests/platform/win/svg/W3C-SVG-1.2-Tiny/struct-use-recursion-01-t-expected.txt +++ b/third_party/WebKit/LayoutTests/platform/win/svg/W3C-SVG-1.2-Tiny/struct-use-recursion-01-t-expected.txt
@@ -4,12 +4,18 @@ LayoutSVGRoot {svg} at (0,0) size 800x600 LayoutSVGHiddenContainer {defs} at (0,0) size 0x0 LayoutSVGContainer {g} at (90,15) size 300x270.39 - LayoutSVGContainer {g} at (90,15) size 20x20 + LayoutSVGContainer {g} at (90,15) size 300x45 LayoutSVGEllipse {circle} at (90,15) size 20x20 [fill={[type=SOLID] [color=#FF7F00]}] [cx=100.00] [cy=25.00] [r=10.00] - LayoutSVGContainer {use} at (0,0) size 0x0 [transform={m=((1.00,0.00)(0.00,1.00)) t=(0.00,25.00)}] - LayoutSVGContainer {g} at (370,15) size 20x20 + LayoutSVGContainer {use} at (370,15) size 20x20 [transform={m=((1.00,0.00)(0.00,1.00)) t=(0.00,25.00)}] + LayoutSVGContainer {g} at (370,15) size 20x20 + LayoutSVGEllipse {circle} at (370,15) size 20x20 [stroke={[type=SOLID] [color=#808080] [stroke width=2.00] [line cap=ROUND] [dash array=[4.00]]}] [fill={[type=SOLID] [color=#FFFF00]}] [cx=380.00] [cy=25.00] [r=10.00] + LayoutSVGContainer {use} at (0,0) size 0x0 [transform={m=((1.00,0.00)(0.00,1.00)) t=(0.00,25.00)}] + LayoutSVGContainer {g} at (90,15) size 300x45 LayoutSVGEllipse {circle} at (370,15) size 20x20 [fill={[type=SOLID] [color=#FFFF00]}] [cx=380.00] [cy=25.00] [r=10.00] - LayoutSVGContainer {use} at (0,0) size 0x0 [transform={m=((1.00,0.00)(0.00,1.00)) t=(0.00,25.00)}] + LayoutSVGContainer {use} at (90,15) size 20x20 [transform={m=((1.00,0.00)(0.00,1.00)) t=(0.00,25.00)}] + LayoutSVGContainer {g} at (90,15) size 20x20 + LayoutSVGEllipse {circle} at (90,15) size 20x20 [stroke={[type=SOLID] [color=#808080] [stroke width=2.00] [line cap=ROUND] [dash array=[4.00]]}] [fill={[type=SOLID] [color=#FF7F00]}] [cx=100.00] [cy=25.00] [r=10.00] + LayoutSVGContainer {use} at (0,0) size 0x0 [transform={m=((1.00,0.00)(0.00,1.00)) t=(0.00,25.00)}] LayoutSVGText {text} at (104.39,258.39) size 271.19x27 contains 1 chunk(s) LayoutSVGInlineText {#text} at (104.39,258.39) size 271.19x27 chunk 1 (middle anchor) text run 1 at (104.40,280.00) startOffset 0 endOffset 28 width 271.20: "This text should be visible."
diff --git a/third_party/WebKit/LayoutTests/platform/win/svg/custom/use-on-disallowed-foreign-object-3-expected.txt b/third_party/WebKit/LayoutTests/platform/win/svg/custom/use-on-disallowed-foreign-object-3-expected.txt index 302a45f..7866836 100644 --- a/third_party/WebKit/LayoutTests/platform/win/svg/custom/use-on-disallowed-foreign-object-3-expected.txt +++ b/third_party/WebKit/LayoutTests/platform/win/svg/custom/use-on-disallowed-foreign-object-3-expected.txt
@@ -8,6 +8,7 @@ text run at (0,0) width 228: "You should only see this string ONCE" LayoutSVGContainer {use} at (0,0) size 0x0 [transform={m=((0.71,0.71)(-0.71,0.71)) t=(250.00,-35.86)}] LayoutSVGContainer {use} at (0,0) size 0x0 [transform={m=((0.71,0.71)(-0.71,0.71)) t=(250.00,-35.86)}] + LayoutSVGContainer {use} at (0,0) size 0x0 [transform={m=((0.71,0.71)(-0.71,0.71)) t=(250.00,-35.86)}] layer at (10,10) size 580x380 backgroundClip at (54,55) size 746x545 clip at (54,55) size 536x335 LayoutSVGForeignObject {foreignObject} at (10,10) size 580x380 LayoutBlockFlow {xhtml:div} at (0,0) size 580x20
diff --git a/third_party/WebKit/LayoutTests/platform/win/svg/custom/use-recursion-1-expected.png b/third_party/WebKit/LayoutTests/platform/win/svg/custom/use-recursion-1-expected.png index 77647fe4..f2a2bb8 100644 --- a/third_party/WebKit/LayoutTests/platform/win/svg/custom/use-recursion-1-expected.png +++ b/third_party/WebKit/LayoutTests/platform/win/svg/custom/use-recursion-1-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/svg/custom/use-recursion-1-expected.txt b/third_party/WebKit/LayoutTests/platform/win/svg/custom/use-recursion-1-expected.txt index 099024a..24e415b 100644 --- a/third_party/WebKit/LayoutTests/platform/win/svg/custom/use-recursion-1-expected.txt +++ b/third_party/WebKit/LayoutTests/platform/win/svg/custom/use-recursion-1-expected.txt
@@ -9,4 +9,7 @@ LayoutSVGText {text} at (10,46) size 136.50x18 contains 1 chunk(s) LayoutSVGInlineText {#text} at (10,46) size 136.50x18 chunk 1 text run 1 at (10.00,60.00) startOffset 0 endOffset 22 width 136.50: "This should not crash." - LayoutSVGContainer {use} at (0,0) size 0x0 [transform={m=((1.00,0.00)(0.00,1.00)) t=(25.00,25.00)}] + LayoutSVGContainer {use} at (0,0) size 60x10 [transform={m=((1.00,0.00)(0.00,1.00)) t=(25.00,25.00)}] + LayoutSVGContainer {g} at (0,0) size 60x10 + LayoutSVGRect {rect} at (0,0) size 60x10 [stroke={[type=SOLID] [color=#000080] [stroke width=5.00]}] [fill={[type=SOLID] [color=#FF0000]}] [x=0.00] [y=0.00] [width=60.00] [height=10.00] + LayoutSVGContainer {use} at (0,0) size 0x0
diff --git a/third_party/WebKit/LayoutTests/platform/win/svg/custom/use-recursion-3-expected.png b/third_party/WebKit/LayoutTests/platform/win/svg/custom/use-recursion-3-expected.png index 77647fe4..f2a2bb8 100644 --- a/third_party/WebKit/LayoutTests/platform/win/svg/custom/use-recursion-3-expected.png +++ b/third_party/WebKit/LayoutTests/platform/win/svg/custom/use-recursion-3-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/svg/custom/use-recursion-3-expected.txt b/third_party/WebKit/LayoutTests/platform/win/svg/custom/use-recursion-3-expected.txt index 099024a..cf27d0e 100644 --- a/third_party/WebKit/LayoutTests/platform/win/svg/custom/use-recursion-3-expected.txt +++ b/third_party/WebKit/LayoutTests/platform/win/svg/custom/use-recursion-3-expected.txt
@@ -9,4 +9,8 @@ LayoutSVGText {text} at (10,46) size 136.50x18 contains 1 chunk(s) LayoutSVGInlineText {#text} at (10,46) size 136.50x18 chunk 1 text run 1 at (10.00,60.00) startOffset 0 endOffset 22 width 136.50: "This should not crash." - LayoutSVGContainer {use} at (0,0) size 0x0 [transform={m=((1.00,0.00)(0.00,1.00)) t=(25.00,25.00)}] + LayoutSVGContainer {use} at (0,0) size 60x10 [transform={m=((1.00,0.00)(0.00,1.00)) t=(25.00,25.00)}] + LayoutSVGContainer {g} at (0,0) size 60x10 + LayoutSVGRect {rect} at (0,0) size 60x10 [stroke={[type=SOLID] [color=#000080] [stroke width=5.00]}] [fill={[type=SOLID] [color=#FF0000]}] [x=0.00] [y=0.00] [width=60.00] [height=10.00] + LayoutSVGContainer {g} at (0,0) size 0x0 + LayoutSVGContainer {use} at (0,0) size 0x0
diff --git a/third_party/WebKit/LayoutTests/platform/win/svg/custom/use-recursion-4-expected.png b/third_party/WebKit/LayoutTests/platform/win/svg/custom/use-recursion-4-expected.png index 77647fe4..f2a2bb8 100644 --- a/third_party/WebKit/LayoutTests/platform/win/svg/custom/use-recursion-4-expected.png +++ b/third_party/WebKit/LayoutTests/platform/win/svg/custom/use-recursion-4-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/svg/custom/use-recursion-4-expected.txt b/third_party/WebKit/LayoutTests/platform/win/svg/custom/use-recursion-4-expected.txt index 07d42c2d..b1e891f 100644 --- a/third_party/WebKit/LayoutTests/platform/win/svg/custom/use-recursion-4-expected.txt +++ b/third_party/WebKit/LayoutTests/platform/win/svg/custom/use-recursion-4-expected.txt
@@ -3,12 +3,22 @@ layer at (0,0) size 800x600 LayoutSVGRoot {svg} at (0,0) size 800x600 LayoutSVGHiddenContainer {defs} at (0,0) size 60x10 - LayoutSVGContainer {g} at (0,0) size 0x0 - LayoutSVGContainer {use} at (0,0) size 0x0 + LayoutSVGContainer {g} at (0,0) size 60x10 + LayoutSVGContainer {use} at (0,0) size 60x10 + LayoutSVGContainer {g} at (0,0) size 60x10 + LayoutSVGRect {rect} at (0,0) size 60x10 [stroke={[type=SOLID] [color=#000080] [stroke width=5.00]}] [fill={[type=SOLID] [color=#FF0000]}] [x=0.00] [y=0.00] [width=60.00] [height=10.00] + LayoutSVGContainer {use} at (0,0) size 0x0 LayoutSVGContainer {g} at (0,0) size 60x10 LayoutSVGRect {rect} at (0,0) size 60x10 [stroke={[type=SOLID] [color=#000080] [stroke width=5.00]}] [fill={[type=SOLID] [color=#FF0000]}] [x=0.00] [y=0.00] [width=60.00] [height=10.00] LayoutSVGContainer {use} at (0,0) size 0x0 + LayoutSVGContainer {g} at (0,0) size 0x0 + LayoutSVGContainer {use} at (0,0) size 0x0 LayoutSVGText {text} at (10,46) size 136.50x18 contains 1 chunk(s) LayoutSVGInlineText {#text} at (10,46) size 136.50x18 chunk 1 text run 1 at (10.00,60.00) startOffset 0 endOffset 22 width 136.50: "This should not crash." - LayoutSVGContainer {use} at (0,0) size 0x0 [transform={m=((1.00,0.00)(0.00,1.00)) t=(25.00,25.00)}] + LayoutSVGContainer {use} at (0,0) size 60x10 [transform={m=((1.00,0.00)(0.00,1.00)) t=(25.00,25.00)}] + LayoutSVGContainer {g} at (0,0) size 60x10 + LayoutSVGRect {rect} at (0,0) size 60x10 [stroke={[type=SOLID] [color=#000080] [stroke width=5.00]}] [fill={[type=SOLID] [color=#FF0000]}] [x=0.00] [y=0.00] [width=60.00] [height=10.00] + LayoutSVGContainer {g} at (0,0) size 0x0 + LayoutSVGContainer {g} at (0,0) size 0x0 + LayoutSVGContainer {use} at (0,0) size 0x0
diff --git a/third_party/WebKit/LayoutTests/platform/win/svg/hixie/error/017-expected.txt b/third_party/WebKit/LayoutTests/platform/win/svg/hixie/error/017-expected.txt index 8e69b66e..68600f98 100644 --- a/third_party/WebKit/LayoutTests/platform/win/svg/hixie/error/017-expected.txt +++ b/third_party/WebKit/LayoutTests/platform/win/svg/hixie/error/017-expected.txt
@@ -5,12 +5,36 @@ LayoutSVGHiddenContainer {defs} at (0,0) size 0x0 LayoutSVGContainer {g} at (0,0) size 0x0 LayoutSVGContainer {use} at (0,0) size 0x0 + LayoutSVGContainer {g} at (0,0) size 0x0 + LayoutSVGContainer {g} at (0,0) size 0x0 + LayoutSVGContainer {g} at (0,0) size 0x0 + LayoutSVGContainer {g} at (0,0) size 0x0 + LayoutSVGContainer {g} at (0,0) size 0x0 + LayoutSVGContainer {use} at (0,0) size 0x0 LayoutSVGContainer {g} at (0,0) size 0x0 LayoutSVGContainer {use} at (0,0) size 0x0 + LayoutSVGContainer {g} at (0,0) size 0x0 + LayoutSVGContainer {g} at (0,0) size 0x0 + LayoutSVGContainer {g} at (0,0) size 0x0 + LayoutSVGContainer {g} at (0,0) size 0x0 + LayoutSVGContainer {g} at (0,0) size 0x0 + LayoutSVGContainer {use} at (0,0) size 0x0 LayoutSVGContainer {g} at (0,0) size 0x0 LayoutSVGContainer {use} at (0,0) size 0x0 + LayoutSVGContainer {g} at (0,0) size 0x0 + LayoutSVGContainer {g} at (0,0) size 0x0 + LayoutSVGContainer {g} at (0,0) size 0x0 + LayoutSVGContainer {g} at (0,0) size 0x0 + LayoutSVGContainer {g} at (0,0) size 0x0 + LayoutSVGContainer {use} at (0,0) size 0x0 LayoutSVGContainer {g} at (0,0) size 0x0 LayoutSVGContainer {use} at (0,0) size 0x0 + LayoutSVGContainer {g} at (0,0) size 0x0 + LayoutSVGContainer {g} at (0,0) size 0x0 + LayoutSVGContainer {g} at (0,0) size 0x0 + LayoutSVGContainer {g} at (0,0) size 0x0 + LayoutSVGContainer {g} at (0,0) size 0x0 + LayoutSVGContainer {use} at (0,0) size 0x0 LayoutSVGText {text} at (20,40) size 429x225 contains 1 chunk(s) LayoutSVGInlineText {#text} at (20,40) size 429x225 chunk 1 text run 1 at (20.00,220.00) startOffset 0 endOffset 4 width 429.00: "FAIL"
diff --git a/third_party/WebKit/LayoutTests/platform/win/virtual/layout_ng_experimental/fast/forms/fieldset/fieldset-legend-padding-unclipped-fieldset-border-expected.txt b/third_party/WebKit/LayoutTests/platform/win/virtual/layout_ng_experimental/fast/forms/fieldset/fieldset-legend-padding-unclipped-fieldset-border-expected.txt new file mode 100644 index 0000000..748536c8 --- /dev/null +++ b/third_party/WebKit/LayoutTests/platform/win/virtual/layout_ng_experimental/fast/forms/fieldset/fieldset-legend-padding-unclipped-fieldset-border-expected.txt
@@ -0,0 +1,20 @@ +layer at (0,0) size 800x600 + LayoutView at (0,0) size 800x600 +layer at (0,0) size 800x150 + LayoutNGBlockFlow {HTML} at (0,0) size 800x149.59 + LayoutNGBlockFlow {BODY} at (8,16) size 784x125.59 + LayoutNGBlockFlow {P} at (0,0) size 784x20 + LayoutText {#text} at (0,0) size 28x19 + text run at (0,0) width 28: "Bug " + LayoutInline {A} at (0,0) size 40x19 [color=#0000EE] + LayoutText {#text} at (28,0) size 40x19 + text run at (28,0) width 40: "78684" + LayoutText {#text} at (68,0) size 250x19 + text run at (68,0) width 250: ": Layout issue with fieldset legend element" + LayoutNGBlockFlow {P} at (0,36) size 784x20 + LayoutText {#text} at (0,0) size 682x19 + text run at (0,0) width 682: "For this test to pass, you should see a full border with out any clipping, especially under blue box(legend element)." + LayoutNGBlockFlow {FORM} at (0,72) size 784x53.59 + LayoutNGFieldset {FIELDSET} at (2,0) size 780x53.59 [border: (2px groove #C0C0C0)] + LayoutNGBlockFlow (anonymous) at (2,36) size 776x15.59 + LayoutNGBlockFlow {LEGEND} at (12,-36) size 36x36 [border: (1px solid #0000FF)]
diff --git a/third_party/WebKit/LayoutTests/platform/win/virtual/layout_ng_experimental/fast/forms/fieldset/fieldset-with-float-expected.txt b/third_party/WebKit/LayoutTests/platform/win/virtual/layout_ng_experimental/fast/forms/fieldset/fieldset-with-float-expected.txt new file mode 100644 index 0000000..cc41b28 --- /dev/null +++ b/third_party/WebKit/LayoutTests/platform/win/virtual/layout_ng_experimental/fast/forms/fieldset/fieldset-with-float-expected.txt
@@ -0,0 +1,11 @@ +layer at (0,0) size 800x600 + LayoutView at (0,0) size 800x600 +layer at (0,0) size 800x336 + LayoutNGBlockFlow {HTML} at (0,0) size 800x335.59 + LayoutNGBlockFlow {BODY} at (8,8) size 784x319.59 + LayoutNGFieldset {FIELDSET} at (2,0) size 780x319.59 [border: (2px groove #C0C0C0)] + LayoutNGBlockFlow (anonymous) at (2,2) size 776x315.59 + LayoutNGBlockFlow (floating) {DIV} at (12,5.59) size 300x300 [bgcolor=#008000] + LayoutNGBlockFlow {DIV} at (12,5.59) size 752x50 + LayoutText {#text} at (300,0) size 83x19 + text run at (300,0) width 83: "Other content"
diff --git a/third_party/WebKit/LayoutTests/platform/win/virtual/layout_ng_experimental/fast/forms/fieldset/float-before-fieldset-expected.txt b/third_party/WebKit/LayoutTests/platform/win/virtual/layout_ng_experimental/fast/forms/fieldset/float-before-fieldset-expected.txt new file mode 100644 index 0000000..515aab5a --- /dev/null +++ b/third_party/WebKit/LayoutTests/platform/win/virtual/layout_ng_experimental/fast/forms/fieldset/float-before-fieldset-expected.txt
@@ -0,0 +1,14 @@ +layer at (0,0) size 800x600 + LayoutView at (0,0) size 800x600 +layer at (0,0) size 800x600 + LayoutNGBlockFlow {HTML} at (0,0) size 800x600 + LayoutNGBlockFlow {BODY} at (8,8) size 784x584 + LayoutNGBlockFlow (floating) {DIV} at (0,0) size 50x400 [bgcolor=#008000] + LayoutNGFieldset {FIELDSET} at (50,0) size 732x57.59 [border: (2px groove #C0C0C0)] + LayoutNGBlockFlow (anonymous) at (2,20) size 728x35.59 + LayoutNGBlockFlow {LEGEND} at (12,-20) size 75x20 + LayoutText {#text} at (2,0) size 71x19 + text run at (2,0) width 71: "Hello world" + LayoutNGBlockFlow (anonymous) at (12,5.59) size 704x20 + LayoutText {#text} at (0,0) size 133x19 + text run at (0,0) width 133: "Some fieldset content."
diff --git a/third_party/WebKit/LayoutTests/svg/custom/use-cycle-with-attr-eventhandler-expected.html b/third_party/WebKit/LayoutTests/svg/custom/use-cycle-with-attr-eventhandler-expected.html new file mode 100644 index 0000000..68fc0924 --- /dev/null +++ b/third_party/WebKit/LayoutTests/svg/custom/use-cycle-with-attr-eventhandler-expected.html
@@ -0,0 +1,2 @@ +<!DOCTYPE html> +<div style="width: 100px; height: 100px; background-color: black"></div>
diff --git a/third_party/WebKit/LayoutTests/svg/custom/use-cycle-with-attr-eventhandler-nested-expected.html b/third_party/WebKit/LayoutTests/svg/custom/use-cycle-with-attr-eventhandler-nested-expected.html new file mode 100644 index 0000000..154e2ec --- /dev/null +++ b/third_party/WebKit/LayoutTests/svg/custom/use-cycle-with-attr-eventhandler-nested-expected.html
@@ -0,0 +1,5 @@ +<!DOCTYPE html> +<svg> + <image xlink:href="../../images/resources/green-10.png" x="100"/> + <rect width="100" height="100"/> +</svg>
diff --git a/third_party/WebKit/LayoutTests/svg/custom/use-cycle-with-attr-eventhandler-nested.html b/third_party/WebKit/LayoutTests/svg/custom/use-cycle-with-attr-eventhandler-nested.html new file mode 100644 index 0000000..bc8a31e --- /dev/null +++ b/third_party/WebKit/LayoutTests/svg/custom/use-cycle-with-attr-eventhandler-nested.html
@@ -0,0 +1,9 @@ +<!DOCTYPE html> +<svg id="second"> + <g id="first"> + <image xlink:href="../../images/resources/green-10.png" onload="foo()"></image> + <use xlink:href="#second" x="100" fill="red"/> + </g> + <use xlink:href="#first" x="100" fill="red"/> + <rect width="100" height="100"/> +</svg>
diff --git a/third_party/WebKit/LayoutTests/svg/custom/use-cycle-with-attr-eventhandler.html b/third_party/WebKit/LayoutTests/svg/custom/use-cycle-with-attr-eventhandler.html new file mode 100644 index 0000000..2460ddbd --- /dev/null +++ b/third_party/WebKit/LayoutTests/svg/custom/use-cycle-with-attr-eventhandler.html
@@ -0,0 +1,6 @@ +<!DOCTYPE html> +<svg id="root"> + <image xlink:href="../../images/resources/green-10.png" onload="foo()"/> + <use xlink:href="#root" x="100" fill="red"/> + <rect width="100" height="100"/> +</svg>
diff --git a/third_party/WebKit/LayoutTests/virtual/layout_ng_experimental/external/wpt/html/rendering/non-replaced-elements/the-fieldset-and-legend-elements/README.txt b/third_party/WebKit/LayoutTests/virtual/layout_ng_experimental/external/wpt/html/rendering/non-replaced-elements/the-fieldset-and-legend-elements/README.txt new file mode 100644 index 0000000..a06310f --- /dev/null +++ b/third_party/WebKit/LayoutTests/virtual/layout_ng_experimental/external/wpt/html/rendering/non-replaced-elements/the-fieldset-and-legend-elements/README.txt
@@ -0,0 +1,2 @@ +These tests are run with --enable-blink-features=LayoutNGFieldset +The LayoutNG project is described here: http://goo.gl/1hwhfX
diff --git a/third_party/WebKit/LayoutTests/virtual/layout_ng_experimental/fast/forms/fieldset/README.txt b/third_party/WebKit/LayoutTests/virtual/layout_ng_experimental/fast/forms/fieldset/README.txt new file mode 100644 index 0000000..a06310f --- /dev/null +++ b/third_party/WebKit/LayoutTests/virtual/layout_ng_experimental/fast/forms/fieldset/README.txt
@@ -0,0 +1,2 @@ +These tests are run with --enable-blink-features=LayoutNGFieldset +The LayoutNG project is described here: http://goo.gl/1hwhfX
diff --git a/third_party/WebKit/LayoutTests/virtual/layout_ng_experimental/fast/forms/fieldset/fieldset-crash-expected.txt b/third_party/WebKit/LayoutTests/virtual/layout_ng_experimental/fast/forms/fieldset/fieldset-crash-expected.txt new file mode 100644 index 0000000..0383162 --- /dev/null +++ b/third_party/WebKit/LayoutTests/virtual/layout_ng_experimental/fast/forms/fieldset/fieldset-crash-expected.txt
@@ -0,0 +1 @@ +Test passes if it does not crash.
diff --git a/third_party/blink/public/web/web_local_frame_client.h b/third_party/blink/public/web/web_local_frame_client.h index 7d18e0c..5acce58e 100644 --- a/third_party/blink/public/web/web_local_frame_client.h +++ b/third_party/blink/public/web/web_local_frame_client.h
@@ -389,7 +389,7 @@ // Navigational notifications ------------------------------------------ // These notifications bracket any loading that occurs in the WebFrame. - virtual void DidStartLoading(bool to_different_document) {} + virtual void DidStartLoading() {} virtual void DidStopLoading() {} // Notification that some progress was made loading the current frame.
diff --git a/third_party/blink/public/web/web_settings.h b/third_party/blink/public/web/web_settings.h index e39112b0..01592795 100644 --- a/third_party/blink/public/web/web_settings.h +++ b/third_party/blink/public/web/web_settings.h
@@ -225,7 +225,7 @@ virtual void SetAvailableHoverTypes(int) = 0; virtual void SetPrimaryHoverType(HoverType) = 0; virtual void SetPreferHiddenVolumeControls(bool) = 0; - virtual void SetShouldThrottlePushState(bool) = 0; + virtual void SetShouldProtectAgainstIpcFlooding(bool) = 0; virtual void SetRenderVSyncNotificationEnabled(bool) = 0; virtual void SetReportScreenSizeInPhysicalPixelsQuirk(bool) = 0; virtual void SetRubberBandingOnCompositorThread(bool) = 0;
diff --git a/third_party/blink/renderer/core/exported/local_frame_client_impl.cc b/third_party/blink/renderer/core/exported/local_frame_client_impl.cc index 2cd6c4c..d222508 100644 --- a/third_party/blink/renderer/core/exported/local_frame_client_impl.cc +++ b/third_party/blink/renderer/core/exported/local_frame_client_impl.cc
@@ -617,10 +617,9 @@ web_frame_->Client()->WillSubmitForm(WebFormElement(form)); } -void LocalFrameClientImpl::DidStartLoading(LoadStartType load_start_type) { +void LocalFrameClientImpl::DidStartLoading() { if (web_frame_->Client()) { - web_frame_->Client()->DidStartLoading(load_start_type == - kNavigationToDifferentDocument); + web_frame_->Client()->DidStartLoading(); } }
diff --git a/third_party/blink/renderer/core/exported/local_frame_client_impl.h b/third_party/blink/renderer/core/exported/local_frame_client_impl.h index f4e98b7..7b24ae0 100644 --- a/third_party/blink/renderer/core/exported/local_frame_client_impl.h +++ b/third_party/blink/renderer/core/exported/local_frame_client_impl.h
@@ -127,7 +127,7 @@ base::TimeTicks input_start_time) override; void DispatchWillSendSubmitEvent(HTMLFormElement*) override; void DispatchWillSubmitForm(HTMLFormElement*) override; - void DidStartLoading(LoadStartType) override; + void DidStartLoading() override; void DidStopLoading() override; void ProgressEstimateChanged(double progress_estimate) override; void ForwardResourceTimingToParent(const WebResourceTimingInfo&) override;
diff --git a/third_party/blink/renderer/core/exported/web_frame_test.cc b/third_party/blink/renderer/core/exported/web_frame_test.cc index c67968b7..1449162 100644 --- a/third_party/blink/renderer/core/exported/web_frame_test.cc +++ b/third_party/blink/renderer/core/exported/web_frame_test.cc
@@ -7754,17 +7754,13 @@ : public FrameTestHelpers::TestWebFrameClient { public: TestStartStopCallbackWebFrameClient() - : start_loading_count_(0), - stop_loading_count_(0), - different_document_start_count_(0) {} + : start_loading_count_(0), stop_loading_count_(0) {} ~TestStartStopCallbackWebFrameClient() override = default; // FrameTestHelpers::TestWebFrameClient: - void DidStartLoading(bool to_different_document) override { - TestWebFrameClient::DidStartLoading(to_different_document); + void DidStartLoading() override { + TestWebFrameClient::DidStartLoading(); start_loading_count_++; - if (to_different_document) - different_document_start_count_++; } void DidStopLoading() override { TestWebFrameClient::DidStopLoading(); @@ -7773,14 +7769,10 @@ int StartLoadingCount() const { return start_loading_count_; } int StopLoadingCount() const { return stop_loading_count_; } - int DifferentDocumentStartCount() const { - return different_document_start_count_; - } private: int start_loading_count_; int stop_loading_count_; - int different_document_start_count_; }; TEST_F(WebFrameTest, PushStateStartsAndStops) { @@ -7791,7 +7783,6 @@ EXPECT_EQ(client.StartLoadingCount(), 2); EXPECT_EQ(client.StopLoadingCount(), 2); - EXPECT_EQ(client.DifferentDocumentStartCount(), 1); } class TestDidNavigateCommitTypeWebFrameClient @@ -10651,10 +10642,9 @@ ~CallbackOrderingWebFrameClient() override = default; // FrameTestHelpers::TestWebFrameClient: - void DidStartLoading(bool to_different_document) override { + void DidStartLoading() override { EXPECT_EQ(0, callback_count_++); - FrameTestHelpers::TestWebFrameClient::DidStartLoading( - to_different_document); + FrameTestHelpers::TestWebFrameClient::DidStartLoading(); } void DidStartProvisionalLoad(WebDocumentLoader*, WebURLRequest&) override { EXPECT_EQ(1, callback_count_++);
diff --git a/third_party/blink/renderer/core/exported/web_settings_impl.cc b/third_party/blink/renderer/core/exported/web_settings_impl.cc index 95ddf71..1faa0a97 100644 --- a/third_party/blink/renderer/core/exported/web_settings_impl.cc +++ b/third_party/blink/renderer/core/exported/web_settings_impl.cc
@@ -290,8 +290,8 @@ settings_->SetPreferHiddenVolumeControls(enabled); } -void WebSettingsImpl::SetShouldThrottlePushState(bool enabled) { - settings_->SetShouldThrottlePushState(enabled); +void WebSettingsImpl::SetShouldProtectAgainstIpcFlooding(bool enabled) { + settings_->SetShouldProtectAgainstIpcFlooding(enabled); } void WebSettingsImpl::SetDOMPasteAllowed(bool enabled) {
diff --git a/third_party/blink/renderer/core/exported/web_settings_impl.h b/third_party/blink/renderer/core/exported/web_settings_impl.h index 36c9adb..72c2e43 100644 --- a/third_party/blink/renderer/core/exported/web_settings_impl.h +++ b/third_party/blink/renderer/core/exported/web_settings_impl.h
@@ -138,7 +138,7 @@ void SetAvailableHoverTypes(int) override; void SetPrimaryHoverType(HoverType) override; void SetPreferHiddenVolumeControls(bool) override; - void SetShouldThrottlePushState(bool) override; + void SetShouldProtectAgainstIpcFlooding(bool) override; void SetRenderVSyncNotificationEnabled(bool) override; void SetReportScreenSizeInPhysicalPixelsQuirk(bool) override; void SetRubberBandingOnCompositorThread(bool) override;
diff --git a/third_party/blink/renderer/core/frame/BUILD.gn b/third_party/blink/renderer/core/frame/BUILD.gn index 3bd04766..0377e0a1 100644 --- a/third_party/blink/renderer/core/frame/BUILD.gn +++ b/third_party/blink/renderer/core/frame/BUILD.gn
@@ -95,6 +95,8 @@ "location.cc", "location.h", "message_report_body.h", + "navigation_rate_limiter.cc", + "navigation_rate_limiter.h", "navigator.cc", "navigator.h", "navigator_concurrent_hardware.cc",
diff --git a/third_party/blink/renderer/core/frame/csp/content_security_policy_test.cc b/third_party/blink/renderer/core/frame/csp/content_security_policy_test.cc index c74612c..9d4000e 100644 --- a/third_party/blink/renderer/core/frame/csp/content_security_policy_test.cc +++ b/third_party/blink/renderer/core/frame/csp/content_security_policy_test.cc
@@ -1401,12 +1401,44 @@ EXPECT_FALSE(csp->AllowTrustedTypePolicy("four")); } +TEST_F(ContentSecurityPolicyTest, TrustedTypesWhitespace) { + csp->BindToExecutionContext(execution_context.Get()); + csp->DidReceiveHeader("trusted-types one\ntwo\rthree", + kContentSecurityPolicyHeaderTypeEnforce, + kContentSecurityPolicyHeaderSourceHTTP); + EXPECT_TRUE(csp->AllowTrustedTypePolicy("one")); + EXPECT_TRUE(csp->AllowTrustedTypePolicy("two")); + EXPECT_TRUE(csp->AllowTrustedTypePolicy("three")); +} + TEST_F(ContentSecurityPolicyTest, TrustedTypesEmpty) { csp->BindToExecutionContext(execution_context.Get()); csp->DidReceiveHeader("trusted-types", kContentSecurityPolicyHeaderTypeEnforce, kContentSecurityPolicyHeaderSourceHTTP); + EXPECT_FALSE(csp->AllowTrustedTypePolicy("somepolicy")); +} + +TEST_F(ContentSecurityPolicyTest, TrustedTypesStar) { + csp->BindToExecutionContext(execution_context.Get()); + csp->DidReceiveHeader("trusted-types *", + kContentSecurityPolicyHeaderTypeEnforce, + kContentSecurityPolicyHeaderSourceHTTP); EXPECT_TRUE(csp->AllowTrustedTypePolicy("somepolicy")); } +TEST_F(ContentSecurityPolicyTest, TrustedTypesReserved) { + csp->BindToExecutionContext(execution_context.Get()); + csp->DidReceiveHeader("trusted-types one \"two\" 'three'", + kContentSecurityPolicyHeaderTypeEnforce, + kContentSecurityPolicyHeaderSourceHTTP); + EXPECT_TRUE(csp->AllowTrustedTypePolicy("one")); + + // Quoted strings are considered 'reserved': + EXPECT_FALSE(csp->AllowTrustedTypePolicy("two")); + EXPECT_FALSE(csp->AllowTrustedTypePolicy("\"two\"")); + EXPECT_FALSE(csp->AllowTrustedTypePolicy("three")); + EXPECT_FALSE(csp->AllowTrustedTypePolicy("'three'")); +} + } // namespace blink
diff --git a/third_party/blink/renderer/core/frame/csp/string_list_directive.cc b/third_party/blink/renderer/core/frame/csp/string_list_directive.cc index 9a099273..448a0fa 100644 --- a/third_party/blink/renderer/core/frame/csp/string_list_directive.cc +++ b/third_party/blink/renderer/core/frame/csp/string_list_directive.cc
@@ -14,21 +14,38 @@ StringListDirective::StringListDirective(const String& name, const String& value, ContentSecurityPolicy* policy) - : CSPDirective(name, value, policy) { - // TODO(orsibatiz): After policy naming rules are estabilished, do a more - // complex parsing according to that. - value.Split(' ', false, list_); + : CSPDirective(name, value, policy), allow_any_(false) { + // Turn whitespace-y characters into ' ' and then split on ' ' into list_. + value.SimplifyWhiteSpace().Split(' ', false, list_); + + // A single entry "*" means all values are allowed. + if (list_.size() == 1 && list_.at(0) == "*") { + allow_any_ = true; + list_.clear(); + } + + // There appears to be no wtf::Vector equivalent to STLs erase(from, to) + // method, so we can't do the canonical .erase(remove_if(..), end) and have + // to emulate this: + list_.Shrink( + std::remove_if(list_.begin(), list_.end(), &IsInvalidStringValue) - + list_.begin()); +} + +// TODO(vogelheim): If StringListDirective will be used in contexts other than +// TrustedTypes, this needs to be made configurable or +// over-rideable. +bool StringListDirective::IsInvalidStringValue(const String& str) { + // TODO(vogelheim): Update this as the Trusted Type spec evolves. + + // Currently, Trusted Type demands that quoted strings are treated as + // placeholders (and thus cannot be policy names). We'll just disallow any + // string with quote marks in them. + return str.Contains('\'') || str.Contains('"'); } bool StringListDirective::Allows(const String& string_piece) { - if (list_.IsEmpty()) - return true; - for (String p : list_) { - if (p == string_piece) { - return true; - } - } - return false; + return allow_any_ || list_.Contains(string_piece); } void StringListDirective::Trace(blink::Visitor* visitor) {
diff --git a/third_party/blink/renderer/core/frame/csp/string_list_directive.h b/third_party/blink/renderer/core/frame/csp/string_list_directive.h index a12d12c..03715c8 100644 --- a/third_party/blink/renderer/core/frame/csp/string_list_directive.h +++ b/third_party/blink/renderer/core/frame/csp/string_list_directive.h
@@ -22,7 +22,11 @@ bool Allows(const String& string_piece); private: + // Determine whether a given string in the string list is valid. + static bool IsInvalidStringValue(const String& str); + Vector<String> list_; + bool allow_any_; }; } // namespace blink
diff --git a/third_party/blink/renderer/core/frame/frame.cc b/third_party/blink/renderer/core/frame/frame.cc index c24553a..71c6828 100644 --- a/third_party/blink/renderer/core/frame/frame.cc +++ b/third_party/blink/renderer/core/frame/frame.cc
@@ -72,6 +72,7 @@ visitor->Trace(window_proxy_manager_); visitor->Trace(dom_window_); visitor->Trace(client_); + visitor->Trace(navigation_rate_limiter_); } void Frame::Detach(FrameDetachType type) { @@ -252,6 +253,7 @@ owner_(owner), client_(client), window_proxy_manager_(window_proxy_manager), + navigation_rate_limiter_(*this), is_loading_(false), devtools_frame_token_(client->GetDevToolsFrameToken()), create_stack_(base::debug::StackTrace()) {
diff --git a/third_party/blink/renderer/core/frame/frame.h b/third_party/blink/renderer/core/frame/frame.h index 5845feb..bb94ac3 100644 --- a/third_party/blink/renderer/core/frame/frame.h +++ b/third_party/blink/renderer/core/frame/frame.h
@@ -40,6 +40,7 @@ #include "third_party/blink/renderer/core/dom/user_gesture_indicator.h" #include "third_party/blink/renderer/core/frame/frame_lifecycle.h" #include "third_party/blink/renderer/core/frame/frame_view.h" +#include "third_party/blink/renderer/core/frame/navigation_rate_limiter.h" #include "third_party/blink/renderer/core/loader/frame_loader_types.h" #include "third_party/blink/renderer/core/page/frame_tree.h" #include "third_party/blink/renderer/platform/graphics/touch_action.h" @@ -56,9 +57,9 @@ class FrameClient; class FrameOwner; class HTMLFrameOwnerElement; +class KURL; class LayoutEmbeddedContent; class LocalFrame; -class KURL; class Page; class SecurityContext; class Settings; @@ -231,6 +232,10 @@ return detach_stack_; } + NavigationRateLimiter& navigation_rate_limiter() { + return navigation_rate_limiter_; + } + protected: Frame(FrameClient*, Page&, FrameOwner*, WindowProxyManager*); @@ -267,6 +272,9 @@ Member<FrameClient> client_; const Member<WindowProxyManager> window_proxy_manager_; FrameLifecycle lifecycle_; + + NavigationRateLimiter navigation_rate_limiter_; + // TODO(sashab): Investigate if this can be represented with m_lifecycle. bool is_loading_; base::UnguessableToken devtools_frame_token_;
diff --git a/third_party/blink/renderer/core/frame/frame_test_helpers.cc b/third_party/blink/renderer/core/frame/frame_test_helpers.cc index 8ab6a37..4fc07575c 100644 --- a/third_party/blink/renderer/core/frame/frame_test_helpers.cc +++ b/third_party/blink/renderer/core/frame/frame_test_helpers.cc
@@ -447,7 +447,7 @@ return CreateLocalChild(*parent, scope); } -void TestWebFrameClient::DidStartLoading(bool) { +void TestWebFrameClient::DidStartLoading() { ++loads_in_progress_; }
diff --git a/third_party/blink/renderer/core/frame/frame_test_helpers.h b/third_party/blink/renderer/core/frame/frame_test_helpers.h index ceabae35..d0ad38a 100644 --- a/third_party/blink/renderer/core/frame/frame_test_helpers.h +++ b/third_party/blink/renderer/core/frame/frame_test_helpers.h
@@ -313,7 +313,7 @@ WebSandboxFlags, const ParsedFeaturePolicy&, const WebFrameOwnerProperties&) override; - void DidStartLoading(bool) override; + void DidStartLoading() override; void DidStopLoading() override; void DidCreateDocumentLoader(WebDocumentLoader*) override; service_manager::InterfaceProvider* GetInterfaceProvider() override {
diff --git a/third_party/blink/renderer/core/frame/history.cc b/third_party/blink/renderer/core/frame/history.cc index b1d17d8..a235dd3 100644 --- a/third_party/blink/renderer/core/frame/history.cc +++ b/third_party/blink/renderer/core/frame/history.cc
@@ -151,36 +151,6 @@ return history_item->ScrollRestorationType(); } -// TODO(crbug.com/394296): This is not the long-term fix to IPC flooding that we -// need. However, it does somewhat mitigate the immediate concern of |pushState| -// and |replaceState| DoS (assuming the renderer has not been compromised). -bool History::ShouldThrottleStateObjectChanges() { - if (!GetFrame()->GetSettings()->GetShouldThrottlePushState()) - return false; - - // The aim is to enable 8 'frames' (history updates) per second, but we - // express it as 80 frames per 10 seconds because some use cases (including - // tests) do more than 8 updates in 1 second. But over time, applications - // shooting for 8 FPS should work. If necessary to support legitimate - // applications, we can increase this threshold somewhat. - const int kStateUpdateLimit = 80; - - if (state_flood_guard.count > kStateUpdateLimit) { - static constexpr auto kStateUpdateLimitResetInterval = - TimeDelta::FromSeconds(10); - const auto now = CurrentTimeTicks(); - if (now - state_flood_guard.last_updated > kStateUpdateLimitResetInterval) { - state_flood_guard.count = 0; - state_flood_guard.last_updated = now; - return false; - } - return true; - } - - state_flood_guard.count++; - return false; -} - bool History::stateChanged() const { return last_state_object_requested_ != StateInternal(); } @@ -221,6 +191,9 @@ return; } + if (!GetFrame()->navigation_rate_limiter().CanProceed()) + return; + if (delta) { GetFrame()->Client()->NavigateBackForward(delta); } else { @@ -308,7 +281,7 @@ return; } - if (ShouldThrottleStateObjectChanges()) { + if (!GetFrame()->navigation_rate_limiter().CanProceed()) { // TODO(769592): Get an API spec change so that we can throw an exception: // // exception_state.ThrowDOMException(DOMExceptionCode::kQuotaExceededError, @@ -316,11 +289,6 @@ // "prevent the browser from hanging."); // // instead of merely warning. - - GetFrame()->Console().AddMessage( - ConsoleMessage::Create(kJSMessageSource, kWarningMessageLevel, - "Throttling history state changes to prevent " - "the browser from hanging.")); return; }
diff --git a/third_party/blink/renderer/core/frame/history.h b/third_party/blink/renderer/core/frame/history.h index 95e5a638..2ba91ea 100644 --- a/third_party/blink/renderer/core/frame/history.h +++ b/third_party/blink/renderer/core/frame/history.h
@@ -103,13 +103,7 @@ SerializedScriptValue* StateInternal() const; HistoryScrollRestorationType ScrollRestorationInternal() const; - bool ShouldThrottleStateObjectChanges(); - scoped_refptr<SerializedScriptValue> last_state_object_requested_; - struct { - int count; - TimeTicks last_updated; - } state_flood_guard; }; } // namespace blink
diff --git a/third_party/blink/renderer/core/frame/local_frame.cc b/third_party/blink/renderer/core/frame/local_frame.cc index 6e83b3a..8380db1 100644 --- a/third_party/blink/renderer/core/frame/local_frame.cc +++ b/third_party/blink/renderer/core/frame/local_frame.cc
@@ -274,12 +274,16 @@ const KURL& url, WebFrameLoadType frame_load_type, UserGestureStatus user_gesture_status) { + if (!navigation_rate_limiter().CanProceed()) + return; navigation_scheduler_->ScheduleFrameNavigation(&origin_document, url, frame_load_type); } void LocalFrame::Navigate(const FrameLoadRequest& request, WebFrameLoadType frame_load_type) { + if (!navigation_rate_limiter().CanProceed()) + return; loader_.StartNavigation(request, frame_load_type); }
diff --git a/third_party/blink/renderer/core/frame/local_frame_client.h b/third_party/blink/renderer/core/frame/local_frame_client.h index 25c49e0..fe2d45c 100644 --- a/third_party/blink/renderer/core/frame/local_frame_client.h +++ b/third_party/blink/renderer/core/frame/local_frame_client.h
@@ -165,7 +165,7 @@ virtual void DispatchWillSendSubmitEvent(HTMLFormElement*) = 0; virtual void DispatchWillSubmitForm(HTMLFormElement*) = 0; - virtual void DidStartLoading(LoadStartType) = 0; + virtual void DidStartLoading() = 0; virtual void ProgressEstimateChanged(double progress_estimate) = 0; virtual void DidStopLoading() = 0;
diff --git a/third_party/blink/renderer/core/frame/navigation_rate_limiter.cc b/third_party/blink/renderer/core/frame/navigation_rate_limiter.cc new file mode 100644 index 0000000..aa3e5628 --- /dev/null +++ b/third_party/blink/renderer/core/frame/navigation_rate_limiter.cc
@@ -0,0 +1,62 @@ +// Copyright (c) 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +#include "third_party/blink/renderer/core/frame/navigation_rate_limiter.h" +#include "third_party/blink/renderer/core/frame/frame.h" +#include "third_party/blink/renderer/core/frame/frame_console.h" +#include "third_party/blink/renderer/core/frame/local_frame.h" +#include "third_party/blink/renderer/core/frame/settings.h" +#include "third_party/blink/renderer/core/inspector/console_message.h" + +namespace blink { + +NavigationRateLimiter::NavigationRateLimiter(Frame& frame) + : frame_(frame), + time_first_count_(base::TimeTicks::Now()), + enabled(frame_->GetSettings()->GetShouldProtectAgainstIpcFlooding()) {} + +void NavigationRateLimiter::Trace(blink::Visitor* visitor) { + visitor->Trace(frame_); +} + +bool NavigationRateLimiter::CanProceed() { + if (!enabled) + return true; + + // The aim is to roughly enable 20 same-document navigation per second, but we + // express it as 200 per 10 seconds because some use cases (including tests) + // do more than 20 updates in 1 second. But over time, applications shooting + // for more should work. If necessary to support legitimate applications, we + // can increase this threshold somewhat. + static constexpr int kStateUpdateLimit = 200; + static constexpr base::TimeDelta kStateUpdateLimitResetInterval = + base::TimeDelta::FromSeconds(10); + + if (++count_ <= kStateUpdateLimit) + return true; + + const base::TimeTicks now = base::TimeTicks::Now(); + if (now - time_first_count_ > kStateUpdateLimitResetInterval) { + time_first_count_ = now; + count_ = 1; + error_message_sent_ = false; + return true; + } + + // Display an error message. Do it only once in a while, else it will flood + // the browser process with the FrameHostMsg_DidAddMessageToConsole IPC. + if (!error_message_sent_) { + error_message_sent_ = true; + if (frame_->IsLocalFrame()) { + ToLocalFrame(frame_)->Console().AddMessage(ConsoleMessage::Create( + kJSMessageSource, kWarningMessageLevel, + "Throttling navigation to prevent the browser from " + "hanging. See https://crbug.com/882238 and " + "chrome://flags/#disable-ipc-flooding-protection")); + } + } + + return false; +} + +} // namespace blink
diff --git a/third_party/blink/renderer/core/frame/navigation_rate_limiter.h b/third_party/blink/renderer/core/frame/navigation_rate_limiter.h new file mode 100644 index 0000000..0250fc2 --- /dev/null +++ b/third_party/blink/renderer/core/frame/navigation_rate_limiter.h
@@ -0,0 +1,42 @@ +// Copyright (c) 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_FRAME_NAVIGATION_RATE_LIMITER_H_ +#define THIRD_PARTY_BLINK_RENDERER_CORE_FRAME_NAVIGATION_RATE_LIMITER_H_ + +#include "base/time/time.h" +#include "third_party/blink/renderer/platform/heap/member.h" + +namespace blink { +class Visitor; +class Frame; + +// TODO(https://crbug.com/394296, https://crbug.com/882238) +// Prevent the renderer process to flood the browser process by sending IPC for +// same-document navigations. +// This is not the long-term fix to IPC flooding. However, it mitigate the +// immediate concern assuming the renderer has not been compromised. +class NavigationRateLimiter final { + DISALLOW_NEW(); + + public: + explicit NavigationRateLimiter(Frame&); + + // Notify this object a new navigation is requested. Return true if this one + // is allowed to proceed. + bool CanProceed(); + + void Trace(blink::Visitor*); + + private: + Member<Frame> frame_; + base::TimeTicks time_first_count_; + int count_ = 0; + bool enabled; + + bool error_message_sent_ = false; +}; + +} // namespace blink + +#endif // THIRD_PARTY_BLINK_RENDERER_CORE_FRAME_NAVIGATION_RATE_LIMITER_H_
diff --git a/third_party/blink/renderer/core/frame/remote_frame.cc b/third_party/blink/renderer/core/frame/remote_frame.cc index e1358d8..e8526b4 100644 --- a/third_party/blink/renderer/core/frame/remote_frame.cc +++ b/third_party/blink/renderer/core/frame/remote_frame.cc
@@ -71,6 +71,9 @@ void RemoteFrame::Navigate(const FrameLoadRequest& passed_request, WebFrameLoadType frame_load_type) { + if (!navigation_rate_limiter().CanProceed()) + return; + FrameLoadRequest frame_request(passed_request); // The process where this frame actually lives won't have sufficient
diff --git a/third_party/blink/renderer/core/frame/settings.json5 b/third_party/blink/renderer/core/frame/settings.json5 index db9341b93..d7d4d5c8 100644 --- a/third_party/blink/renderer/core/frame/settings.json5 +++ b/third_party/blink/renderer/core/frame/settings.json5
@@ -947,7 +947,7 @@ type: "WebEffectiveConnectionType", }, { - name: "shouldThrottlePushState", + name: "shouldProtectAgainstIpcFlooding", initial: true, },
diff --git a/third_party/blink/renderer/core/layout/layout_block.cc b/third_party/blink/renderer/core/layout/layout_block.cc index 4a912cc..c28144a6 100644 --- a/third_party/blink/renderer/core/layout/layout_block.cc +++ b/third_party/blink/renderer/core/layout/layout_block.cc
@@ -966,6 +966,12 @@ parent->MarkContainerNeedsCollectInlines(); } +bool LayoutBlock::IsAnonymousNGFieldsetContentWrapper() const { + if (!RuntimeEnabledFeatures::LayoutNGFieldsetEnabled() || !Parent()) + return false; + return Parent()->IsLayoutNGFieldset(); +} + void LayoutBlock::InvalidatePaint( const PaintInvalidatorContext& context) const { BlockPaintInvalidator(*this).InvalidatePaint(context); @@ -1130,6 +1136,12 @@ const HitTestLocation& location_in_container, const LayoutPoint& accumulated_offset, HitTestAction hit_test_action) { + // We may use legacy code to hit-test the anonymous fieldset content wrapper + // child. The layout object for the rendered legend will be a child of that + // one, and has to be skipped here, since its fragment is actually laid out on + // the outside and is a sibling of the anonymous wrapper. + bool may_contain_rendered_legend = IsAnonymousNGFieldsetContentWrapper(); + DCHECK(!ChildrenInline()); LayoutPoint scrolled_offset(HasOverflowClip() ? accumulated_offset - ScrolledContentOffset() @@ -1143,6 +1155,7 @@ FlipForWritingModeForChild(child, scrolled_offset); if (!child->HasSelfPaintingLayer() && !child->IsFloating() && !child->IsColumnSpanAll() && + (!may_contain_rendered_legend || !child->IsRenderedLegend()) && child->NodeAtPoint(result, location_in_container, child_point, child_hit_test)) { UpdateHitTestResult(
diff --git a/third_party/blink/renderer/core/layout/layout_block.h b/third_party/blink/renderer/core/layout/layout_block.h index 901f99c..2ffb4f3 100644 --- a/third_party/blink/renderer/core/layout/layout_block.h +++ b/third_party/blink/renderer/core/layout/layout_block.h
@@ -196,6 +196,12 @@ width_available_to_children_changed_ = true; } + // Return true if this is the anonymous child wrapper of an NG fieldset + // container. Such a wrapper holds all the fieldset contents. Only the + // rendered legend is laid out on the outside, although the layout object + // itself for the legend is still a child of this object. + bool IsAnonymousNGFieldsetContentWrapper() const; + void SetHasMarkupTruncation(bool b) { has_markup_truncation_ = b; } bool HasMarkupTruncation() const { return has_markup_truncation_; }
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 fa35bed..dc667e2 100644 --- a/third_party/blink/renderer/core/layout/layout_block_flow.cc +++ b/third_party/blink/renderer/core/layout/layout_block_flow.cc
@@ -4439,8 +4439,9 @@ bool LayoutBlockFlow::CreatesNewFormattingContext() const { if (IsInline() || IsFloatingOrOutOfFlowPositioned() || HasOverflowClip() || IsFlexItemIncludingDeprecated() || IsTableCell() || IsTableCaption() || - IsFieldset() || IsCustomItem() || IsDocumentElement() || IsGridItem() || - IsWritingModeRoot() || StyleRef().Display() == EDisplay::kFlowRoot || + IsFieldsetIncludingNG() || IsCustomItem() || IsDocumentElement() || + IsGridItem() || IsWritingModeRoot() || + StyleRef().Display() == EDisplay::kFlowRoot || ShouldApplyPaintContainment() || ShouldApplyLayoutContainment() || StyleRef().SpecifiesColumns() || StyleRef().GetColumnSpan() == EColumnSpan::kAll) {
diff --git a/third_party/blink/renderer/core/layout/layout_inline.cc b/third_party/blink/renderer/core/layout/layout_inline.cc index 310ab35..51c5266 100644 --- a/third_party/blink/renderer/core/layout/layout_inline.cc +++ b/third_party/blink/renderer/core/layout/layout_inline.cc
@@ -877,6 +877,12 @@ } LayoutPoint LayoutInline::FirstLineBoxTopLeft() const { + // This method is called from various places. It's mainly (only?) about + // calculating offsetLeft and offsetTop, though. Thus the callers seem to + // expect a purely physical point. This is what NG does. Legacy, on the other + // hand, sets the block-axis coordinate relatively to the block-start border + // edge, which means that offsetLeft will be wrong when writing-mode is + // vertical-rl. if (const NGPhysicalBoxFragment* box_fragment = EnclosingBlockFlowFragmentOf(*this)) { const auto& fragments =
diff --git a/third_party/blink/renderer/core/layout/layout_object.h b/third_party/blink/renderer/core/layout/layout_object.h index 469658b..8f4ad37 100644 --- a/third_party/blink/renderer/core/layout/layout_object.h +++ b/third_party/blink/renderer/core/layout/layout_object.h
@@ -556,6 +556,9 @@ } bool IsFieldset() const { return IsOfType(kLayoutObjectFieldset); } bool IsLayoutNGFieldset() const { return IsOfType(kLayoutObjectNGFieldset); } + bool IsFieldsetIncludingNG() const { + return IsFieldset() || IsLayoutNGFieldset(); + } bool IsFileUploadControl() const { return IsOfType(kLayoutObjectFileUploadControl); }
diff --git a/third_party/blink/renderer/core/layout/ng/geometry/ng_box_strut.cc b/third_party/blink/renderer/core/layout/ng/geometry/ng_box_strut.cc index f9b117d..c3291b8 100644 --- a/third_party/blink/renderer/core/layout/ng/geometry/ng_box_strut.cc +++ b/third_party/blink/renderer/core/layout/ng/geometry/ng_box_strut.cc
@@ -4,6 +4,7 @@ #include "third_party/blink/renderer/core/layout/ng/geometry/ng_box_strut.h" +#include "third_party/blink/renderer/platform/geometry/layout_rect_outsets.h" #include "third_party/blink/renderer/platform/wtf/text/wtf_string.h" namespace blink { @@ -79,6 +80,10 @@ IsFlippedLinesWritingMode(writing_mode)); } +LayoutRectOutsets NGPhysicalBoxStrut::ToLayoutRectOutsets() const { + return LayoutRectOutsets(top, right, bottom, left); +} + String NGBoxStrut::ToString() const { return String::Format("Inline: (%d %d) Block: (%d %d)", inline_start.ToInt(), inline_end.ToInt(), block_start.ToInt(),
diff --git a/third_party/blink/renderer/core/layout/ng/geometry/ng_box_strut.h b/third_party/blink/renderer/core/layout/ng/geometry/ng_box_strut.h index 1f15434c..5972759 100644 --- a/third_party/blink/renderer/core/layout/ng/geometry/ng_box_strut.h +++ b/third_party/blink/renderer/core/layout/ng/geometry/ng_box_strut.h
@@ -13,6 +13,7 @@ namespace blink { +class LayoutRectOutsets; struct NGLineBoxStrut; struct NGPhysicalBoxStrut; @@ -143,6 +144,8 @@ LayoutUnit HorizontalSum() const { return left + right; } LayoutUnit VerticalSum() const { return top + bottom; } + LayoutRectOutsets ToLayoutRectOutsets() const; + LayoutUnit top; LayoutUnit right; LayoutUnit bottom;
diff --git a/third_party/blink/renderer/core/layout/ng/inline/ng_inline_box_state.cc b/third_party/blink/renderer/core/layout/ng/inline/ng_inline_box_state.cc index f585f52..5025ded 100644 --- a/third_party/blink/renderer/core/layout/ng/inline/ng_inline_box_state.cc +++ b/third_party/blink/renderer/core/layout/ng/inline/ng_inline_box_state.cc
@@ -56,6 +56,11 @@ include_used_fonts = style.LineHeight().IsNegative(); } +void NGInlineBoxState::ResetTextMetrics() { + metrics = text_metrics = NGLineHeightMetrics(); + text_top = text_height = LayoutUnit(); +} + void NGInlineBoxState::EnsureTextMetrics(const ComputedStyle& style, FontBaseline baseline_type) { if (text_metrics.IsEmpty()) @@ -116,7 +121,7 @@ if (!line_height_quirk) box.metrics = box.text_metrics; else - box.metrics = box.text_metrics = NGLineHeightMetrics(); + box.ResetTextMetrics(); if (box.needs_box_fragment) { // Existing box states are wrapped before they were closed, and hence // they do not have start edges, unless 'box-decoration-break: clone'.
diff --git a/third_party/blink/renderer/core/layout/ng/inline/ng_inline_box_state.h b/third_party/blink/renderer/core/layout/ng/inline/ng_inline_box_state.h index ab97231..036bd79 100644 --- a/third_party/blink/renderer/core/layout/ng/inline/ng_inline_box_state.h +++ b/third_party/blink/renderer/core/layout/ng/inline/ng_inline_box_state.h
@@ -84,6 +84,7 @@ void ComputeTextMetrics(const ComputedStyle& style, FontBaseline baseline_type); void EnsureTextMetrics(const ComputedStyle&, FontBaseline); + void ResetTextMetrics(); void AccumulateUsedFonts(const ShapeResult*, FontBaseline);
diff --git a/third_party/blink/renderer/core/layout/ng/ng_block_node.cc b/third_party/blink/renderer/core/layout/ng/ng_block_node.cc index 99fef44..738e260 100644 --- a/third_party/blink/renderer/core/layout/ng/ng_block_node.cc +++ b/third_party/blink/renderer/core/layout/ng/ng_block_node.cc
@@ -293,11 +293,14 @@ block_flow->SetCachedLayoutResult(constraint_space, break_token, *layout_result); NGLayoutInputNode first_child = FirstChild(); - if (first_child && first_child.IsInline()) { - CopyFragmentDataToLayoutBoxForInlineChildren( - ToNGPhysicalBoxFragment(*layout_result->PhysicalFragment()), - layout_result->PhysicalFragment()->Size().width, - Style().IsFlippedBlocksWritingMode()); + bool has_inline_children = first_child && first_child.IsInline(); + if (has_inline_children || box_->IsLayoutNGFieldset()) { + if (has_inline_children) { + CopyFragmentDataToLayoutBoxForInlineChildren( + ToNGPhysicalBoxFragment(*layout_result->PhysicalFragment()), + layout_result->PhysicalFragment()->Size().width, + Style().IsFlippedBlocksWritingMode()); + } block_flow->SetPaintFragment(break_token, layout_result->PhysicalFragment(), @@ -598,22 +601,41 @@ const NGConstraintSpace& constraint_space, const NGPhysicalBoxFragment& physical_fragment, const NGPhysicalOffset& offset_from_start) { + LayoutBox* rendered_legend = nullptr; for (const auto& child_fragment : physical_fragment.Children()) { auto* child_object = child_fragment->GetLayoutObject(); // Skip any line-boxes we have as children, this is handled within // NGInlineNode at the moment. - if (!child_fragment->IsBox()) + if (!child_fragment->IsBox() && !child_fragment->IsRenderedLegend()) continue; const auto& box_fragment = *ToNGPhysicalBoxFragment(child_fragment.get()); if (IsFirstFragment(constraint_space, box_fragment)) { + if (box_fragment.IsRenderedLegend()) + rendered_legend = ToLayoutBox(box_fragment.GetLayoutObject()); CopyChildFragmentPosition(box_fragment, child_fragment.Offset(), offset_from_start); } if (child_object->IsLayoutBlockFlow()) ToLayoutBlockFlow(child_object)->AddOverflowFromFloats(); } + + if (rendered_legend) { + // The rendered legend is a child of the the anonymous fieldset content + // child wrapper object on the legacy side. LayoutNG, on the other hand, + // generates a fragment for the rendered legend as a direct child of the + // fieldset container fragment (as a *sibling* preceding the anonymous + // fieldset content wrapper). Now that we have positioned the anonymous + // wrapper, we're ready to compensate for this discrepancy. See + // LayoutNGFieldset for more details. + LayoutBlock* content_wrapper = rendered_legend->ContainingBlock(); + DCHECK(content_wrapper->IsAnonymous()); + DCHECK(IsHTMLFieldSetElement(content_wrapper->Parent()->GetNode())); + LayoutPoint location = rendered_legend->Location(); + location -= content_wrapper->Location(); + rendered_legend->SetLocation(location); + } } void NGBlockNode::PlaceChildrenInFlowThread(
diff --git a/third_party/blink/renderer/core/layout/ng/ng_fieldset_layout_algorithm.cc b/third_party/blink/renderer/core/layout/ng/ng_fieldset_layout_algorithm.cc index 99fa9756..6fe1904 100644 --- a/third_party/blink/renderer/core/layout/ng/ng_fieldset_layout_algorithm.cc +++ b/third_party/blink/renderer/core/layout/ng/ng_fieldset_layout_algorithm.cc
@@ -122,6 +122,7 @@ border_box_size.block_size = std::max(border_box_size.block_size, minimum_border_box_block_size); + container_builder_.SetIsFieldsetContainer(); container_builder_.SetInlineSize(border_box_size.inline_size); container_builder_.SetIntrinsicBlockSize(intrinsic_block_size); container_builder_.SetBlockSize(border_box_size.block_size);
diff --git a/third_party/blink/renderer/core/layout/ng/ng_fragment_builder.cc b/third_party/blink/renderer/core/layout/ng/ng_fragment_builder.cc index 2fffa3b..e91155e6 100644 --- a/third_party/blink/renderer/core/layout/ng/ng_fragment_builder.cc +++ b/third_party/blink/renderer/core/layout/ng/ng_fragment_builder.cc
@@ -33,6 +33,9 @@ return NGPhysicalFragment::NGBoxType::kAtomicInline; if (layout_object->IsInline()) return NGPhysicalFragment::NGBoxType::kInlineBox; + if (layout_object->IsLayoutBlock() && + ToLayoutBlock(layout_object)->CreatesNewFormattingContext()) + return NGPhysicalFragment::NGBoxType::kBlockFlowRoot; return NGPhysicalFragment::NGBoxType::kNormalBox; } @@ -94,6 +97,7 @@ const NGLogicalOffset& child_offset) { switch (child->Type()) { case NGPhysicalBoxFragment::kFragmentBox: + case NGPhysicalBoxFragment::kFragmentRenderedLegend: if (child->BreakToken()) child_break_tokens_.push_back(child->BreakToken()); break; @@ -294,7 +298,9 @@ } scoped_refptr<NGBreakToken> break_token; + bool is_rendered_legend = false; if (node_) { + is_rendered_legend = node_.IsRenderedLegend(); if (!inline_break_tokens_.IsEmpty()) { if (auto token = inline_break_tokens_.back()) { if (!token->IsFinished()) @@ -319,7 +325,8 @@ layout_object_, Style(), style_variant_, physical_size, children_, borders_.ConvertToPhysical(GetWritingMode(), Direction()), padding_.ConvertToPhysical(GetWritingMode(), Direction()), - contents_ink_overflow, baselines_, BoxType(), is_old_layout_root_, + contents_ink_overflow, baselines_, BoxType(), is_fieldset_container_, + is_rendered_legend, is_old_layout_root_, border_edges_.ToPhysical(GetWritingMode()), std::move(break_token))); Vector<NGPositionedFloat> positioned_floats;
diff --git a/third_party/blink/renderer/core/layout/ng/ng_fragment_builder.h b/third_party/blink/renderer/core/layout/ng/ng_fragment_builder.h index 2378902..a8940d7 100644 --- a/third_party/blink/renderer/core/layout/ng/ng_fragment_builder.h +++ b/third_party/blink/renderer/core/layout/ng/ng_fragment_builder.h
@@ -134,6 +134,10 @@ NGPhysicalFragment::NGBoxType BoxType() const; NGFragmentBuilder& SetBoxType(NGPhysicalFragment::NGBoxType); + NGFragmentBuilder& SetIsFieldsetContainer() { + is_fieldset_container_ = true; + return *this; + } NGFragmentBuilder& SetIsOldLayoutRoot(); bool DidBreak() const { return did_break_; } @@ -191,6 +195,7 @@ NGBoxStrut padding_; NGPhysicalFragment::NGBoxType box_type_; + bool is_fieldset_container_ = false; bool is_old_layout_root_; bool did_break_; bool has_forced_break_ = false;
diff --git a/third_party/blink/renderer/core/layout/ng/ng_layout_input_node.cc b/third_party/blink/renderer/core/layout/ng/ng_layout_input_node.cc index 08c9990..58d4250 100644 --- a/third_party/blink/renderer/core/layout/ng/ng_layout_input_node.cc +++ b/third_party/blink/renderer/core/layout/ng/ng_layout_input_node.cc
@@ -111,6 +111,10 @@ return IsBlock() && box_->IsLayoutNGFieldset(); } +bool NGLayoutInputNode::IsRenderedLegend() const { + return IsBlock() && box_->IsRenderedLegend(); +} + bool NGLayoutInputNode::IsAnonymousBlock() const { return box_->IsAnonymousBlock(); }
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 55d1494..a6389c5 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
@@ -74,6 +74,11 @@ bool ListMarkerOccupiesWholeLine() const; bool IsTableCell() const; bool IsFieldsetContainer() const; + + // Return true if this is the legend child of a fieldset that gets special + // treatment (i.e. placed over the block-start border). + bool IsRenderedLegend() const; + bool IsAnonymousBlock() const; // If the node is a quirky container for margin collapsing, see:
diff --git a/third_party/blink/renderer/core/layout/ng/ng_layout_result.h b/third_party/blink/renderer/core/layout/ng/ng_layout_result.h index c62d89d2..cbf54b08 100644 --- a/third_party/blink/renderer/core/layout/ng/ng_layout_result.h +++ b/third_party/blink/renderer/core/layout/ng/ng_layout_result.h
@@ -77,7 +77,9 @@ const NGMarginStrut EndMarginStrut() const { return end_margin_strut_; } const LayoutUnit IntrinsicBlockSize() const { - DCHECK(root_fragment_->Type() == NGPhysicalFragment::kFragmentBox); + DCHECK(root_fragment_->Type() == NGPhysicalFragment::kFragmentBox || + root_fragment_->Type() == + NGPhysicalFragment::kFragmentRenderedLegend); return intrinsic_block_size_; }
diff --git a/third_party/blink/renderer/core/layout/ng/ng_physical_box_fragment.cc b/third_party/blink/renderer/core/layout/ng/ng_physical_box_fragment.cc index 2bbbf7a..03ebd11 100644 --- a/third_party/blink/renderer/core/layout/ng/ng_physical_box_fragment.cc +++ b/third_party/blink/renderer/core/layout/ng/ng_physical_box_fragment.cc
@@ -27,22 +27,26 @@ const NGPhysicalOffsetRect& contents_ink_overflow, Vector<NGBaseline>& baselines, NGBoxType box_type, + bool is_fieldset_container, + bool is_rendered_legend, bool is_old_layout_root, unsigned border_edges, // NGBorderEdges::Physical scoped_refptr<NGBreakToken> break_token) - : NGPhysicalContainerFragment(layout_object, - style, - style_variant, - size, - kFragmentBox, - box_type, - children, - contents_ink_overflow, - std::move(break_token)), + : NGPhysicalContainerFragment( + layout_object, + style, + style_variant, + size, + is_rendered_legend ? kFragmentRenderedLegend : kFragmentBox, + box_type, + children, + contents_ink_overflow, + std::move(break_token)), baselines_(std::move(baselines)), borders_(borders), padding_(padding) { DCHECK(baselines.IsEmpty()); // Ensure move semantics is used. + is_fieldset_container_ = is_fieldset_container; is_old_layout_root_ = is_old_layout_root; border_edge_ = border_edges; children_inline_ = layout_object && layout_object->ChildrenInline();
diff --git a/third_party/blink/renderer/core/layout/ng/ng_physical_box_fragment.h b/third_party/blink/renderer/core/layout/ng/ng_physical_box_fragment.h index dc530ca5..3d9608c5c 100644 --- a/third_party/blink/renderer/core/layout/ng/ng_physical_box_fragment.h +++ b/third_party/blink/renderer/core/layout/ng/ng_physical_box_fragment.h
@@ -28,6 +28,8 @@ const NGPhysicalOffsetRect& contents_ink_overflow, Vector<NGBaseline>& baselines, NGBoxType box_type, + bool is_fieldset_container, + bool is_rendered_legend, bool is_old_layout_root, unsigned, // NGBorderEdges::Physical scoped_refptr<NGBreakToken> break_token = nullptr); @@ -86,11 +88,14 @@ NGPhysicalOffsetRect descendant_outlines_; }; -DEFINE_TYPE_CASTS(NGPhysicalBoxFragment, - NGPhysicalFragment, - fragment, - fragment->Type() == NGPhysicalFragment::kFragmentBox, - fragment.Type() == NGPhysicalFragment::kFragmentBox); +DEFINE_TYPE_CASTS( + NGPhysicalBoxFragment, + NGPhysicalFragment, + fragment, + (fragment->Type() == NGPhysicalFragment::kFragmentBox || + fragment->Type() == NGPhysicalFragment::kFragmentRenderedLegend), + (fragment.Type() == NGPhysicalFragment::kFragmentBox || + fragment.Type() == NGPhysicalFragment::kFragmentRenderedLegend)); } // namespace blink
diff --git a/third_party/blink/renderer/core/layout/ng/ng_physical_fragment.cc b/third_party/blink/renderer/core/layout/ng/ng_physical_fragment.cc index ca6df77..8e9f157 100644 --- a/third_party/blink/renderer/core/layout/ng/ng_physical_fragment.cc +++ b/third_party/blink/renderer/core/layout/ng/ng_physical_fragment.cc
@@ -85,6 +85,9 @@ case NGPhysicalFragment::NGBoxType::kOutOfFlowPositioned: result.Append("out-of-flow-positioned"); break; + case NGPhysicalFragment::NGBoxType::kBlockFlowRoot: + result.Append("block-flow-root"); + break; } if (fragment.IsOldLayoutRoot()) { if (result.length()) @@ -96,6 +99,16 @@ result.Append(" "); result.Append("block-flow"); } + if (fragment.IsRenderedLegend()) { + if (result.length()) + result.Append(" "); + result.Append("rendered-legend"); + } + if (fragment.IsFieldsetContainer()) { + if (result.length()) + result.Append(" "); + result.Append("fieldset-container"); + } if (fragment.IsBox() && static_cast<const NGPhysicalBoxFragment&>(fragment).ChildrenInline()) { if (result.length()) @@ -117,10 +130,13 @@ } bool has_content = false; - if (fragment->IsBox()) { + if (fragment->IsBox() || fragment->IsRenderedLegend()) { const auto* box = ToNGPhysicalBoxFragment(fragment); if (flags & NGPhysicalFragment::DumpType) { - builder->Append("Box"); + if (fragment->IsRenderedLegend()) + builder->Append("RenderedLegend"); + else + builder->Append("Box"); String box_type = StringForBoxType(*fragment); has_content = true; if (!box_type.IsEmpty()) { @@ -231,6 +247,7 @@ break_token_(std::move(break_token)), type_(type), sub_type_(sub_type), + is_fieldset_container_(false), is_old_layout_root_(false), style_variant_((unsigned)style_variant) {} @@ -241,6 +258,7 @@ void NGPhysicalFragment::Destroy() const { switch (Type()) { case kFragmentBox: + case kFragmentRenderedLegend: delete static_cast<const NGPhysicalBoxFragment*>(this); break; case kFragmentText: @@ -321,11 +339,12 @@ NGPhysicalOffsetRect NGPhysicalFragment::SelfInkOverflow() const { switch (Type()) { - case NGPhysicalFragment::kFragmentBox: + case kFragmentBox: + case kFragmentRenderedLegend: return ToNGPhysicalBoxFragment(*this).SelfInkOverflow(); - case NGPhysicalFragment::kFragmentText: + case kFragmentText: return ToNGPhysicalTextFragment(*this).SelfInkOverflow(); - case NGPhysicalFragment::kFragmentLineBox: + case kFragmentLineBox: return {{}, Size()}; } NOTREACHED(); @@ -334,11 +353,12 @@ NGPhysicalOffsetRect NGPhysicalFragment::InkOverflow(bool apply_clip) const { switch (Type()) { - case NGPhysicalFragment::kFragmentBox: + case kFragmentBox: + case kFragmentRenderedLegend: return ToNGPhysicalBoxFragment(*this).InkOverflow(apply_clip); - case NGPhysicalFragment::kFragmentText: + case kFragmentText: return ToNGPhysicalTextFragment(*this).SelfInkOverflow(); - case NGPhysicalFragment::kFragmentLineBox: + case kFragmentLineBox: return ToNGPhysicalLineBoxFragment(*this).InkOverflow(); } NOTREACHED(); @@ -347,11 +367,12 @@ NGPhysicalOffsetRect NGPhysicalFragment::ScrollableOverflow() const { switch (Type()) { - case NGPhysicalFragment::kFragmentBox: + case kFragmentBox: + case kFragmentRenderedLegend: return ToNGPhysicalBoxFragment(*this).ScrollableOverflow(); - case NGPhysicalFragment::kFragmentText: + case kFragmentText: return {{}, Size()}; - case NGPhysicalFragment::kFragmentLineBox: + case kFragmentLineBox: NOTREACHED() << "You must call NGLineBoxFragment::ScrollableOverflow explicitly."; break; @@ -418,6 +439,7 @@ Size().ToString().Ascii().data())); switch (Type()) { case kFragmentBox: + case kFragmentRenderedLegend: output.Append(String::Format(", BoxType: '%s'", StringForBoxType(*this).Ascii().data())); break;
diff --git a/third_party/blink/renderer/core/layout/ng/ng_physical_fragment.h b/third_party/blink/renderer/core/layout/ng/ng_physical_fragment.h index cf5af893..a4e54763 100644 --- a/third_party/blink/renderer/core/layout/ng/ng_physical_fragment.h +++ b/third_party/blink/renderer/core/layout/ng/ng_physical_fragment.h
@@ -51,7 +51,8 @@ enum NGFragmentType { kFragmentBox = 0, kFragmentText = 1, - kFragmentLineBox = 2 + kFragmentLineBox = 2, + kFragmentRenderedLegend = 3, // When adding new values, make sure the bit size of |type_| is large // enough to store. }; @@ -64,6 +65,7 @@ kAtomicInline, kFloating, kOutOfFlowPositioned, + kBlockFlowRoot, // When adding new values, make sure the bit size of |sub_type_| is large // enough to store. @@ -78,12 +80,19 @@ NGFragmentType Type() const { return static_cast<NGFragmentType>(type_); } bool IsContainer() const { return Type() == NGFragmentType::kFragmentBox || - Type() == NGFragmentType::kFragmentLineBox; + Type() == NGFragmentType::kFragmentLineBox || + Type() == NGFragmentType::kFragmentRenderedLegend; } bool IsBox() const { return Type() == NGFragmentType::kFragmentBox; } bool IsText() const { return Type() == NGFragmentType::kFragmentText; } bool IsLineBox() const { return Type() == NGFragmentType::kFragmentLineBox; } + // Return true if this is the legend child of a fieldset that gets special + // treatment (i.e. placed over the block-start border). + bool IsRenderedLegend() const { + return Type() == NGFragmentType::kFragmentRenderedLegend; + } + // Returns the box type of this fragment. NGBoxType BoxType() const { DCHECK(IsBox()); @@ -115,6 +124,12 @@ bool IsBlockFlow() const; bool IsListMarker() const; + // Return true if this fragment is a container established by a fieldset + // element. Such a fragment contains an optional rendered legend fragment and + // an optional fieldset contents wrapper fragment (which holds everything + // inside the fieldset except the rendered legend). + bool IsFieldsetContainer() const { return is_fieldset_container_; } + // Returns whether the fragment is old layout root. bool IsOldLayoutRoot() const { return is_old_layout_root_; } @@ -232,6 +247,7 @@ const unsigned type_ : 2; // NGFragmentType const unsigned sub_type_ : 3; // Union of NGBoxType and NGTextType + unsigned is_fieldset_container_ : 1; unsigned is_old_layout_root_ : 1; unsigned border_edge_ : 4; // NGBorderEdges::Physical const unsigned style_variant_ : 2; // NGStyleVariant
diff --git a/third_party/blink/renderer/core/loader/allowed_by_nosniff.cc b/third_party/blink/renderer/core/loader/allowed_by_nosniff.cc index 6728251..c3bc435 100644 --- a/third_party/blink/renderer/core/loader/allowed_by_nosniff.cc +++ b/third_party/blink/renderer/core/loader/allowed_by_nosniff.cc
@@ -126,8 +126,11 @@ bool MimeTypeAsScriptImpl(ExecutionContext* execution_context, const ResourceResponse& response, bool is_worker_global_scope) { - // Is it a file:-URL? If so, decide based on file suffix. - if (response.Url().IsLocalFile() && + // The content type is really only meaningful for the http:-family & data + // schemes. + bool is_http_family_or_data = response.Url().ProtocolIsInHTTPFamily() || + response.Url().ProtocolIsData(); + if (!is_http_family_or_data && response.Url().LastPathComponent().EndsWith(".js")) { return true; }
diff --git a/third_party/blink/renderer/core/loader/allowed_by_nosniff_test.cc b/third_party/blink/renderer/core/loader/allowed_by_nosniff_test.cc index 9cf9722..28421ee6 100644 --- a/third_party/blink/renderer/core/loader/allowed_by_nosniff_test.cc +++ b/third_party/blink/renderer/core/loader/allowed_by_nosniff_test.cc
@@ -189,4 +189,36 @@ } } +TEST_F(AllowedByNosniffTest, AllTheSchemes) { + // We test various URL schemes. + // To force a decision based on the scheme, we give all responses an + // invalid Content-Type plus a "nosniff" header. That way, all Content-Type + // based checks are always denied and we can test for whether this is decided + // based on the URL or not. + struct { + const char* url; + bool allowed; + } data[] = { + {"http://example.com/bla.js", false}, + {"https://example.com/bla.js", false}, + {"file://etc/passwd.js", true}, + {"file://etc/passwd", false}, + {"chrome://dino/dino.js", true}, + {"chrome://dino/dino.css", false}, + {"ftp://example.com/bla.js", true}, + {"ftp://example.com/bla.txt", false}, + }; + + for (auto& testcase : data) { + SetUp(); + SCOPED_TRACE(testing::Message() << "\n url: " << testcase.url + << "\n allowed: " << testcase.allowed); + ResourceResponse response(KURL(testcase.url)); + response.SetHTTPHeaderField("Content-Type", "invalid"); + response.SetHTTPHeaderField("X-Content-Type-Options", "nosniff"); + EXPECT_EQ(testcase.allowed, + AllowedByNosniff::MimeTypeAsScript(doc(), response)); + } +} + } // namespace blink
diff --git a/third_party/blink/renderer/core/loader/empty_clients.h b/third_party/blink/renderer/core/loader/empty_clients.h index 43b4e3a..bab778108 100644 --- a/third_party/blink/renderer/core/loader/empty_clients.h +++ b/third_party/blink/renderer/core/loader/empty_clients.h
@@ -283,7 +283,7 @@ void DispatchWillSendSubmitEvent(HTMLFormElement*) override; void DispatchWillSubmitForm(HTMLFormElement*) override; - void DidStartLoading(LoadStartType) override {} + void DidStartLoading() override {} void ProgressEstimateChanged(double) override {} void DidStopLoading() override {}
diff --git a/third_party/blink/renderer/core/loader/frame_loader.cc b/third_party/blink/renderer/core/loader/frame_loader.cc index be8969d..96600c4 100644 --- a/third_party/blink/renderer/core/loader/frame_loader.cc +++ b/third_party/blink/renderer/core/loader/frame_loader.cc
@@ -507,7 +507,7 @@ // from the document, since a new document is already loading. bool was_loading = frame_->IsLoading(); if (!was_loading) - Client()->DidStartLoading(kNavigationWithinSameDocument); + Client()->DidStartLoading(); // Update the data source's request with the new URL to fake the URL change frame_->GetDocument()->SetURL(new_url);
diff --git a/third_party/blink/renderer/core/loader/progress_tracker.cc b/third_party/blink/renderer/core/loader/progress_tracker.cc index 7d5ba73..1b3ea59 100644 --- a/third_party/blink/renderer/core/loader/progress_tracker.cc +++ b/third_party/blink/renderer/core/loader/progress_tracker.cc
@@ -110,7 +110,7 @@ Reset(); progress_value_ = kInitialProgressValue; if (!frame_->IsLoading()) { - GetLocalFrameClient()->DidStartLoading(kNavigationToDifferentDocument); + GetLocalFrameClient()->DidStartLoading(); frame_->SetIsLoading(true); probe::frameStartedLoading(frame_); }
diff --git a/third_party/blink/renderer/core/paint/BUILD.gn b/third_party/blink/renderer/core/paint/BUILD.gn index dd8354b..92db246f 100644 --- a/third_party/blink/renderer/core/paint/BUILD.gn +++ b/third_party/blink/renderer/core/paint/BUILD.gn
@@ -122,6 +122,8 @@ "ng/ng_block_flow_painter.h", "ng/ng_box_fragment_painter.cc", "ng/ng_box_fragment_painter.h", + "ng/ng_fieldset_painter.cc", + "ng/ng_fieldset_painter.h", "ng/ng_fragment_painter.cc", "ng/ng_fragment_painter.h", "ng/ng_inline_box_fragment_painter.cc",
diff --git a/third_party/blink/renderer/core/paint/block_painter.cc b/third_party/blink/renderer/core/paint/block_painter.cc index 438f1b4..5b9ca9f 100644 --- a/third_party/blink/renderer/core/paint/block_painter.cc +++ b/third_party/blink/renderer/core/paint/block_painter.cc
@@ -101,9 +101,19 @@ } void BlockPainter::PaintChildren(const PaintInfo& paint_info) { + // We may use legacy paint to paint the anonymous fieldset child. The layout + // object for the rendered legend will be a child of that one, and has to be + // skipped here, since it's handled by a special NG fieldset painter. + bool may_contain_rendered_legend = + layout_block_.IsAnonymousNGFieldsetContentWrapper(); for (LayoutBox* child = layout_block_.FirstChildBox(); child; - child = child->NextSiblingBox()) + child = child->NextSiblingBox()) { + if (may_contain_rendered_legend && child->IsRenderedLegend()) { + may_contain_rendered_legend = false; + continue; + } PaintChild(*child, paint_info); + } } void BlockPainter::PaintChild(const LayoutBox& child,
diff --git a/third_party/blink/renderer/core/paint/ng/ng_box_fragment_painter.cc b/third_party/blink/renderer/core/paint/ng/ng_box_fragment_painter.cc index b4332d1..23ee4bd 100644 --- a/third_party/blink/renderer/core/paint/ng/ng_box_fragment_painter.cc +++ b/third_party/blink/renderer/core/paint/ng/ng_box_fragment_painter.cc
@@ -25,6 +25,7 @@ #include "third_party/blink/renderer/core/paint/box_decoration_data.h" #include "third_party/blink/renderer/core/paint/compositing/composited_layer_mapping.h" #include "third_party/blink/renderer/core/paint/list_marker_painter.h" +#include "third_party/blink/renderer/core/paint/ng/ng_fieldset_painter.h" #include "third_party/blink/renderer/core/paint/ng/ng_fragment_painter.h" #include "third_party/blink/renderer/core/paint/ng/ng_inline_box_fragment_painter.h" #include "third_party/blink/renderer/core/paint/ng/ng_paint_fragment.h" @@ -140,7 +141,8 @@ border_edges_( NGBorderEdges::FromPhysical(box.PhysicalFragment().BorderEdges(), box.Style().GetWritingMode())) { - DCHECK(box.PhysicalFragment().IsBox()); + DCHECK(box.PhysicalFragment().IsBox() || + box.PhysicalFragment().IsRenderedLegend()); } void NGBoxFragmentPainter::Paint(const PaintInfo& paint_info) { @@ -230,8 +232,7 @@ // to check the object as some objects may have box decoration background // other than from their own style. // TODO(eae): We can probably get rid of suppress_box_decoration_background. - if (!suppress_box_decoration_background && is_visible && - style.HasBoxDecorationBackground()) + if (!suppress_box_decoration_background && is_visible) PaintBoxDecorationBackground(paint_info, paint_offset); if (RuntimeEnabledFeatures::PaintTouchActionRectsEnabled()) @@ -363,7 +364,8 @@ else NGBoxFragmentPainter(*child).Paint(paint_info); } else { - NOTREACHED() << fragment.ToString(); + DCHECK(fragment.Type() == NGPhysicalFragment::kFragmentRenderedLegend) + << fragment.ToString(); } } } @@ -430,6 +432,19 @@ void NGBoxFragmentPainter::PaintBoxDecorationBackground( const PaintInfo& paint_info, const LayoutPoint& paint_offset) { + if (box_fragment_.PhysicalFragment().IsFieldsetContainer()) { + NGFieldsetPainter(box_fragment_) + .PaintBoxDecorationBackground(paint_info, paint_offset); + return; + } + + // Note that for fieldsets we need to enter decoration and background painting + // even if we have no such things, because the rendered legend is painted in + // this phase as well. Hence the early check above. + const ComputedStyle& style = box_fragment_.Style(); + if (!style.HasBoxDecorationBackground()) + return; + // TODO(mstensho): Break dependency on LayoutObject functionality. const LayoutObject& layout_object = *box_fragment_.GetLayoutObject();
diff --git a/third_party/blink/renderer/core/paint/ng/ng_fieldset_painter.cc b/third_party/blink/renderer/core/paint/ng/ng_fieldset_painter.cc new file mode 100644 index 0000000..edcc67c4 --- /dev/null +++ b/third_party/blink/renderer/core/paint/ng/ng_fieldset_painter.cc
@@ -0,0 +1,112 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "third_party/blink/renderer/core/paint/ng/ng_fieldset_painter.h" + +#include "third_party/blink/renderer/core/layout/layout_box.h" +#include "third_party/blink/renderer/core/layout/ng/ng_physical_box_fragment.h" +#include "third_party/blink/renderer/core/paint/background_image_geometry.h" +#include "third_party/blink/renderer/core/paint/box_decoration_data.h" +#include "third_party/blink/renderer/core/paint/fieldset_paint_info.h" +#include "third_party/blink/renderer/core/paint/ng/ng_box_fragment_painter.h" +#include "third_party/blink/renderer/core/paint/ng/ng_paint_fragment.h" +#include "third_party/blink/renderer/core/paint/object_painter.h" +#include "third_party/blink/renderer/core/paint/paint_info.h" +#include "third_party/blink/renderer/platform/geometry/layout_rect_outsets.h" +#include "third_party/blink/renderer/platform/graphics/graphics_context_state_saver.h" +#include "third_party/blink/renderer/platform/graphics/paint/drawing_recorder.h" + +namespace blink { + +void NGFieldsetPainter::PaintBoxDecorationBackground( + const PaintInfo& paint_info, + const LayoutPoint paint_offset) { + const NGPaintFragment* legend = nullptr; + if (fieldset_.Children().size()) { + const auto first_child = fieldset_.Children()[0]; + if (first_child->PhysicalFragment().IsRenderedLegend()) + legend = &(*first_child); + } + + // Paint the fieldset (background, other decorations, and) border, with the + // cutout hole for the legend. + PaintFieldsetDecorationBackground(legend, paint_info, paint_offset); + + // Proceed to painting the legend. According to the spec, it should be done as + // part of the border phase. + if (legend) + PaintLegend(*legend, paint_info); +} + +void NGFieldsetPainter::PaintFieldsetDecorationBackground( + const NGPaintFragment* legend, + const PaintInfo& paint_info, + const LayoutPoint paint_offset) { + LayoutSize fieldset_size(fieldset_.Size().ToLayoutSize()); + LayoutRect paint_rect(paint_offset, fieldset_size); + + if (DrawingRecorder::UseCachedDrawingIfPossible(paint_info.context, fieldset_, + paint_info.phase)) + return; + + const NGPhysicalBoxFragment& fragment = + ToNGPhysicalBoxFragment(fieldset_.PhysicalFragment()); + LayoutRectOutsets fieldset_borders = fragment.Borders().ToLayoutRectOutsets(); + const ComputedStyle& style = fieldset_.Style(); + LayoutRect legend_border_box; + if (legend) { + legend_border_box.SetLocation(legend->Offset().ToLayoutPoint()); + legend_border_box.SetSize(legend->Size().ToLayoutSize()); + } + FieldsetPaintInfo fieldset_paint_info(style, fieldset_size, fieldset_borders, + legend_border_box); + LayoutRect contracted_rect(paint_rect); + contracted_rect.Contract(fieldset_paint_info.border_outsets); + + DrawingRecorder recorder(paint_info.context, fieldset_, paint_info.phase); + BoxDecorationData box_decoration_data(fragment); + + NGBoxFragmentPainter fragment_painter(fieldset_); + fragment_painter.PaintNormalBoxShadow(paint_info, contracted_rect, style); + + // TODO(eae): Switch to LayoutNG version of BackgroundImageGeometry. + BackgroundImageGeometry geometry( + *static_cast<const LayoutBoxModelObject*>(fieldset_.GetLayoutObject())); + + fragment_painter.PaintFillLayers( + paint_info, box_decoration_data.background_color, + style.BackgroundLayers(), contracted_rect, geometry); + fragment_painter.PaintInsetBoxShadowWithBorderRect( + paint_info, contracted_rect, fieldset_.Style()); + + if (!box_decoration_data.has_border_decoration) + return; + + // Create a clipping region around the legend and paint the border as normal. + GraphicsContext& graphics_context = paint_info.context; + GraphicsContextStateSaver state_saver(graphics_context); + + LayoutRect legend_cutout_rect = fieldset_paint_info.legend_cutout_rect; + legend_cutout_rect.MoveBy(paint_rect.Location()); + graphics_context.ClipOut(PixelSnappedIntRect(legend_cutout_rect)); + + LayoutObject* layout_object = fieldset_.GetLayoutObject(); + Node* node = layout_object->GeneratingNode(); + fragment_painter.PaintBorder(fieldset_, layout_object->GetDocument(), node, + paint_info, contracted_rect, fieldset_.Style()); +} + +void NGFieldsetPainter::PaintLegend(const NGPaintFragment& legend, + const PaintInfo& paint_info) { + // Unless the legend establishes its own self-painting layer, paint the legend + // as part of the border phase, according to spec. + LayoutObject* legend_object = legend.GetLayoutObject(); + if (ToLayoutBox(legend_object)->HasSelfPaintingLayer()) + return; + PaintInfo legend_paint_info = paint_info; + legend_paint_info.phase = PaintPhase::kForeground; + ObjectPainter(*legend_object).PaintAllPhasesAtomically(legend_paint_info); +} + +} // namespace blink
diff --git a/third_party/blink/renderer/core/paint/ng/ng_fieldset_painter.h b/third_party/blink/renderer/core/paint/ng/ng_fieldset_painter.h new file mode 100644 index 0000000..09540ac --- /dev/null +++ b/third_party/blink/renderer/core/paint/ng/ng_fieldset_painter.h
@@ -0,0 +1,35 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_PAINT_NG_NG_FIELDSET_PAINTER_H_ +#define THIRD_PARTY_BLINK_RENDERER_CORE_PAINT_NG_NG_FIELDSET_PAINTER_H_ + +#include "third_party/blink/renderer/platform/geometry/layout_point.h" +#include "third_party/blink/renderer/platform/wtf/allocator.h" + +namespace blink { + +class NGPaintFragment; +struct PaintInfo; + +class NGFieldsetPainter { + STACK_ALLOCATED(); + + public: + NGFieldsetPainter(const NGPaintFragment& fieldset) : fieldset_(fieldset) {} + + void PaintBoxDecorationBackground(const PaintInfo&, const LayoutPoint); + + private: + void PaintFieldsetDecorationBackground(const NGPaintFragment* legend, + const PaintInfo&, + const LayoutPoint); + void PaintLegend(const NGPaintFragment& legend, const PaintInfo&); + + const NGPaintFragment& fieldset_; +}; + +} // namespace blink + +#endif // THIRD_PARTY_BLINK_RENDERER_CORE_PAINT_NG_NG_FIELDSET_PAINTER_H_
diff --git a/third_party/blink/renderer/core/svg/svg_use_element.cc b/third_party/blink/renderer/core/svg/svg_use_element.cc index c160e46..8d2a842 100644 --- a/third_party/blink/renderer/core/svg/svg_use_element.cc +++ b/third_party/blink/renderer/core/svg/svg_use_element.cc
@@ -439,7 +439,7 @@ DCHECK(!InUseShadowTree()); // Do not allow self-referencing. - if (&target == this || IsDisallowedElement(target)) + if (IsDisallowedElement(target) || HasCycleUseReferencing(*this, target)) return; // Set up root SVG element in shadow tree. @@ -464,11 +464,7 @@ // Expand all <use> elements in the shadow tree. // Expand means: replace the actual <use> element by what it references. - if (!ExpandUseElementsInShadowTree()) { - shadow_root.RemoveChildren(kOmitSubtreeModifiedEvent); - ClearResourceReference(); - return; - } + ExpandUseElementsInShadowTree(); // If the instance root was a <use>, it could have been replaced now, so // reset |m_targetElementInstance|. @@ -565,14 +561,13 @@ return true; AtomicString target_id = target.GetIdAttribute(); - ContainerNode* instance = target_instance.parentNode(); + ContainerNode* instance = target_instance.ParentOrShadowHostElement(); while (instance && instance->IsSVGElement()) { SVGElement* element = ToSVGElement(instance); if (element->HasID() && element->GetIdAttribute() == target_id && element->GetDocument() == target.GetDocument()) return true; - - instance = instance->parentNode(); + instance = instance->ParentOrShadowHostElement(); } return false; } @@ -590,7 +585,7 @@ replacement_element.removeAttribute(XLinkNames::hrefAttr); } -bool SVGUseElement::ExpandUseElementsInShadowTree() { +void SVGUseElement::ExpandUseElementsInShadowTree() { // Why expand the <use> elements in the shadow tree here, and not just // do this directly in buildShadowTree, if we encounter a <use> element? // @@ -608,7 +603,7 @@ ToSVGElementOrNull(original_use.ResolveTargetElement(kDontAddObserver)); if (target) { if (IsDisallowedElement(*target) || HasCycleUseReferencing(*use, *target)) - return false; + return; } // Don't DCHECK(target) here, it may be "pending", too. @@ -633,7 +628,6 @@ use = Traversal<SVGUseElement>::Next(*replacing_element, &shadow_root); } - return true; } void SVGUseElement::InvalidateShadowTree() {
diff --git a/third_party/blink/renderer/core/svg/svg_use_element.h b/third_party/blink/renderer/core/svg/svg_use_element.h index fb663e4..5e853d81 100644 --- a/third_party/blink/renderer/core/svg/svg_use_element.h +++ b/third_party/blink/renderer/core/svg/svg_use_element.h
@@ -107,7 +107,7 @@ void ClearResourceReference(); bool HasCycleUseReferencing(const ContainerNode& target_instance, const SVGElement& new_target) const; - bool ExpandUseElementsInShadowTree(); + void ExpandUseElementsInShadowTree(); void CloneNonMarkupEventListeners(); void AddReferencesToFirstDegreeNestedUseElements(SVGElement& target);
diff --git a/third_party/blink/renderer/modules/background_fetch/background_fetch_manager.cc b/third_party/blink/renderer/modules/background_fetch/background_fetch_manager.cc index 515a067..7b07f93 100644 --- a/third_party/blink/renderer/modules/background_fetch/background_fetch_manager.cc +++ b/third_party/blink/renderer/modules/background_fetch/background_fetch_manager.cc
@@ -92,29 +92,9 @@ request_url.ProtocolIsInHTTPFamily(); } -bool ShouldBlockCORSPreflight(ExecutionContext* execution_context, - const WebServiceWorkerRequest& web_request, - const KURL& request_url) { - // Requests that require CORS preflights are temporarily blocked, because the - // browser side of Background Fetch doesn't yet support performing CORS - // checks. TODO(crbug.com/711354): Remove this temporary block. - - // Same origin requests don't require a CORS preflight. - // https://fetch.spec.whatwg.org/#main-fetch - // TODO(crbug.com/711354): Make sure that cross-origin redirects are disabled. - bool same_origin = - execution_context->GetSecurityOrigin()->CanRequest(request_url); - if (same_origin) - return false; - - // Requests that are more involved than what is possible with HTML's form - // element require a CORS-preflight request. - // https://fetch.spec.whatwg.org/#main-fetch - if (!CORS::IsCORSSafelistedMethod(web_request.Method()) || - !CORS::ContainsOnlyCORSSafelistedHeaders(web_request.Headers())) { - return true; - } - +bool ShouldBlockGateWayAttacks(ExecutionContext* execution_context, + const WebServiceWorkerRequest& web_request, + const KURL& request_url) { if (RuntimeEnabledFeatures::CorsRFC1918Enabled()) { mojom::IPAddressSpace requestor_space = execution_context->GetSecurityContext().AddressSpace(); @@ -235,10 +215,11 @@ "it contains dangling markup"); } - if (ShouldBlockCORSPreflight(execution_context, web_request, request_url)) { + if (ShouldBlockGateWayAttacks(execution_context, web_request, + request_url)) { return RejectWithTypeError(script_state, request_url, - "CORS preflights are not yet supported " - "by this browser"); + "Requestor IP address space doesn't match the " + "target address space."); } kurls.insert(request_url);
diff --git a/third_party/blink/renderer/modules/nfc/OWNERS b/third_party/blink/renderer/modules/nfc/OWNERS index 24ac3f7..0243a40c 100644 --- a/third_party/blink/renderer/modules/nfc/OWNERS +++ b/third_party/blink/renderer/modules/nfc/OWNERS
@@ -1,3 +1,2 @@ -alexander.shalamov@intel.com kenneth.r.christiansen@intel.com -rijubrata.bhaumik@intel.com \ No newline at end of file +rijubrata.bhaumik@intel.com
diff --git a/third_party/blink/renderer/modules/sensor/OWNERS b/third_party/blink/renderer/modules/sensor/OWNERS index 655a26a..5419ed8e 100644 --- a/third_party/blink/renderer/modules/sensor/OWNERS +++ b/third_party/blink/renderer/modules/sensor/OWNERS
@@ -1,4 +1,3 @@ -alexander.shalamov@intel.com reillyg@chromium.org rijubrata.bhaumik@intel.com timvolodine@chromium.org
diff --git a/third_party/blink/renderer/platform/lifecycle_notifier.h b/third_party/blink/renderer/platform/lifecycle_notifier.h index 47e9a283..05e9958 100644 --- a/third_party/blink/renderer/platform/lifecycle_notifier.h +++ b/third_party/blink/renderer/platform/lifecycle_notifier.h
@@ -29,7 +29,7 @@ #include "base/auto_reset.h" #include "third_party/blink/renderer/platform/heap/handle.h" -#include "third_party/blink/renderer/platform/wtf/hash_set.h" +#include "third_party/blink/renderer/platform/heap/heap_allocator.h" namespace blink { @@ -82,7 +82,7 @@ } private: - using ObserverSet = HeapHashSet<WeakMember<LifecycleObserverBase>>; + using ObserverSet = HeapLinkedHashSet<WeakMember<LifecycleObserverBase>>; enum IterationState { kAllowingNone = 0, @@ -154,7 +154,7 @@ // Observer unregistration is allowed, but effectively a no-op. base::AutoReset<IterationState> scope(&iteration_state_, kAllowingRemoval); ObserverSet observers; - observers_.swap(observers); + observers_.Swap(observers); for (LifecycleObserverBase* observer_base : observers) { Observer* observer = static_cast<Observer*>(observer_base); DCHECK(observer->LifecycleContext() == Context());
diff --git a/third_party/blink/renderer/platform/network/network_utils.cc b/third_party/blink/renderer/platform/network/network_utils.cc index a0c34aef..ef46907 100644 --- a/third_party/blink/renderer/platform/network/network_utils.cc +++ b/third_party/blink/renderer/platform/network/network_utils.cc
@@ -13,7 +13,6 @@ #include "net/http/http_util.h" #include "net/url_request/url_request_data_job.h" #include "third_party/blink/public/common/mime_util/mime_util.h" -#include "third_party/blink/public/platform/url_conversion.h" #include "third_party/blink/public/platform/web_string.h" #include "third_party/blink/renderer/platform/loader/fetch/resource_response.h" #include "third_party/blink/renderer/platform/shared_buffer.h" @@ -79,8 +78,7 @@ new net::HttpResponseHeaders(std::string())); int result = net::URLRequestDataJob::BuildResponse( - WebStringToGURL(url.GetString()), &utf8_mime_type, &utf8_charset, - &data_string, headers.get()); + GURL(url), &utf8_mime_type, &utf8_charset, &data_string, headers.get()); if (result != net::OK) return nullptr; @@ -109,8 +107,7 @@ bool IsDataURLMimeTypeSupported(const KURL& url) { std::string utf8_mime_type; std::string utf8_charset; - if (net::DataURL::Parse(WebStringToGURL(url.GetString()), &utf8_mime_type, - &utf8_charset, nullptr)) { + if (net::DataURL::Parse(GURL(url), &utf8_mime_type, &utf8_charset, nullptr)) { return blink::IsSupportedMimeType(utf8_mime_type); } return false;
diff --git a/third_party/sqlite/fuzz/sqlite3_prepare_v2_fuzzer.cc b/third_party/sqlite/fuzz/sqlite3_prepare_v2_fuzzer.cc index cc5c8f18..e658b6b 100644 --- a/third_party/sqlite/fuzz/sqlite3_prepare_v2_fuzzer.cc +++ b/third_party/sqlite/fuzz/sqlite3_prepare_v2_fuzzer.cc
@@ -7,6 +7,7 @@ #include <algorithm> #include <array> +#include <cctype> #include <string> #include <vector>
diff --git a/third_party/wds/OWNERS b/third_party/wds/OWNERS index bff88c9..b3fe3e5 100644 --- a/third_party/wds/OWNERS +++ b/third_party/wds/OWNERS
@@ -1 +1 @@ -alexander.shalamov@intel.com +eero.hakkinen@intel.com
diff --git a/tools/gritsettings/translation_expectations.pyl b/tools/gritsettings/translation_expectations.pyl index 65da08de..24d06b0 100644 --- a/tools/gritsettings/translation_expectations.pyl +++ b/tools/gritsettings/translation_expectations.pyl
@@ -55,11 +55,10 @@ }, "android_grds": { "languages": [ - "am", "ar", "bg", "bn", "ca", "cs", "da", "de", "el", "en-GB", "es", - "es-419", "et", "fa", "fi", "fil", "fr", "gu", "hi", "hr", "hu", "id", - "it", "iw", "ja", "kn", "ko", "lt", "lv", "ml", "mr", "ms", "nl", "no", - "pl", "pt-BR", "pt-PT", "ro", "ru", "sk", "sl", "sr", "sv", "sw", "ta", - "te", "th", "tr", "uk", "vi", "zh-CN", "zh-TW", + "am", "ar", "bg", "ca", "cs", "da", "de", "el", "en-GB", "es", "es-419", + "fa", "fi", "fil", "fr", "hi", "hr", "hu", "id", "it", "iw", "ja", "ko", + "lt", "lv", "nl", "no", "pl", "pt-BR", "pt-PT", "ro", "ru", "sk", "sl", + "sr", "sv", "sw", "th", "tr", "uk", "vi", "zh-CN", "zh-TW", ], "files": [ "android_webview/java/strings/android_webview_strings.grd",
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml index c37b5c0..6f9c5df 100644 --- a/tools/metrics/histograms/enums.xml +++ b/tools/metrics/histograms/enums.xml
@@ -30522,6 +30522,7 @@ <int value="1820317896" label="NTPShowGoogleGInOmnibox:disabled"/> <int value="1820451991" label="enable-offline-auto-reload"/> <int value="1821723343" label="disable-saml-signin"/> + <int value="1823102966" label="disable-ipc-flooding-protection"/> <int value="1825940786" label="ChromeHomePromo:disabled"/> <int value="1827369558" label="AndroidPayIntegrationV1:disabled"/> <int value="1828660283" label="enable-webfonts-intervention-trigger"/>
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml index a5334d04..52517ec 100644 --- a/tools/metrics/histograms/histograms.xml +++ b/tools/metrics/histograms/histograms.xml
@@ -109463,6 +109463,26 @@ </summary> </histogram> +<histogram name="Translate.ExplicitLanguageAsk.LanguageAdded" + enum="CLD3LanguageCode"> + <owner>yyushkina@google.com</owner> + <owner>anthonyvd@google.com</owner> + <summary> + The languages that were added to the Accept Languages list from the Explicit + Language Ask prompt. + </summary> +</histogram> + +<histogram name="Translate.ExplicitLanguageAsk.LanguageRemoved" + enum="CLD3LanguageCode"> + <owner>yyushkina@google.com</owner> + <owner>anthonyvd@google.com</owner> + <summary> + The languages that were removed from the Accept Languages list from the + Explicit Language Ask prompt. + </summary> +</histogram> + <histogram name="Translate.ForceTriggerBackoffStateReached" enum="Boolean"> <owner>anthonyvd@chromium.org</owner> <owner>yyushkina@chromium.org</owner>
diff --git a/tools/perf/expectations.config b/tools/perf/expectations.config index 89ec212..e1ae377 100644 --- a/tools/perf/expectations.config +++ b/tools/perf/expectations.config
@@ -203,6 +203,7 @@ # Benchmark: system_health.common_desktop crbug.com/828917 [ Mac ] system_health.common_desktop/multitab:misc:typical24 [ Skip ] crbug.com/874803 [ Win_10 ] system_health.common_desktop/multitab:misc:typical24 [ Skip ] +crbug.com/874803 [ All ] system_health.common_desktop/multitab:misc:typical24:2018 [ Skip ] crbug.com/773084 [ Mac ] system_health.common_desktop/browse:tools:maps [ Skip ] crbug.com/839411 [ Win ] system_health.common_desktop/browse:social:twitter_infinite_scroll [ Skip ] crbug.com/846022 [ Linux ] system_health.common_desktop/browse:social:twitter_infinite_scroll [ Skip ]
diff --git a/ui/base/l10n/l10n_util_win.h b/ui/base/l10n/l10n_util_win.h index 11b30ba2..a245ec9 100644 --- a/ui/base/l10n/l10n_util_win.h +++ b/ui/base/l10n/l10n_util_win.h
@@ -51,7 +51,7 @@ // Retrieve the locale override, or an empty vector if the locale has not been // or failed to be overridden. -const std::vector<std::string>& GetLocaleOverrides(); +UI_BASE_EXPORT const std::vector<std::string>& GetLocaleOverrides(); } // namespace l10n_util
diff --git a/ui/webui/mojo_web_ui_controller.cc b/ui/webui/mojo_web_ui_controller.cc index e2de8d2..769e194 100644 --- a/ui/webui/mojo_web_ui_controller.cc +++ b/ui/webui/mojo_web_ui_controller.cc
@@ -24,6 +24,12 @@ content::RenderFrameHost* render_frame_host, const std::string& interface_name, mojo::ScopedMessagePipeHandle* interface_pipe) { + if (!registry_.CanBindInterface(interface_name)) { + LOG(WARNING) << "Cannot bind request to " << interface_name << "; ignoring " + << "request."; + return; + } + // Right now, this is expected to be called only for main frames. if (render_frame_host->GetParent()) { LOG(ERROR) << "Terminating renderer for requesting " << interface_name
diff --git a/ui/webui/resources/cr_components/chromeos/multidevice_setup/BUILD.gn b/ui/webui/resources/cr_components/chromeos/multidevice_setup/BUILD.gn index 9a329756..86fda9f 100644 --- a/ui/webui/resources/cr_components/chromeos/multidevice_setup/BUILD.gn +++ b/ui/webui/resources/cr_components/chromeos/multidevice_setup/BUILD.gn
@@ -60,6 +60,7 @@ ":setup_succeeded_page", ":start_setup_page", "//ui/webui/resources/js:cr", + "//ui/webui/resources/js:web_ui_listener_behavior", ] extra_deps = [
diff --git a/ui/webui/resources/cr_components/chromeos/multidevice_setup/mojo_api.js b/ui/webui/resources/cr_components/chromeos/multidevice_setup/mojo_api.js index 0fd824c1..d2aba99 100644 --- a/ui/webui/resources/cr_components/chromeos/multidevice_setup/mojo_api.js +++ b/ui/webui/resources/cr_components/chromeos/multidevice_setup/mojo_api.js
@@ -14,15 +14,19 @@ /** @implements {multidevice_setup.MojoInterfaceProvider} */ class MojoInterfaceProviderImpl { constructor() { - /** @private {!chromeos.multideviceSetup.mojom.MultiDeviceSetupPtr} */ - this.ptr_ = new chromeos.multideviceSetup.mojom.MultiDeviceSetupPtr(); - Mojo.bindInterface( - chromeos.multideviceSetup.mojom.MultiDeviceSetup.name, - mojo.makeRequest(this.ptr_).handle); + /** @private {?chromeos.multideviceSetup.mojom.MultiDeviceSetupPtr} */ + this.ptr_ = null; } /** @override */ getInterfacePtr() { + if (!this.ptr_) { + this.ptr_ = new chromeos.multideviceSetup.mojom.MultiDeviceSetupPtr(); + Mojo.bindInterface( + chromeos.multideviceSetup.mojom.MultiDeviceSetup.name, + mojo.makeRequest(this.ptr_).handle); + } + return this.ptr_; } }
diff --git a/ui/webui/resources/cr_components/chromeos/multidevice_setup/multidevice_setup.html b/ui/webui/resources/cr_components/chromeos/multidevice_setup/multidevice_setup.html index 8256304..d245b45 100644 --- a/ui/webui/resources/cr_components/chromeos/multidevice_setup/multidevice_setup.html +++ b/ui/webui/resources/cr_components/chromeos/multidevice_setup/multidevice_setup.html
@@ -10,6 +10,7 @@ <link rel="import" href="chrome://resources/cr_components/chromeos/multidevice_setup/setup_succeeded_page.html"> <link rel="import" href="chrome://resources/cr_components/chromeos/multidevice_setup/start_setup_page.html"> <link rel="import" href="chrome://resources/html/cr.html"> +<link rel="import" href="chrome://resources/html/web_ui_listener_behavior.html"> <link rel="import" href="chrome://resources/polymer/v1_0/iron-pages/iron-pages.html"> <dom-module id="multidevice-setup">
diff --git a/ui/webui/resources/cr_components/chromeos/multidevice_setup/multidevice_setup.js b/ui/webui/resources/cr_components/chromeos/multidevice_setup/multidevice_setup.js index 2b3a13e..c88e37f 100644 --- a/ui/webui/resources/cr_components/chromeos/multidevice_setup/multidevice_setup.js +++ b/ui/webui/resources/cr_components/chromeos/multidevice_setup/multidevice_setup.js
@@ -18,6 +18,8 @@ const MultiDeviceSetup = Polymer({ is: 'multidevice-setup', + behaviors: [WebUIListenerBehavior], + properties: { /** * Delegate object which performs differently in OOBE vs. non-OOBE mode. @@ -106,10 +108,10 @@ passwordPageForwardButtonDisabled_: Boolean, /** - * Interface to the MultiDeviceSetup Mojo service. - * @private {!chromeos.multideviceSetup.mojom.MultiDeviceSetupImpl} + * Provider of an interface to the MultiDeviceSetup Mojo service. + * @private {!multidevice_setup.MojoInterfaceProvider} */ - multideviceSetup_: Object + mojoInterfaceProvider_: Object }, listeners: { @@ -119,14 +121,20 @@ /** @override */ created: function() { - this.multideviceSetup_ = - multidevice_setup.MojoInterfaceProviderImpl.getInstance() - .getInterfacePtr(); + this.mojoInterfaceProvider_ = + multidevice_setup.MojoInterfaceProviderImpl.getInstance(); }, /** @override */ - attached: function() { - this.multideviceSetup_.getEligibleHostDevices() + ready: function() { + this.addWebUIListener( + 'multidevice_setup.initializeSetupFlow', + this.initializeSetupFlow.bind(this)); + }, + + initializeSetupFlow: function() { + this.mojoInterfaceProvider_.getInterfacePtr() + .getEligibleHostDevices() .then((responseParams) => { if (responseParams.eligibleHostDevices.length == 0) { console.warn('Potential host list is empty.');