diff --git a/.gitignore b/.gitignore index 719b6b94..12348f9 100644 --- a/.gitignore +++ b/.gitignore
@@ -68,6 +68,7 @@ /c /cdm /ceee/internal/ +/chrome/android/profiles/chrome-profile-*.prof /chrome/angle_unittests_run.xml /chrome/build/chrome.x64.orderfile /chrome/build/chrome.x86.orderfile
diff --git a/DEPS b/DEPS index 458b731..13dcd7d6 100644 --- a/DEPS +++ b/DEPS
@@ -78,7 +78,7 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling Skia # and whatever else without interference from each other. - 'skia_revision': 'aebad197dcaf2f02d5c71e9cf9b3f383a36df538', + 'skia_revision': 'da6d0720300a29a4deb5dd4c433a92a3ec41286e', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling V8 # and whatever else without interference from each other. @@ -90,7 +90,7 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling ANGLE # and whatever else without interference from each other. - 'angle_revision': 'd8724a947bd8663a796a3dc70057a17fc91ae516', + 'angle_revision': '8b5e8fdb3c353d46c81243b31889856181ff66ae', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling build tools # and whatever else without interference from each other. @@ -102,7 +102,7 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling PDFium # and whatever else without interference from each other. - 'pdfium_revision': '05dcbc931eacb72f1a11835ae282fc8434b7a434', + 'pdfium_revision': 'cbd4410908e2a4898fdd5e0d6d17591fc2c71f54', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling openmax_dl # and whatever else without interference from each other. @@ -134,7 +134,7 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling catapult # and whatever else without interference from each other. - 'catapult_revision': '7365f02611830723d60963f0619d5bab45060849', + 'catapult_revision': '19e11600d3a9410651e6c12e801a03eeca7274cc', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling libFuzzer # and whatever else without interference from each other. @@ -142,7 +142,7 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling devtools-node-modules # and whatever else without interference from each other. - 'devtools_node_modules_revision': '2597f8672ac64e29173d3b9ec14a6fdfb73e2582', + 'devtools_node_modules_revision': '5f7cd2497d7a643125c3b6eb910d99ba28be6899', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling libprotobuf-mutator # and whatever else without interference from each other. @@ -640,7 +640,7 @@ Var('chromium_git') + '/external/khronosgroup/webgl.git' + '@' + 'd458ada06171a85af00367251a4ed55db7fe2018', 'src/third_party/webrtc': - Var('webrtc_git') + '/src.git' + '@' + '731082ce7ea6e86a0d0d738460d7366f7df7c0c5', # commit position 20628 + Var('webrtc_git') + '/src.git' + '@' + '35d2b7e9de9ddb40cac35a21d50977dc5ca231d8', # commit position 20628 'src/third_party/xdg-utils': { 'url': Var('chromium_git') + '/chromium/deps/xdg-utils.git' + '@' + 'd80274d5869b17b8c9067a1022e4416ee7ed5e0d',
diff --git a/android_webview/BUILD.gn b/android_webview/BUILD.gn index 7611210..0f57442 100644 --- a/android_webview/BUILD.gn +++ b/android_webview/BUILD.gn
@@ -57,6 +57,7 @@ "java/src/org/chromium/android_webview/AwResource.java", "java/src/org/chromium/android_webview/AwSettings.java", "java/src/org/chromium/android_webview/AwTokenBindingManager.java", + "java/src/org/chromium/android_webview/AwTracingController.java", "java/src/org/chromium/android_webview/AwWebContentsDelegate.java", "java/src/org/chromium/android_webview/AwWebResourceResponse.java", "java/src/org/chromium/android_webview/InputStreamUtil.java", @@ -616,6 +617,8 @@ "browser/surfaces_instance.cc", "browser/surfaces_instance.h", "browser/token_binding_manager_bridge.cc", + "browser/tracing/aw_tracing_controller.cc", + "browser/tracing/aw_tracing_controller.h", "browser/tracing/aw_tracing_delegate.cc", "browser/tracing/aw_tracing_delegate.h", "common/android_webview_message_generator.cc", @@ -808,6 +811,7 @@ "java/src/org/chromium/android_webview/AwSettings.java", "java/src/org/chromium/android_webview/AwSwitches.java", "java/src/org/chromium/android_webview/AwTokenBindingManager.java", + "java/src/org/chromium/android_webview/AwTracingController.java", "java/src/org/chromium/android_webview/AwViewMethods.java", "java/src/org/chromium/android_webview/AwViewAndroidDelegate.java", "java/src/org/chromium/android_webview/AwWebContentsDelegate.java",
diff --git a/android_webview/browser/tracing/aw_tracing_controller.cc b/android_webview/browser/tracing/aw_tracing_controller.cc new file mode 100644 index 0000000..8184684 --- /dev/null +++ b/android_webview/browser/tracing/aw_tracing_controller.cc
@@ -0,0 +1,134 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "android_webview/browser/tracing/aw_tracing_controller.h" + +#include "base/android/jni_android.h" +#include "base/android/jni_array.h" +#include "base/android/jni_string.h" +#include "base/bind.h" +#include "base/memory/ref_counted_memory.h" +#include "base/task_scheduler/post_task.h" + +#include "content/public/browser/browser_thread.h" +#include "content/public/browser/tracing_controller.h" + +#include "jni/AwTracingController_jni.h" + +using base::android::JavaParamRef; + +namespace { + +base::android::ScopedJavaLocalRef<jbyteArray> StringToJavaBytes( + JNIEnv* env, + const std::string& str) { + return base::android::ToJavaByteArray( + env, reinterpret_cast<const uint8_t*>(str.data()), str.size()); +} + +class AwTraceDataEndpoint + : public content::TracingController::TraceDataEndpoint { + public: + typedef base::Callback<void(std::unique_ptr<std::string>)> + ReceivedChunkCallback; + typedef base::Callback<void(std::unique_ptr<const base::DictionaryValue>)> + CompletedCallback; + + static scoped_refptr<content::TracingController::TraceDataEndpoint> Create( + ReceivedChunkCallback received_chunk_callback, + CompletedCallback completed_callback) { + return new AwTraceDataEndpoint(received_chunk_callback, completed_callback); + } + + void ReceiveTraceFinalContents( + std::unique_ptr<const base::DictionaryValue> metadata) override { + content::BrowserThread::PostTask( + content::BrowserThread::UI, FROM_HERE, + base::Bind(completed_callback_, base::Passed(std::move(metadata)))); + } + + void ReceiveTraceChunk(std::unique_ptr<std::string> chunk) override { + content::BrowserThread::PostTask( + content::BrowserThread::UI, FROM_HERE, + base::Bind(received_chunk_callback_, base::Passed(std::move(chunk)))); + } + + explicit AwTraceDataEndpoint(ReceivedChunkCallback received_chunk_callback, + CompletedCallback completed_callback) + : received_chunk_callback_(received_chunk_callback), + completed_callback_(completed_callback) {} + + private: + ~AwTraceDataEndpoint() override {} + + ReceivedChunkCallback received_chunk_callback_; + CompletedCallback completed_callback_; + + DISALLOW_COPY_AND_ASSIGN(AwTraceDataEndpoint); +}; + +} // namespace + +namespace android_webview { + +static jlong JNI_AwTracingController_Init(JNIEnv* env, + const JavaParamRef<jobject>& obj) { + AwTracingController* controller = new AwTracingController(env, obj); + return reinterpret_cast<intptr_t>(controller); +} + +AwTracingController::AwTracingController(JNIEnv* env, jobject obj) + : weak_java_object_(env, obj), weak_factory_(this) {} + +AwTracingController::~AwTracingController() {} + +bool AwTracingController::Start(JNIEnv* env, + const JavaParamRef<jobject>& obj, + const JavaParamRef<jstring>& jcategories, + jint jmode) { + std::string categories = + base::android::ConvertJavaStringToUTF8(env, jcategories); + base::trace_event::TraceConfig trace_config( + categories, static_cast<base::trace_event::TraceRecordMode>(jmode)); + return content::TracingController::GetInstance()->StartTracing( + trace_config, content::TracingController::StartTracingDoneCallback()); +} + +bool AwTracingController::StopAndFlush(JNIEnv* env, + const JavaParamRef<jobject>& obj) { + return content::TracingController::GetInstance()->StopTracing( + AwTraceDataEndpoint::Create( + base::Bind(&AwTracingController::OnTraceDataReceived, + weak_factory_.GetWeakPtr()), + base::Bind(&AwTracingController::OnTraceDataComplete, + weak_factory_.GetWeakPtr()))); +} + +void AwTracingController::OnTraceDataComplete( + std::unique_ptr<const base::DictionaryValue> metadata) { + JNIEnv* env = base::android::AttachCurrentThread(); + base::android::ScopedJavaLocalRef<jobject> obj = weak_java_object_.get(env); + if (obj.obj()) { + Java_AwTracingController_onTraceDataComplete(env, obj); + } +} + +void AwTracingController::OnTraceDataReceived( + std::unique_ptr<std::string> chunk) { + JNIEnv* env = base::android::AttachCurrentThread(); + base::android::ScopedJavaLocalRef<jobject> obj = weak_java_object_.get(env); + if (obj.obj()) { + base::android::ScopedJavaLocalRef<jbyteArray> java_trace_data = + StringToJavaBytes(env, *chunk); + Java_AwTracingController_onTraceDataChunkReceived(env, obj, + java_trace_data); + } +} + +bool AwTracingController::IsTracing(JNIEnv* env, + const JavaParamRef<jobject>& obj) { + return content::TracingController::GetInstance()->IsTracing(); +} + +} // namespace android_webview
diff --git a/android_webview/browser/tracing/aw_tracing_controller.h b/android_webview/browser/tracing/aw_tracing_controller.h new file mode 100644 index 0000000..509860f --- /dev/null +++ b/android_webview/browser/tracing/aw_tracing_controller.h
@@ -0,0 +1,43 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ANDROID_WEBVIEW_BROWSER_TRACING_AW_TRACING_CONTROLLER_H_ +#define ANDROID_WEBVIEW_BROWSER_TRACING_AW_TRACING_CONTROLLER_H_ + +#include "base/android/jni_weak_ref.h" +#include "base/macros.h" +#include "base/memory/weak_ptr.h" + +#include "content/public/browser/tracing_controller.h" + +namespace android_webview { + +class AwTracingController { + public: + AwTracingController(JNIEnv* env, jobject obj); + + bool Start(JNIEnv* env, + const base::android::JavaParamRef<jobject>& obj, + const base::android::JavaParamRef<jstring>& categories, + jint mode); + bool StopAndFlush(JNIEnv* env, + const base::android::JavaParamRef<jobject>& obj); + bool IsTracing(JNIEnv* env, const base::android::JavaParamRef<jobject>& obj); + + private: + ~AwTracingController(); + + void OnTraceDataReceived(std::unique_ptr<std::string> chunk); + void OnTraceDataComplete( + std::unique_ptr<const base::DictionaryValue> metadata); + + JavaObjectWeakGlobalRef weak_java_object_; + base::WeakPtrFactory<AwTracingController> weak_factory_; + + DISALLOW_COPY_AND_ASSIGN(AwTracingController); +}; + +} // namespace android_webview + +#endif // ANDROID_WEBVIEW_BROWSER_TRACING_AW_TRACING_CONTROLLER_H_
diff --git a/android_webview/java/src/org/chromium/android_webview/AwBrowserContext.java b/android_webview/java/src/org/chromium/android_webview/AwBrowserContext.java index 3d4504a..b6370a3e7 100644 --- a/android_webview/java/src/org/chromium/android_webview/AwBrowserContext.java +++ b/android_webview/java/src/org/chromium/android_webview/AwBrowserContext.java
@@ -24,6 +24,7 @@ private AwGeolocationPermissions mGeolocationPermissions; private AwFormDatabase mFormDatabase; private AwServiceWorkerController mServiceWorkerController; + private AwTracingController mTracingController; private Context mApplicationContext; public AwBrowserContext(SharedPreferences sharedPreferences, Context applicationContext) { @@ -54,6 +55,13 @@ return mServiceWorkerController; } + public AwTracingController getTracingController() { + if (mTracingController == null) { + mTracingController = new AwTracingController(); + } + return mTracingController; + } + /** * @see android.webkit.WebView#pauseTimers() */
diff --git a/android_webview/java/src/org/chromium/android_webview/AwTracingController.java b/android_webview/java/src/org/chromium/android_webview/AwTracingController.java new file mode 100644 index 0000000..8b2d6707 --- /dev/null +++ b/android_webview/java/src/org/chromium/android_webview/AwTracingController.java
@@ -0,0 +1,78 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package org.chromium.android_webview; + +import android.support.annotation.Nullable; + +import org.chromium.base.annotations.CalledByNative; +import org.chromium.base.annotations.JNINamespace; + +/** + * Manages tracing functionality in WebView. + */ +@JNINamespace("android_webview") +public class AwTracingController { + private static final String TAG = "cr.AwTracingController"; + + private AwTracingOutputStream mOutputStream; + + // TODO: consider caching a mIsTracing value for efficiency. + // boolean mIsTracing; + + /** + * Interface for the callbacks to return tracing data. + */ + public interface AwTracingOutputStream { + public void write(byte[] chunk); + public void complete(); + } + + public AwTracingController() { + mNativeAwTracingController = nativeInit(); + } + + // Start tracing. + public boolean start(String categoryFilter, int mode) { + if (isTracing()) { + return false; + } + + boolean result = nativeStart(mNativeAwTracingController, categoryFilter, mode); + return result; + } + + // Stop tracing and flush tracing data. + public boolean stopAndFlush(@Nullable AwTracingOutputStream outputStream) { + if (!isTracing()) return false; + mOutputStream = outputStream; + nativeStopAndFlush(mNativeAwTracingController); + return true; + } + + public boolean isTracing() { + return nativeIsTracing(mNativeAwTracingController); + } + + @CalledByNative + private void onTraceDataChunkReceived(byte[] data) { + if (mOutputStream != null) { + mOutputStream.write(data); + } + } + + @CalledByNative + private void onTraceDataComplete() { + if (mOutputStream != null) { + mOutputStream.complete(); + } + } + + private long mNativeAwTracingController; + private native long nativeInit(); + private native boolean nativeStart( + long nativeAwTracingController, String categories, int traceMode); + private native boolean nativeStopAndFlush(long nativeAwTracingController); + private native boolean nativeIsTracing(long nativeAwTracingController); +}
diff --git a/android_webview/test/shell/src/org/chromium/android_webview/shell/AwShellActivity.java b/android_webview/test/shell/src/org/chromium/android_webview/shell/AwShellActivity.java index 1a192fd1..4203a74 100644 --- a/android_webview/test/shell/src/org/chromium/android_webview/shell/AwShellActivity.java +++ b/android_webview/test/shell/src/org/chromium/android_webview/shell/AwShellActivity.java
@@ -36,7 +36,6 @@ import org.chromium.base.ContextUtils; import org.chromium.base.Log; import org.chromium.base.TraceEvent; -import org.chromium.content.app.ContentApplication; import org.chromium.content_public.browser.NavigationController; import org.chromium.content_public.browser.WebContents; import org.chromium.content_public.common.ContentUrlConstants; @@ -66,7 +65,7 @@ AwShellResourceProvider.registerResources(this); - ContentApplication.initCommandLine(this); + ((AwShellApplication) getApplication()).initCommandLine(); ContextUtils.initApplicationContext(getApplicationContext()); AwBrowserProcess.loadLibrary(null);
diff --git a/android_webview/test/shell/src/org/chromium/android_webview/shell/AwShellApplication.java b/android_webview/test/shell/src/org/chromium/android_webview/shell/AwShellApplication.java index d07ade4..cea82bc 100644 --- a/android_webview/test/shell/src/org/chromium/android_webview/shell/AwShellApplication.java +++ b/android_webview/test/shell/src/org/chromium/android_webview/shell/AwShellApplication.java
@@ -12,7 +12,6 @@ */ public class AwShellApplication extends ContentApplication { - @Override public void initCommandLine() { if (!CommandLine.isInitialized()) { CommandLine.initFromFile("/data/local/tmp/android-webview-command-line");
diff --git a/ash/BUILD.gn b/ash/BUILD.gn index 4b1c93e..513d365 100644 --- a/ash/BUILD.gn +++ b/ash/BUILD.gn
@@ -108,6 +108,8 @@ "display/display_error_observer_chromeos.h", "display/display_move_window_util.cc", "display/display_move_window_util.h", + "display/display_shutdown_observer.cc", + "display/display_shutdown_observer.h", "display/display_synchronizer.cc", "display/display_synchronizer.h", "display/display_util.cc", @@ -139,8 +141,6 @@ "display/screen_position_controller.h", "display/shared_display_edge_indicator.cc", "display/shared_display_edge_indicator.h", - "display/shutdown_observer_chromeos.cc", - "display/shutdown_observer_chromeos.h", "display/touch_calibrator_controller.cc", "display/touch_calibrator_controller.h", "display/touch_calibrator_view.cc",
diff --git a/ash/display/shutdown_observer_chromeos.cc b/ash/display/display_shutdown_observer.cc similarity index 66% rename from ash/display/shutdown_observer_chromeos.cc rename to ash/display/display_shutdown_observer.cc index ead47b4f..ee846a6 100644 --- a/ash/display/shutdown_observer_chromeos.cc +++ b/ash/display/display_shutdown_observer.cc
@@ -2,22 +2,22 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "ash/display/shutdown_observer_chromeos.h" +#include "ash/display/display_shutdown_observer.h" #include "ui/display/manager/chromeos/display_configurator.h" namespace ash { -ShutdownObserver::ShutdownObserver( +DisplayShutdownObserver::DisplayShutdownObserver( display::DisplayConfigurator* display_configurator) : display_configurator_(display_configurator), scoped_session_observer_(this) {} -ShutdownObserver::~ShutdownObserver() = default; +DisplayShutdownObserver::~DisplayShutdownObserver() = default; -void ShutdownObserver::OnChromeTerminating() { +void DisplayShutdownObserver::OnChromeTerminating() { // Stop handling display configuration events once the shutdown - // process starts. crbug.com/177014. + // process starts. http://crbug.com/177014. display_configurator_->PrepareForExit(); }
diff --git a/ash/display/shutdown_observer_chromeos.h b/ash/display/display_shutdown_observer.h similarity index 61% rename from ash/display/shutdown_observer_chromeos.h rename to ash/display/display_shutdown_observer.h index fc773db..6f91770 100644 --- a/ash/display/shutdown_observer_chromeos.h +++ b/ash/display/display_shutdown_observer.h
@@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef ASH_DISPLAY_SHUTDOWN_OBSERVER_CHROMEOS_H_ -#define ASH_DISPLAY_SHUTDOWN_OBSERVER_CHROMEOS_H_ +#ifndef ASH_DISPLAY_DISPLAY_SHUTDOWN_OBSERVER_H_ +#define ASH_DISPLAY_DISPLAY_SHUTDOWN_OBSERVER_H_ #include "ash/session/session_observer.h" #include "base/macros.h" @@ -16,10 +16,11 @@ // Adds self as SessionObserver and listens for OnChromeTerminating() on // behalf of |display_configurator_|. -class ShutdownObserver : public SessionObserver { +class DisplayShutdownObserver : public SessionObserver { public: - explicit ShutdownObserver(display::DisplayConfigurator* display_configurator); - ~ShutdownObserver() override; + explicit DisplayShutdownObserver( + display::DisplayConfigurator* display_configurator); + ~DisplayShutdownObserver() override; private: // SessionObserver: @@ -28,9 +29,9 @@ display::DisplayConfigurator* const display_configurator_; ScopedSessionObserver scoped_session_observer_; - DISALLOW_COPY_AND_ASSIGN(ShutdownObserver); + DISALLOW_COPY_AND_ASSIGN(DisplayShutdownObserver); }; } // namespace ash -#endif // ASH_DISPLAY_SHUTDOWN_OBSERVER_CHROMEOS_H_ +#endif // ASH_DISPLAY_DISPLAY_SHUTDOWN_OBSERVER_H_
diff --git a/ash/display/projecting_observer_chromeos.cc b/ash/display/projecting_observer_chromeos.cc index 727e923..352c7f0f 100644 --- a/ash/display/projecting_observer_chromeos.cc +++ b/ash/display/projecting_observer_chromeos.cc
@@ -4,22 +4,29 @@ #include "ash/display/projecting_observer_chromeos.h" +#include "ash/shell.h" #include "base/logging.h" +#include "chromeos/dbus/dbus_thread_manager.h" #include "chromeos/dbus/power_manager_client.h" #include "ui/display/types/display_snapshot.h" namespace ash { ProjectingObserver::ProjectingObserver( - chromeos::PowerManagerClient* power_manager_client) - : has_internal_output_(false), - output_count_(0), - casting_session_count_(0), - power_manager_client_(power_manager_client) { - DCHECK(power_manager_client); + display::DisplayConfigurator* display_configurator) + : display_configurator_(display_configurator) { + if (Shell::HasInstance()) + Shell::Get()->AddShellObserver(this); + if (display_configurator_) + display_configurator_->AddObserver(this); } -ProjectingObserver::~ProjectingObserver() = default; +ProjectingObserver::~ProjectingObserver() { + if (Shell::HasInstance()) + Shell::Get()->RemoveShellObserver(this); + if (display_configurator_) + display_configurator_->RemoveObserver(this); +} void ProjectingObserver::OnDisplayModeChanged( const display::DisplayConfigurator::DisplayStateList& display_states) { @@ -56,7 +63,12 @@ bool projecting = has_internal_output_ && (output_count_ + casting_session_count_ > 1); - power_manager_client_->SetIsProjecting(projecting); + chromeos::PowerManagerClient* power_manager_client = + power_manager_client_for_test_ + ? power_manager_client_for_test_ + : chromeos::DBusThreadManager::Get()->GetPowerManagerClient(); + if (power_manager_client) + power_manager_client->SetIsProjecting(projecting); } } // namespace ash
diff --git a/ash/display/projecting_observer_chromeos.h b/ash/display/projecting_observer_chromeos.h index 22f79c5..e64c7e0ae 100644 --- a/ash/display/projecting_observer_chromeos.h +++ b/ash/display/projecting_observer_chromeos.h
@@ -20,9 +20,9 @@ : public display::DisplayConfigurator::Observer, public ShellObserver { public: - // |power_manager_client| must outlive this object. + // |display_configurator| must outlive this instance. May be null in tests. explicit ProjectingObserver( - chromeos::PowerManagerClient* power_manager_client); + display::DisplayConfigurator* display_configurator); ~ProjectingObserver() override; // DisplayConfigurator::Observer implementation: @@ -33,21 +33,30 @@ void OnCastingSessionStartedOrStopped(bool started) override; private: + friend class ProjectingObserverTest; + + void set_power_manager_client_for_test( + chromeos::PowerManagerClient* power_manager_client) { + power_manager_client_for_test_ = power_manager_client; + } + // Sends the current projecting state to power manager. void SetIsProjecting(); + display::DisplayConfigurator* display_configurator_; // Unowned + // True if at least one output is internal. This value is updated when // |OnDisplayModeChanged| is called. - bool has_internal_output_; + bool has_internal_output_ = false; // Keeps track of the number of connected outputs. - int output_count_; + int output_count_ = 0; // Number of outstanding casting sessions. - int casting_session_count_; + int casting_session_count_ = 0; - // Weak pointer to the DBusClient PowerManagerClient; - chromeos::PowerManagerClient* power_manager_client_; + // Weak pointer to the DBusClient PowerManagerClient for testing; + chromeos::PowerManagerClient* power_manager_client_for_test_ = nullptr; DISALLOW_COPY_AND_ASSIGN(ProjectingObserver); };
diff --git a/ash/display/projecting_observer_chromeos_unittest.cc b/ash/display/projecting_observer_chromeos_unittest.cc index da2ef3db..55eff557 100644 --- a/ash/display/projecting_observer_chromeos_unittest.cc +++ b/ash/display/projecting_observer_chromeos_unittest.cc
@@ -12,6 +12,7 @@ #include "ui/display/manager/fake_display_snapshot.h" namespace ash { + namespace { std::unique_ptr<display::DisplaySnapshot> CreateInternalSnapshot() { @@ -30,20 +31,6 @@ .Build(); } -class ProjectingObserverTest : public testing::Test { - public: - ProjectingObserverTest() : observer_(&fake_power_client_) {} - - ~ProjectingObserverTest() override = default; - - protected: - chromeos::FakePowerManagerClient fake_power_client_; - ProjectingObserver observer_; - - private: - DISALLOW_COPY_AND_ASSIGN(ProjectingObserverTest); -}; - display::DisplayConfigurator::DisplayStateList GetPointers( const std::vector<std::unique_ptr<display::DisplaySnapshot>>& displays) { display::DisplayConfigurator::DisplayStateList result; @@ -54,9 +41,26 @@ } // namespace +class ProjectingObserverTest : public testing::Test { + public: + ProjectingObserverTest() { + observer_ = std::make_unique<ProjectingObserver>(nullptr); + observer_->set_power_manager_client_for_test(&fake_power_client_); + } + + ~ProjectingObserverTest() override = default; + + protected: + chromeos::FakePowerManagerClient fake_power_client_; + std::unique_ptr<ProjectingObserver> observer_; + + private: + DISALLOW_COPY_AND_ASSIGN(ProjectingObserverTest); +}; + TEST_F(ProjectingObserverTest, CheckNoDisplay) { std::vector<std::unique_ptr<display::DisplaySnapshot>> displays; - observer_.OnDisplayModeChanged(GetPointers(displays)); + observer_->OnDisplayModeChanged(GetPointers(displays)); EXPECT_EQ(1, fake_power_client_.num_set_is_projecting_calls()); EXPECT_FALSE(fake_power_client_.is_projecting()); @@ -65,7 +69,7 @@ TEST_F(ProjectingObserverTest, CheckWithoutInternalDisplay) { std::vector<std::unique_ptr<display::DisplaySnapshot>> displays; displays.push_back(CreateVGASnapshot()); - observer_.OnDisplayModeChanged(GetPointers(displays)); + observer_->OnDisplayModeChanged(GetPointers(displays)); EXPECT_EQ(1, fake_power_client_.num_set_is_projecting_calls()); EXPECT_FALSE(fake_power_client_.is_projecting()); @@ -74,7 +78,7 @@ TEST_F(ProjectingObserverTest, CheckWithInternalDisplay) { std::vector<std::unique_ptr<display::DisplaySnapshot>> displays; displays.push_back(CreateInternalSnapshot()); - observer_.OnDisplayModeChanged(GetPointers(displays)); + observer_->OnDisplayModeChanged(GetPointers(displays)); EXPECT_EQ(1, fake_power_client_.num_set_is_projecting_calls()); EXPECT_FALSE(fake_power_client_.is_projecting()); @@ -84,7 +88,7 @@ std::vector<std::unique_ptr<display::DisplaySnapshot>> displays; displays.push_back(CreateVGASnapshot()); displays.push_back(CreateVGASnapshot()); - observer_.OnDisplayModeChanged(GetPointers(displays)); + observer_->OnDisplayModeChanged(GetPointers(displays)); EXPECT_EQ(1, fake_power_client_.num_set_is_projecting_calls()); // We need at least 1 internal display to set projecting to on. @@ -95,7 +99,7 @@ std::vector<std::unique_ptr<display::DisplaySnapshot>> displays; displays.push_back(CreateInternalSnapshot()); displays.push_back(CreateVGASnapshot()); - observer_.OnDisplayModeChanged(GetPointers(displays)); + observer_->OnDisplayModeChanged(GetPointers(displays)); EXPECT_EQ(1, fake_power_client_.num_set_is_projecting_calls()); EXPECT_TRUE(fake_power_client_.is_projecting()); @@ -104,9 +108,9 @@ TEST_F(ProjectingObserverTest, CheckWithVGADisplayAndOneCastingSession) { std::vector<std::unique_ptr<display::DisplaySnapshot>> displays; displays.push_back(CreateVGASnapshot()); - observer_.OnDisplayModeChanged(GetPointers(displays)); + observer_->OnDisplayModeChanged(GetPointers(displays)); - observer_.OnCastingSessionStartedOrStopped(true); + observer_->OnCastingSessionStartedOrStopped(true); EXPECT_EQ(2, fake_power_client_.num_set_is_projecting_calls()); // Need at least one internal display to set projecting state to |true|. @@ -116,9 +120,9 @@ TEST_F(ProjectingObserverTest, CheckWithInternalDisplayAndOneCastingSession) { std::vector<std::unique_ptr<display::DisplaySnapshot>> displays; displays.push_back(CreateInternalSnapshot()); - observer_.OnDisplayModeChanged(GetPointers(displays)); + observer_->OnDisplayModeChanged(GetPointers(displays)); - observer_.OnCastingSessionStartedOrStopped(true); + observer_->OnCastingSessionStartedOrStopped(true); EXPECT_EQ(2, fake_power_client_.num_set_is_projecting_calls()); EXPECT_TRUE(fake_power_client_.is_projecting()); @@ -127,15 +131,15 @@ TEST_F(ProjectingObserverTest, CheckProjectingAfterClosingACastingSession) { std::vector<std::unique_ptr<display::DisplaySnapshot>> displays; displays.push_back(CreateInternalSnapshot()); - observer_.OnDisplayModeChanged(GetPointers(displays)); + observer_->OnDisplayModeChanged(GetPointers(displays)); - observer_.OnCastingSessionStartedOrStopped(true); - observer_.OnCastingSessionStartedOrStopped(true); + observer_->OnCastingSessionStartedOrStopped(true); + observer_->OnCastingSessionStartedOrStopped(true); EXPECT_EQ(3, fake_power_client_.num_set_is_projecting_calls()); EXPECT_TRUE(fake_power_client_.is_projecting()); - observer_.OnCastingSessionStartedOrStopped(false); + observer_->OnCastingSessionStartedOrStopped(false); EXPECT_EQ(4, fake_power_client_.num_set_is_projecting_calls()); EXPECT_TRUE(fake_power_client_.is_projecting()); @@ -145,10 +149,10 @@ CheckStopProjectingAfterClosingAllCastingSessions) { std::vector<std::unique_ptr<display::DisplaySnapshot>> displays; displays.push_back(CreateInternalSnapshot()); - observer_.OnDisplayModeChanged(GetPointers(displays)); + observer_->OnDisplayModeChanged(GetPointers(displays)); - observer_.OnCastingSessionStartedOrStopped(true); - observer_.OnCastingSessionStartedOrStopped(false); + observer_->OnCastingSessionStartedOrStopped(true); + observer_->OnCastingSessionStartedOrStopped(false); EXPECT_EQ(3, fake_power_client_.num_set_is_projecting_calls()); EXPECT_FALSE(fake_power_client_.is_projecting()); @@ -159,11 +163,11 @@ std::vector<std::unique_ptr<display::DisplaySnapshot>> displays; displays.push_back(CreateInternalSnapshot()); displays.push_back(CreateVGASnapshot()); - observer_.OnDisplayModeChanged(GetPointers(displays)); + observer_->OnDisplayModeChanged(GetPointers(displays)); // Remove VGA output. displays.erase(displays.begin() + 1); - observer_.OnDisplayModeChanged(GetPointers(displays)); + observer_->OnDisplayModeChanged(GetPointers(displays)); EXPECT_EQ(2, fake_power_client_.num_set_is_projecting_calls()); EXPECT_FALSE(fake_power_client_.is_projecting());
diff --git a/ash/public/interfaces/wallpaper.mojom b/ash/public/interfaces/wallpaper.mojom index e138386..f0f75789 100644 --- a/ash/public/interfaces/wallpaper.mojom +++ b/ash/public/interfaces/wallpaper.mojom
@@ -63,7 +63,8 @@ // Used by Chrome to set the wallpaper displayed by ash. interface WallpaperController { - // Sets the client interface and the paths of wallpaper directories. The paths + // Do the initialization: Sets the client interface, the paths of wallpaper + // directories and the device wallpaper policy enforcement flag. The paths // must be sent over IPC because chrome owns the concept of user data // directory. // |client|: The client interface. @@ -72,10 +73,13 @@ // reside. // |chromeos_custom_wallpapers_path|: Directory where custom wallpapers // reside. - SetClientAndPaths(WallpaperControllerClient client, - mojo.common.mojom.FilePath user_data_path, - mojo.common.mojom.FilePath chromeos_wallpapers_path, - mojo.common.mojom.FilePath chromeos_custom_wallpapers_path); + // |is_device_wallpaper_policy_enforced|: Whether the device wallpaper policy + // is enforced on the device. + Init(WallpaperControllerClient client, + mojo.common.mojom.FilePath user_data_path, + mojo.common.mojom.FilePath chromeos_wallpapers_path, + mojo.common.mojom.FilePath chromeos_custom_wallpapers_path, + bool is_device_wallpaper_policy_enforced); // Sets wallpaper from policy or from a local file. Saves the custom wallpaper // to file, posts task to generate thumbnail and updates local state.
diff --git a/ash/shell.cc b/ash/shell.cc index bf596d5..353008e 100644 --- a/ash/shell.cc +++ b/ash/shell.cc
@@ -25,6 +25,7 @@ #include "ash/display/display_color_manager_chromeos.h" #include "ash/display/display_configuration_controller.h" #include "ash/display/display_error_observer_chromeos.h" +#include "ash/display/display_shutdown_observer.h" #include "ash/display/event_transformation_handler.h" #include "ash/display/mouse_cursor_event_filter.h" #include "ash/display/projecting_observer_chromeos.h" @@ -32,7 +33,6 @@ #include "ash/display/screen_ash.h" #include "ash/display/screen_orientation_controller_chromeos.h" #include "ash/display/screen_position_controller.h" -#include "ash/display/shutdown_observer_chromeos.h" #include "ash/display/window_tree_host_manager.h" #include "ash/drag_drop/drag_drop_controller.h" #include "ash/first_run/first_run_helper_impl.h" @@ -141,7 +141,6 @@ #include "base/threading/sequenced_worker_pool.h" #include "base/trace_event/trace_event.h" #include "chromeos/chromeos_switches.h" -#include "chromeos/dbus/dbus_thread_manager.h" #include "chromeos/system/devicemode.h" #include "components/prefs/pref_registry_simple.h" #include "components/prefs/pref_service.h" @@ -786,22 +785,17 @@ screen_position_controller_.reset(); display_color_manager_.reset(); + projecting_observer_.reset(); + if (display_change_observer_) display_configurator_->RemoveObserver(display_change_observer_.get()); if (display_error_observer_) display_configurator_->RemoveObserver(display_error_observer_.get()); - if (projecting_observer_) { - display_configurator_->RemoveObserver(projecting_observer_.get()); - RemoveShellObserver(projecting_observer_.get()); - } display_change_observer_.reset(); - shutdown_observer_.reset(); + display_shutdown_observer_.reset(); PowerStatus::Shutdown(); - // Ensure that DBusThreadManager outlives this Shell. - DCHECK(chromeos::DBusThreadManager::IsInitialized()); - // Needs to happen right before |instance_| is reset. shell_port_.reset(); session_controller_->RemoveObserver(this); @@ -881,65 +875,19 @@ base::WrapUnique(native_cursor_manager_)); } + // TODO(stevenjb): ChromeShellDelegate::PreInit currently handles + // DisplayPreference initialization, required for InitializeDisplayManager. + // Before we can move that code into ash/display where it belongs, we need to + // wait for |lcoal_state_| to be set in OnLocalStatePrefServiceInitialized + // before initializing DisplayPreferences (and therefore DisplayManager). + // http://crbug.com/678949. shell_delegate_->PreInit(); - bool display_initialized = display_manager_->InitFromCommandLine(); - if (!display_initialized && config != Config::CLASSIC) { - // Run display configuration off device in mus mode. - display_manager_->set_configure_displays(true); - display_configurator_->set_configure_display(true); - } - display_configuration_controller_ = - std::make_unique<DisplayConfigurationController>( - display_manager_.get(), window_tree_host_manager_.get()); - display_configurator_->Init(shell_port_->CreateNativeDisplayDelegate(), - false); - // The DBusThreadManager must outlive this Shell. See the DCHECK in ~Shell. - chromeos::DBusThreadManager* dbus_thread_manager = - chromeos::DBusThreadManager::Get(); - projecting_observer_.reset( - new ProjectingObserver(dbus_thread_manager->GetPowerManagerClient())); - display_configurator_->AddObserver(projecting_observer_.get()); - AddShellObserver(projecting_observer_.get()); - - if (!display_initialized) { - if (config != Config::CLASSIC && !chromeos::IsRunningAsSystemCompositor()) { - display::mojom::DevDisplayControllerPtr controller; - shell_delegate_->GetShellConnector()->BindInterface( - ui::mojom::kServiceName, &controller); - display_manager_->SetDevDisplayController(std::move(controller)); - } - - if (config != Config::CLASSIC || chromeos::IsRunningAsSystemCompositor()) { - display_change_observer_ = - std::make_unique<display::DisplayChangeObserver>( - display_configurator_.get(), display_manager_.get()); - - shutdown_observer_ = - std::make_unique<ShutdownObserver>(display_configurator_.get()); - - // Register |display_change_observer_| first so that the rest of - // observer gets invoked after the root windows are configured. - display_configurator_->AddObserver(display_change_observer_.get()); - display_error_observer_.reset(new DisplayErrorObserver()); - display_configurator_->AddObserver(display_error_observer_.get()); - display_configurator_->set_state_controller( - display_change_observer_.get()); - display_configurator_->set_mirroring_controller(display_manager_.get()); - display_configurator_->ForceInitialConfigure(); - display_initialized = true; - } - } - - display_color_manager_ = - std::make_unique<DisplayColorManager>(display_configurator_.get()); - - if (!display_initialized) - display_manager_->InitDefaultDisplay(); + InitializeDisplayManager(); if (config == Config::CLASSIC) { - display_manager_->RefreshFontParams(); - + // This will initialize aura::Env which requires |display_manager_| to + // be initialized first. aura::Env::GetInstance()->set_context_factory(context_factory); aura::Env::GetInstance()->set_context_factory_private( context_factory_private); @@ -1161,6 +1109,63 @@ user_metrics_recorder_->OnShellInitialized(); } +void Shell::InitializeDisplayManager() { + const Config config = shell_port_->GetAshConfig(); + bool display_initialized = display_manager_->InitFromCommandLine(); + + if (!display_initialized && config != Config::CLASSIC) { + // Run display configuration off device in mus mode. + display_manager_->set_configure_displays(true); + display_configurator_->set_configure_display(true); + } + display_configuration_controller_ = + std::make_unique<DisplayConfigurationController>( + display_manager_.get(), window_tree_host_manager_.get()); + display_configurator_->Init(shell_port_->CreateNativeDisplayDelegate(), + false); + + projecting_observer_ = + std::make_unique<ProjectingObserver>(display_configurator_.get()); + + if (!display_initialized) { + if (config != Config::CLASSIC && !chromeos::IsRunningAsSystemCompositor()) { + display::mojom::DevDisplayControllerPtr controller; + shell_delegate_->GetShellConnector()->BindInterface( + ui::mojom::kServiceName, &controller); + display_manager_->SetDevDisplayController(std::move(controller)); + } + + if (config != Config::CLASSIC || chromeos::IsRunningAsSystemCompositor()) { + display_change_observer_ = + std::make_unique<display::DisplayChangeObserver>( + display_configurator_.get(), display_manager_.get()); + + display_shutdown_observer_ = std::make_unique<DisplayShutdownObserver>( + display_configurator_.get()); + + // Register |display_change_observer_| first so that the rest of + // observer gets invoked after the root windows are configured. + display_configurator_->AddObserver(display_change_observer_.get()); + display_error_observer_.reset(new DisplayErrorObserver()); + display_configurator_->AddObserver(display_error_observer_.get()); + display_configurator_->set_state_controller( + display_change_observer_.get()); + display_configurator_->set_mirroring_controller(display_manager_.get()); + display_configurator_->ForceInitialConfigure(); + display_initialized = true; + } + } + + display_color_manager_ = + std::make_unique<DisplayColorManager>(display_configurator_.get()); + + if (!display_initialized) + display_manager_->InitDefaultDisplay(); + + if (config == Config::CLASSIC) + display_manager_->RefreshFontParams(); +} + void Shell::InitRootWindow(aura::Window* root_window) { DCHECK(focus_controller_); DCHECK(visibility_controller_.get());
diff --git a/ash/shell.h b/ash/shell.h index b620f74..890db6b 100644 --- a/ash/shell.h +++ b/ash/shell.h
@@ -94,6 +94,7 @@ class DisplayColorManager; class DisplayConfigurationController; class DisplayErrorObserver; +class DisplayShutdownObserver; class DragDropController; class EventClientImpl; class EventTransformationHandler; @@ -143,7 +144,6 @@ struct ShellInitParams; class ShellObserver; class ShutdownController; -class ShutdownObserver; class SmsObserver; class SplitViewController; class StickyKeysController; @@ -588,6 +588,9 @@ void Init(ui::ContextFactory* context_factory, ui::ContextFactoryPrivate* context_factory_private); + // Initializes the display manager and related components. + void InitializeDisplayManager(); + // Initializes the root window so that it can host browser windows. void InitRootWindow(aura::Window* root_window); @@ -745,7 +748,7 @@ std::unique_ptr<display::DisplayChangeObserver> display_change_observer_; // Listens for shutdown and updates DisplayConfigurator. - std::unique_ptr<ShutdownObserver> shutdown_observer_; + std::unique_ptr<DisplayShutdownObserver> display_shutdown_observer_; // Listens for new sms messages and shows notifications. std::unique_ptr<SmsObserver> sms_observer_;
diff --git a/ash/wallpaper/wallpaper_controller.cc b/ash/wallpaper/wallpaper_controller.cc index ea90e6a..dc235d01 100644 --- a/ash/wallpaper/wallpaper_controller.cc +++ b/ash/wallpaper/wallpaper_controller.cc
@@ -1075,15 +1075,18 @@ return EmptyAccountId(); } -void WallpaperController::SetClientAndPaths( +void WallpaperController::Init( mojom::WallpaperControllerClientPtr client, const base::FilePath& user_data_path, const base::FilePath& chromeos_wallpapers_path, - const base::FilePath& chromeos_custom_wallpapers_path) { + const base::FilePath& chromeos_custom_wallpapers_path, + bool is_device_wallpaper_policy_enforced) { + DCHECK(!wallpaper_controller_client_.get()); wallpaper_controller_client_ = std::move(client); dir_user_data_path_ = user_data_path; dir_chrome_os_wallpapers_path_ = chromeos_wallpapers_path; dir_chrome_os_custom_wallpapers_path_ = chromeos_custom_wallpapers_path; + SetDeviceWallpaperPolicyEnforced(is_device_wallpaper_policy_enforced); } void WallpaperController::SetCustomWallpaper( @@ -1263,10 +1266,12 @@ } void WallpaperController::ShowSigninWallpaper() { - current_user_.reset(); - // TODO(crbug.com/791654): Call |SetDeviceWallpaperIfApplicable| from here. - SetDefaultWallpaperImpl(EmptyAccountId(), user_manager::USER_TYPE_REGULAR, - true /*show_wallpaper=*/); + if (ShouldSetDevicePolicyWallpaper()) { + SetDevicePolicyWallpaper(); + } else { + SetDefaultWallpaperImpl(EmptyAccountId(), user_manager::USER_TYPE_REGULAR, + true /*show_wallpaper=*/); + } } void WallpaperController::RemoveUserWallpaper( @@ -1330,8 +1335,8 @@ void WallpaperController::SetClientForTesting( mojom::WallpaperControllerClientPtr client) { - SetClientAndPaths(std::move(client), base::FilePath(), base::FilePath(), - base::FilePath()); + Init(std::move(client), base::FilePath(), base::FilePath(), base::FilePath(), + false /*is_device_wallpaper_policy_enforced=*/); } void WallpaperController::FlushForTesting() {
diff --git a/ash/wallpaper/wallpaper_controller.h b/ash/wallpaper/wallpaper_controller.h index 325230c..7e5bc27 100644 --- a/ash/wallpaper/wallpaper_controller.h +++ b/ash/wallpaper/wallpaper_controller.h
@@ -377,11 +377,11 @@ AccountId GetCurrentUserAccountId(); // mojom::WallpaperController overrides: - void SetClientAndPaths( - mojom::WallpaperControllerClientPtr client, - const base::FilePath& user_data_path, - const base::FilePath& chromeos_wallpapers_path, - const base::FilePath& chromeos_custom_wallpapers_path) override; + void Init(mojom::WallpaperControllerClientPtr client, + const base::FilePath& user_data_path, + const base::FilePath& chromeos_wallpapers_path, + const base::FilePath& chromeos_custom_wallpapers_path, + bool is_device_wallpaper_policy_enforced) override; void SetCustomWallpaper(mojom::WallpaperUserInfoPtr user_info, const std::string& wallpaper_files_id, const std::string& file_name,
diff --git a/base/BUILD.gn b/base/BUILD.gn index 27697fc..0544de5 100644 --- a/base/BUILD.gn +++ b/base/BUILD.gn
@@ -2860,6 +2860,7 @@ "android/library_loader/library_loader_hooks.h", "memory/memory_pressure_listener.h", "metrics/histogram_base.h", + "trace_event/trace_config.h", ] }
diff --git a/base/android/java/src/org/chromium/base/BaseChromiumApplication.java b/base/android/java/src/org/chromium/base/BaseChromiumApplication.java index 9a1d3c2..649090b1e 100644 --- a/base/android/java/src/org/chromium/base/BaseChromiumApplication.java +++ b/base/android/java/src/org/chromium/base/BaseChromiumApplication.java
@@ -25,18 +25,6 @@ } } - /** Initializes the {@link CommandLine}. */ - public void initCommandLine() {} - - /** - * This must only be called for contexts whose application is a subclass of - * {@link BaseChromiumApplication}. - */ - @VisibleForTesting - public static void initCommandLine(Context context) { - ((BaseChromiumApplication) context.getApplicationContext()).initCommandLine(); - } - /** Ensure this application object is not out-of-date. */ private void checkAppBeingReplaced() { // During app update the old apk can still be triggered by broadcasts and spin up an
diff --git a/base/android/javatests/src/org/chromium/base/CommandLineInitUtilTest.java b/base/android/javatests/src/org/chromium/base/CommandLineInitUtilTest.java index 8aeede1..34b06d5 100644 --- a/base/android/javatests/src/org/chromium/base/CommandLineInitUtilTest.java +++ b/base/android/javatests/src/org/chromium/base/CommandLineInitUtilTest.java
@@ -13,6 +13,7 @@ import org.junit.Test; import org.junit.runner.RunWith; +import org.chromium.base.test.util.CommandLineFlags; import org.chromium.base.test.util.Feature; /** @@ -24,7 +25,7 @@ public void setUp() throws Exception { CommandLineInitUtil.initCommandLine( InstrumentationRegistry.getInstrumentation().getTargetContext(), - "content-shell-command-line"); + CommandLineFlags.getTestCmdLineFile()); } /**
diff --git a/base/message_loop/incoming_task_queue.cc b/base/message_loop/incoming_task_queue.cc index 941cbd8..f84b326 100644 --- a/base/message_loop/incoming_task_queue.cc +++ b/base/message_loop/incoming_task_queue.cc
@@ -85,11 +85,6 @@ return PostPendingTask(&pending_task); } -bool IncomingTaskQueue::IsIdleForTesting() { - AutoLock lock(incoming_queue_lock_); - return incoming_queue_.empty(); -} - void IncomingTaskQueue::WillDestroyCurrentMessageLoop() { { AutoLock auto_lock(incoming_queue_lock_); @@ -181,6 +176,7 @@ } void IncomingTaskQueue::TriageQueue::ReloadFromIncomingQueueIfEmpty() { + DCHECK_CALLED_ON_VALID_SEQUENCE(outer_->sequence_checker_); if (queue_.empty()) { // TODO(robliao): Since these high resolution tasks aren't yet in the // delayed queue, they technically shouldn't trigger high resolution timers @@ -351,6 +347,8 @@ } int IncomingTaskQueue::ReloadWorkQueue(TaskQueue* work_queue) { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + // Make sure no tasks are lost. DCHECK(work_queue->empty());
diff --git a/base/message_loop/incoming_task_queue.h b/base/message_loop/incoming_task_queue.h index 861f0fc..0a476365 100644 --- a/base/message_loop/incoming_task_queue.h +++ b/base/message_loop/incoming_task_queue.h
@@ -77,9 +77,6 @@ TimeDelta delay, Nestable nestable); - // Returns true if the message loop is "idle". Provided for testing. - bool IsIdleForTesting(); - // Disconnects |this| from the parent message loop. void WillDestroyCurrentMessageLoop(); @@ -109,8 +106,9 @@ // maintaining three queue queues to process tasks: // // TriageQueue - // The first queue to receive all tasks for the processing sequence. Tasks are - // generally either dispatched immediately or sent to the queues below. + // The first queue to receive all tasks for the processing sequence (when + // reloading from the thread-safe |incoming_queue_|). Tasks are generally + // either dispatched immediately or sent to the queues below. // // DelayedQueue // The queue for holding tasks that should be run later and sorted by expected @@ -242,7 +240,7 @@ // An incoming queue of tasks that are acquired under a mutex for processing // on this instance's thread. These tasks have not yet been been pushed to - // |message_loop_|. + // |triage_tasks_|. TaskQueue incoming_queue_; // True if new tasks should be accepted.
diff --git a/base/message_loop/message_loop.cc b/base/message_loop/message_loop.cc index 41c58bf..455a7d0 100644 --- a/base/message_loop/message_loop.cc +++ b/base/message_loop/message_loop.cc
@@ -258,9 +258,12 @@ } bool MessageLoop::IsIdleForTesting() { - // We only check the incoming queue, since we don't want to lock the work - // queue. - return incoming_task_queue_->IsIdleForTesting(); + return !incoming_task_queue_->triage_tasks().HasTasks() && + (!incoming_task_queue_->deferred_tasks().HasTasks() || + RunLoop::IsNestedOnCurrentThread()) && + (!incoming_task_queue_->delayed_tasks().HasTasks() || + incoming_task_queue_->delayed_tasks().Peek().delayed_run_time > + TimeTicks::Now()); } //------------------------------------------------------------------------------
diff --git a/base/message_loop/message_loop.h b/base/message_loop/message_loop.h index 46c7ab9..90715a0 100644 --- a/base/message_loop/message_loop.h +++ b/base/message_loop/message_loop.h
@@ -266,7 +266,10 @@ void AddTaskObserver(TaskObserver* task_observer); void RemoveTaskObserver(TaskObserver* task_observer); - // Returns true if the message loop is "idle". Provided for testing. + // Returns true if the message loop is idle (same condition which triggers + // RunLoop::RunUntilIdle() to return: i.e. out of tasks which can be processed + // at the current run-level -- there might be deferred non-nestable tasks + // remaining if currently in a nested run level). Provided for testing. bool IsIdleForTesting(); // Runs the specified PendingTask.
diff --git a/base/metrics/statistics_recorder.cc b/base/metrics/statistics_recorder.cc index 1215474..82d7a93 100644 --- a/base/metrics/statistics_recorder.cc +++ b/base/metrics/statistics_recorder.cc
@@ -20,9 +20,12 @@ #include "base/strings/stringprintf.h" #include "base/values.h" -namespace base { namespace { +// Initialize histogram statistics gathering system. +base::LazyInstance<base::StatisticsRecorder>::Leaky g_statistics_recorder_ = + LAZY_INSTANCE_INITIALIZER; + bool HistogramNameLesser(const base::HistogramBase* a, const base::HistogramBase* b) { return strcmp(a->histogram_name(), b->histogram_name()) < 0; @@ -30,14 +33,7 @@ } // namespace -// static -LazyInstance<Lock>::Leaky StatisticsRecorder::lock_; - -// static -StatisticsRecorder* StatisticsRecorder::top_ = nullptr; - -// static -bool StatisticsRecorder::is_vlog_initialized_ = false; +namespace base { size_t StatisticsRecorder::BucketRangesHash::operator()( const BucketRanges* const a) const { @@ -51,55 +47,67 @@ } StatisticsRecorder::~StatisticsRecorder() { - const AutoLock auto_lock(lock_.Get()); - DCHECK_EQ(this, top_); - top_ = previous_; + DCHECK(histograms_); + DCHECK(ranges_); + + // Clean out what this object created and then restore what existed before. + Reset(); + base::AutoLock auto_lock(lock_.Get()); + histograms_ = existing_histograms_.release(); + callbacks_ = existing_callbacks_.release(); + ranges_ = existing_ranges_.release(); + providers_ = existing_providers_.release(); + record_checker_ = existing_record_checker_.release(); } // static void StatisticsRecorder::Initialize() { - const AutoLock auto_lock(lock_.Get()); - if (top_) + // Tests sometimes create local StatisticsRecorders in order to provide a + // contained environment of histograms that can be later discarded. If a + // true global instance gets created in this environment then it will + // eventually get disconnected when the local instance destructs and + // restores the previous state, resulting in no StatisticsRecorder at all. + // The global lazy instance, however, will remain valid thus ensuring that + // another never gets installed via this method. If a |histograms_| map + // exists then assume the StatisticsRecorder is already "initialized". + if (histograms_) return; - const StatisticsRecorder* const p = new StatisticsRecorder; - // The global recorder is never deleted. - ANNOTATE_LEAKING_OBJECT_PTR(p); - DCHECK_EQ(p, top_); + // Ensure that an instance of the StatisticsRecorder object is created. + g_statistics_recorder_.Get(); } // static bool StatisticsRecorder::IsActive() { - const AutoLock auto_lock(lock_.Get()); - return top_ != nullptr; + base::AutoLock auto_lock(lock_.Get()); + return histograms_ != nullptr; } // static void StatisticsRecorder::RegisterHistogramProvider( const WeakPtr<HistogramProvider>& provider) { - const AutoLock auto_lock(lock_.Get()); - top_->providers_.push_back(provider); + providers_->push_back(provider); } // static HistogramBase* StatisticsRecorder::RegisterOrDeleteDuplicate( HistogramBase* histogram) { - // Declared before |auto_lock| to ensure correct destruction order. + // Declared before auto_lock to ensure correct destruction order. std::unique_ptr<HistogramBase> histogram_deleter; - const AutoLock auto_lock(lock_.Get()); + base::AutoLock auto_lock(lock_.Get()); - if (!top_) { + if (!histograms_) { // As per crbug.com/79322 the histograms are intentionally leaked, so we // need to annotate them. Because ANNOTATE_LEAKING_OBJECT_PTR may be used // only once for an object, the duplicates should not be annotated. // Callers are responsible for not calling RegisterOrDeleteDuplicate(ptr) - // twice |if (!top_)|. + // twice |if (!histograms_)|. ANNOTATE_LEAKING_OBJECT_PTR(histogram); // see crbug.com/79322 return histogram; } const char* const name = histogram->histogram_name(); - HistogramBase*& registered = top_->histograms_[name]; + HistogramBase*& registered = (*histograms_)[name]; if (!registered) { // |name| is guaranteed to never change or be deallocated so long @@ -108,8 +116,8 @@ ANNOTATE_LEAKING_OBJECT_PTR(histogram); // see crbug.com/79322 // If there are callbacks for this histogram, we set the kCallbackExists // flag. - const auto callback_iterator = top_->callbacks_.find(name); - if (callback_iterator != top_->callbacks_.end()) { + const auto callback_iterator = callbacks_->find(name); + if (callback_iterator != callbacks_->end()) { if (!callback_iterator->second.is_null()) histogram->SetFlags(HistogramBase::kCallbackExists); else @@ -133,16 +141,16 @@ const BucketRanges* ranges) { DCHECK(ranges->HasValidChecksum()); - // Declared before |auto_lock| to ensure correct destruction order. + // Declared before auto_lock to ensure correct destruction order. std::unique_ptr<const BucketRanges> ranges_deleter; - const AutoLock auto_lock(lock_.Get()); + base::AutoLock auto_lock(lock_.Get()); - if (!top_) { + if (!ranges_) { ANNOTATE_LEAKING_OBJECT_PTR(ranges); return ranges; } - const BucketRanges* const registered = *top_->ranges_.insert(ranges).first; + const BucketRanges* const registered = *ranges_->insert(ranges).first; if (registered == ranges) { ANNOTATE_LEAKING_OBJECT_PTR(ranges); } else { @@ -155,6 +163,9 @@ // static void StatisticsRecorder::WriteHTMLGraph(const std::string& query, std::string* output) { + if (!IsActive()) + return; + Histograms snapshot; GetSnapshot(query, &snapshot); std::sort(snapshot.begin(), snapshot.end(), &HistogramNameLesser); @@ -167,6 +178,8 @@ // static void StatisticsRecorder::WriteGraph(const std::string& query, std::string* output) { + if (!IsActive()) + return; if (query.length()) StringAppendF(output, "Collections of histograms for %s\n", query.c_str()); else @@ -183,6 +196,9 @@ // static std::string StatisticsRecorder::ToJSON(JSONVerbosityLevel verbosity_level) { + if (!IsActive()) + return std::string(); + Histograms snapshot; GetSnapshot(std::string(), &snapshot); @@ -201,11 +217,11 @@ // static void StatisticsRecorder::GetHistograms(Histograms* output) { - const AutoLock auto_lock(lock_.Get()); - if (!top_) + base::AutoLock auto_lock(lock_.Get()); + if (!histograms_) return; - for (const auto& entry : top_->histograms_) { + for (const auto& entry : *histograms_) { output->push_back(entry.second); } } @@ -213,11 +229,11 @@ // static void StatisticsRecorder::GetBucketRanges( std::vector<const BucketRanges*>* output) { - const AutoLock auto_lock(lock_.Get()); - if (!top_) + base::AutoLock auto_lock(lock_.Get()); + if (!ranges_) return; - for (const BucketRanges* const p : top_->ranges_) { + for (const BucketRanges* const p : *ranges_) { output->push_back(p); } } @@ -229,28 +245,21 @@ // will acquire the lock at that time. ImportGlobalPersistentHistograms(); - const AutoLock auto_lock(lock_.Get()); - if (!top_) + base::AutoLock auto_lock(lock_.Get()); + if (!histograms_) return nullptr; - const HistogramMap::const_iterator it = top_->histograms_.find(name); - return it != top_->histograms_.end() ? it->second : nullptr; -} - -// static -StatisticsRecorder::HistogramProviders -StatisticsRecorder::GetHistogramProviders() { - const AutoLock auto_lock(lock_.Get()); - if (!top_) - return {}; - - return top_->providers_; + const HistogramMap::const_iterator it = histograms_->find(name); + return it != histograms_->end() ? it->second : nullptr; } // static void StatisticsRecorder::ImportProvidedHistograms() { + if (!providers_) + return; + // Merge histogram data from each provider in turn. - for (const WeakPtr<HistogramProvider>& provider : GetHistogramProviders()) { + for (const WeakPtr<HistogramProvider>& provider : *providers_) { // Weak-pointer may be invalid if the provider was destructed, though they // generally never are. if (provider) @@ -274,8 +283,11 @@ // static void StatisticsRecorder::InitLogOnShutdown() { - const AutoLock auto_lock(lock_.Get()); - InitLogOnShutdownWhileLocked(); + if (!histograms_) + return; + + base::AutoLock auto_lock(lock_.Get()); + g_statistics_recorder_.Get().InitLogOnShutdownWithoutLock(); } // static @@ -286,14 +298,14 @@ // will acquire the lock at that time. ImportGlobalPersistentHistograms(); - const AutoLock auto_lock(lock_.Get()); - if (!top_) + base::AutoLock auto_lock(lock_.Get()); + if (!histograms_) return; // Need a c-string query for comparisons against c-string histogram name. const char* query_string = query.c_str(); - for (const auto& entry : top_->histograms_) { + for (const auto& entry : *histograms_) { if (strstr(entry.second->histogram_name(), query_string) != nullptr) snapshot->push_back(entry.second); } @@ -304,15 +316,15 @@ const std::string& name, const StatisticsRecorder::OnSampleCallback& cb) { DCHECK(!cb.is_null()); - const AutoLock auto_lock(lock_.Get()); - if (!top_) + base::AutoLock auto_lock(lock_.Get()); + if (!histograms_) return false; - if (!top_->callbacks_.insert({name, cb}).second) + if (!callbacks_->insert({name, cb}).second) return false; - const HistogramMap::const_iterator it = top_->histograms_.find(name); - if (it != top_->histograms_.end()) + const HistogramMap::const_iterator it = histograms_->find(name); + if (it != histograms_->end()) it->second->SetFlags(HistogramBase::kCallbackExists); return true; @@ -320,43 +332,42 @@ // static void StatisticsRecorder::ClearCallback(const std::string& name) { - const AutoLock auto_lock(lock_.Get()); - if (!top_) + base::AutoLock auto_lock(lock_.Get()); + if (!histograms_) return; - top_->callbacks_.erase(name); + callbacks_->erase(name); // We also clear the flag from the histogram (if it exists). - const HistogramMap::const_iterator it = top_->histograms_.find(name); - if (it != top_->histograms_.end()) + const HistogramMap::const_iterator it = histograms_->find(name); + if (it != histograms_->end()) it->second->ClearFlags(HistogramBase::kCallbackExists); } // static StatisticsRecorder::OnSampleCallback StatisticsRecorder::FindCallback( const std::string& name) { - const AutoLock auto_lock(lock_.Get()); - if (!top_) + base::AutoLock auto_lock(lock_.Get()); + if (!histograms_) return OnSampleCallback(); - const auto it = top_->callbacks_.find(name); - return it != top_->callbacks_.end() ? it->second : OnSampleCallback(); + const auto it = callbacks_->find(name); + return it != callbacks_->end() ? it->second : OnSampleCallback(); } // static size_t StatisticsRecorder::GetHistogramCount() { - const AutoLock auto_lock(lock_.Get()); - return top_ ? top_->histograms_.size() : 0; + base::AutoLock auto_lock(lock_.Get()); + return histograms_ ? histograms_->size() : 0; } // static void StatisticsRecorder::ForgetHistogramForTesting(base::StringPiece name) { - const AutoLock auto_lock(lock_.Get()); - if (!top_) + if (!histograms_) return; - const HistogramMap::iterator found = top_->histograms_.find(name); - if (found == top_->histograms_.end()) + const HistogramMap::iterator found = histograms_->find(name); + if (found == histograms_->end()) return; HistogramBase* const base = found->second; @@ -368,40 +379,53 @@ static_cast<Histogram*>(base)->bucket_ranges()->set_persistent_reference(0); } - top_->histograms_.erase(found); + histograms_->erase(found); } // static std::unique_ptr<StatisticsRecorder> StatisticsRecorder::CreateTemporaryForTesting() { - const AutoLock auto_lock(lock_.Get()); return WrapUnique(new StatisticsRecorder()); } // static +void StatisticsRecorder::UninitializeForTesting() { + // Stop now if it's never been initialized. + if (!histograms_) + return; + + // Get the global instance and destruct it. It's held in static memory so + // can't "delete" it; call the destructor explicitly. + DCHECK(g_statistics_recorder_.private_instance_); + g_statistics_recorder_.Get().~StatisticsRecorder(); + + // Now the ugly part. There's no official way to release a LazyInstance once + // created so it's necessary to clear out an internal variable which + // shouldn't be publicly visible but is for initialization reasons. + g_statistics_recorder_.private_instance_ = 0; +} + +// static void StatisticsRecorder::SetRecordChecker( std::unique_ptr<RecordHistogramChecker> record_checker) { - const AutoLock auto_lock(lock_.Get()); - top_->record_checker_ = std::move(record_checker); + record_checker_ = record_checker.release(); } // static bool StatisticsRecorder::ShouldRecordHistogram(uint64_t histogram_hash) { - const AutoLock auto_lock(lock_.Get()); - return !top_ || !top_->record_checker_ || - top_->record_checker_->ShouldRecord(histogram_hash); + return !record_checker_ || record_checker_->ShouldRecord(histogram_hash); } // static StatisticsRecorder::Histograms StatisticsRecorder::GetKnownHistograms( bool include_persistent) { Histograms known; - const AutoLock auto_lock(lock_.Get()); - if (!top_ || top_->histograms_.empty()) + base::AutoLock auto_lock(lock_.Get()); + if (!histograms_ || histograms_->empty()) return known; - known.reserve(top_->histograms_.size()); - for (const auto& h : top_->histograms_) { + known.reserve(histograms_->size()); + for (const auto& h : *histograms_) { if (include_persistent || (h.second->flags() & HistogramBase::kIsPersistent) == 0) known.push_back(h.second); @@ -412,6 +436,9 @@ // static void StatisticsRecorder::ImportGlobalPersistentHistograms() { + if (!histograms_) + return; + // Import histograms from known persistent storage. Histograms could have been // added by other processes and they must be fetched and recognized locally. // If the persistent memory segment is not shared between processes, this call @@ -424,24 +451,73 @@ // of main(), and hence it is not thread safe. It initializes globals to provide // support for all future calls. StatisticsRecorder::StatisticsRecorder() { - lock_.Get().AssertAcquired(); - previous_ = top_; - top_ = this; - InitLogOnShutdownWhileLocked(); + base::AutoLock auto_lock(lock_.Get()); + + existing_histograms_.reset(histograms_); + existing_callbacks_.reset(callbacks_); + existing_ranges_.reset(ranges_); + existing_providers_.reset(providers_); + existing_record_checker_.reset(record_checker_); + + histograms_ = new HistogramMap; + callbacks_ = new CallbackMap; + ranges_ = new RangesMap; + providers_ = new HistogramProviders; + record_checker_ = nullptr; + + InitLogOnShutdownWithoutLock(); +} + +void StatisticsRecorder::InitLogOnShutdownWithoutLock() { + if (!vlog_initialized_ && VLOG_IS_ON(1)) { + vlog_initialized_ = true; + AtExitManager::RegisterCallback(&DumpHistogramsToVlog, this); + } } // static -void StatisticsRecorder::InitLogOnShutdownWhileLocked() { - lock_.Get().AssertAcquired(); - if (!is_vlog_initialized_ && VLOG_IS_ON(1)) { - is_vlog_initialized_ = true; - const auto dump_to_vlog = [](void*) { - std::string output; - WriteGraph("", &output); - VLOG(1) << output; - }; - AtExitManager::RegisterCallback(dump_to_vlog, nullptr); - } +void StatisticsRecorder::Reset() { + // Declared before auto_lock to ensure correct destruction order. + std::unique_ptr<HistogramMap> histograms_deleter; + std::unique_ptr<CallbackMap> callbacks_deleter; + std::unique_ptr<RangesMap> ranges_deleter; + std::unique_ptr<HistogramProviders> providers_deleter; + std::unique_ptr<RecordHistogramChecker> record_checker_deleter; + base::AutoLock auto_lock(lock_.Get()); + histograms_deleter.reset(histograms_); + callbacks_deleter.reset(callbacks_); + ranges_deleter.reset(ranges_); + providers_deleter.reset(providers_); + record_checker_deleter.reset(record_checker_); + histograms_ = nullptr; + callbacks_ = nullptr; + ranges_ = nullptr; + providers_ = nullptr; + record_checker_ = nullptr; + + // We are going to leak the histograms and the ranges. } +// static +void StatisticsRecorder::DumpHistogramsToVlog(void* instance) { + std::string output; + StatisticsRecorder::WriteGraph(std::string(), &output); + VLOG(1) << output; +} + +// static +StatisticsRecorder::HistogramMap* StatisticsRecorder::histograms_ = nullptr; +// static +StatisticsRecorder::CallbackMap* StatisticsRecorder::callbacks_ = nullptr; +// static +StatisticsRecorder::RangesMap* StatisticsRecorder::ranges_ = nullptr; +// static +StatisticsRecorder::HistogramProviders* StatisticsRecorder::providers_ = + nullptr; +// static +RecordHistogramChecker* StatisticsRecorder::record_checker_ = nullptr; +// static +base::LazyInstance<base::Lock>::Leaky StatisticsRecorder::lock_ = + LAZY_INSTANCE_INITIALIZER; + } // namespace base
diff --git a/base/metrics/statistics_recorder.h b/base/metrics/statistics_recorder.h index 4af25812..25427fd 100644 --- a/base/metrics/statistics_recorder.h +++ b/base/metrics/statistics_recorder.h
@@ -34,18 +34,6 @@ class BucketRanges; class HistogramSnapshotManager; -// In-memory recorder of usage statistics (aka metrics, aka histograms). -// -// Most of the methods are static and act on a global recorder. This global -// recorder must first be initialized using Initialize() before being used. This -// global recorder is internally synchronized and all the static methods are -// thread safe. -// -// StatisticsRecorder doesn't have any public constructor. For testing purpose, -// you can create a temporary recorder using the factory method -// CreateTemporaryForTesting(). This temporary recorder becomes the global one -// until deleted. When this temporary recorder is deleted, it restores the -// previous global one. class BASE_EXPORT StatisticsRecorder { public: // An interface class that allows the StatisticsRecorder to forcibly merge @@ -58,83 +46,58 @@ typedef std::vector<HistogramBase*> Histograms; - // Restores the previous global recorder. - // - // When several temporary recorders are created using - // CreateTemporaryForTesting(), these recorders must be deleted in reverse - // order of creation. - // - // This method is thread safe. - // - // Precondition: The recorder being deleted is the current global recorder. ~StatisticsRecorder(); - // Initializes the global recorder. Safe to call multiple times. - // - // This method is thread safe. + // Initializes the StatisticsRecorder system. Safe to call multiple times. static void Initialize(); - // Finds out if histograms can now be registered into our list. - // - // This method is thread safe. + // Find out if histograms can now be registered into our list. static bool IsActive(); - // Registers a provider of histograms that can be called to merge those into - // the global recorder. Calls to ImportProvidedHistograms() will fetch from - // registered providers. - // - // This method is thread safe. + // Register a provider of histograms that can be called to merge those into + // the global StatisticsRecorder. Calls to ImportProvidedHistograms() will + // fetch from registered providers. static void RegisterHistogramProvider( const WeakPtr<HistogramProvider>& provider); - // Registers or adds a new histogram to the collection of statistics. If an + // Register, or add a new histogram to the collection of statistics. If an // identically named histogram is already registered, then the argument - // |histogram| will be deleted. The returned value is always the registered + // |histogram| will deleted. The returned value is always the registered // histogram (either the argument, or the pre-existing registered histogram). - // - // This method is thread safe. static HistogramBase* RegisterOrDeleteDuplicate(HistogramBase* histogram); - // Registers or adds a new BucketRanges. If an equivalent BucketRanges is - // already registered, then the argument |ranges| will be deleted. The - // returned value is always the registered BucketRanges (either the argument, - // or the pre-existing one). - // - // This method is thread safe. + // Register, or add a new BucketRanges. If an identically BucketRanges is + // already registered, then the argument |ranges| will deleted. The returned + // value is always the registered BucketRanges (either the argument, or the + // pre-existing one). static const BucketRanges* RegisterOrDeleteDuplicateRanges( const BucketRanges* ranges); // Methods for appending histogram data to a string. Only histograms which // have |query| as a substring are written to |output| (an empty string will // process all registered histograms). - // - // These methods are thread safe. static void WriteHTMLGraph(const std::string& query, std::string* output); static void WriteGraph(const std::string& query, std::string* output); // Returns the histograms with |verbosity_level| as the serialization // verbosity. - // - // This method is thread safe. static std::string ToJSON(JSONVerbosityLevel verbosity_level); - // Extracts histograms which were marked for use by UMA. + // Method for extracting histograms which were marked for use by UMA. // // This method is thread safe. static void GetHistograms(Histograms* output); - // Extracts BucketRanges used by all histograms registered. + // Method for extracting BucketRanges used by all histograms registered. static void GetBucketRanges(std::vector<const BucketRanges*>* output); - // Finds a histogram by name. Matches the exact name. Returns a null pointer - // if a matching histogram is not found. + // Find a histogram by name. It matches the exact name. + // It returns NULL if a matching histogram is not found. // // This method is thread safe. static HistogramBase* FindHistogram(base::StringPiece name); - // Imports histograms from providers. - // - // This method must be called on the UI thread. + // Imports histograms from providers. This must be called on the UI thread. static void ImportProvidedHistograms(); // Snapshots all histograms via |snapshot_manager|. |flags_to_set| is used to @@ -147,81 +110,71 @@ HistogramBase::Flags required_flags, HistogramSnapshotManager* snapshot_manager); - // Extracts registered histograms. Only histograms which have |query| as a - // substring are extracted. An empty query will extract all registered - // histograms. + // GetSnapshot copies some of the pointers to registered histograms into the + // caller supplied vector (Histograms). Only histograms which have |query| as + // a substring are copied (an empty string will process all registered + // histograms). // // This method is thread safe. static void GetSnapshot(const std::string& query, Histograms* snapshot); typedef base::Callback<void(HistogramBase::Sample)> OnSampleCallback; - // Sets the callback to notify when a new sample is recorded on the histogram - // referred to by |histogram_name|. Can be called before or after the - // histogram is created. Returns whether the callback was successfully set. - // - // This method is thread safe. + // SetCallback sets the callback to notify when a new sample is recorded on + // the histogram referred to by |histogram_name|. The call to this method can + // be be done before or after the histogram is created. This method is thread + // safe. The return value is whether or not the callback was successfully set. static bool SetCallback(const std::string& histogram_name, const OnSampleCallback& callback); - // Clears any callback set on the histogram referred to by |histogram_name|. - // - // This method is thread safe. + // ClearCallback clears any callback set on the histogram referred to by + // |histogram_name|. This method is thread safe. static void ClearCallback(const std::string& histogram_name); - // Retrieves the callback for the histogram referred to by |histogram_name|, - // or a null callback if no callback exists for this histogram. - // - // This method is thread safe. + // FindCallback retrieves the callback for the histogram referred to by + // |histogram_name|, or a null callback if no callback exists for this + // histogram. This method is thread safe. static OnSampleCallback FindCallback(const std::string& histogram_name); // Returns the number of known histograms. - // - // This method is thread safe. static size_t GetHistogramCount(); // Initializes logging histograms with --v=1. Safe to call multiple times. // Is called from ctor but for browser it seems that it is more useful to // start logging after statistics recorder, so we need to init log-on-shutdown // later. - // - // This method is thread safe. static void InitLogOnShutdown(); // Removes a histogram from the internal set of known ones. This can be // necessary during testing persistent histograms where the underlying // memory is being released. - // - // This method is thread safe. static void ForgetHistogramForTesting(base::StringPiece name); - // Creates a temporary StatisticsRecorder object for testing purposes. All new - // histograms will be registered in it until it is destructed or pushed aside - // for the lifetime of yet another StatisticsRecorder object. The destruction - // of the returned object will re-activate the previous one. - // StatisticsRecorder objects must be deleted in the opposite order to which - // they're created. - // - // This method is thread safe. + // Creates a local StatisticsRecorder object for testing purposes. All new + // histograms will be registered in it until it is destructed or pushed + // aside for the lifetime of yet another SR object. The destruction of the + // returned object will re-activate the previous one. Always release SR + // objects in the opposite order to which they're created. static std::unique_ptr<StatisticsRecorder> CreateTemporaryForTesting() WARN_UNUSED_RESULT; + // Resets any global instance of the statistics-recorder that was created + // by a call to Initialize(). + static void UninitializeForTesting(); + // Sets the record checker for determining if a histogram should be recorded. // Record checker doesn't affect any already recorded histograms, so this // method must be called very early, before any threads have started. // Record checker methods can be called on any thread, so they shouldn't // mutate any state. - // // TODO(iburak): This is not yet hooked up to histogram recording // infrastructure. static void SetRecordChecker( std::unique_ptr<RecordHistogramChecker> record_checker); - // Checks if the given histogram should be recorded based on the - // ShouldRecord() method of the record checker. If the record checker is not - // set, returns true. - // - // This method is thread safe. + // Returns true iff the given histogram should be recorded based on + // the ShouldRecord() method of the record checker. + // If the record checker is not set, returns true. static bool ShouldRecordHistogram(uint64_t histogram_hash); private: @@ -246,57 +199,52 @@ unordered_set<const BucketRanges*, BucketRangesHash, BucketRangesEqual> RangesMap; + friend struct LazyInstanceTraitsBase<StatisticsRecorder>; friend class StatisticsRecorderTest; FRIEND_TEST_ALL_PREFIXES(StatisticsRecorderTest, IterationTest); - // Fetches set of existing histograms. Ownership of the individual histograms + // Fetch set of existing histograms. Ownership of the individual histograms // remains with the StatisticsRecorder. - // - // This method is thread safe. static Histograms GetKnownHistograms(bool include_persistent); - // Gets histogram providers. - // - // This method is thread safe. - static HistogramProviders GetHistogramProviders(); - - // Imports histograms from global persistent memory. - // - // Precondition: The global lock must not be held during this call. + // Imports histograms from global persistent memory. The global lock must + // not be held during this call. static void ImportGlobalPersistentHistograms(); - // Constructs a new StatisticsRecorder and sets it as the current global - // recorder. - // - // Precondition: The global lock is already acquired. + // The constructor just initializes static members. Usually client code should + // use Initialize to do this. But in test code, you can friend this class and + // call the constructor to get a clean StatisticsRecorder. StatisticsRecorder(); // Initialize implementation but without lock. Caller should guard // StatisticsRecorder by itself if needed (it isn't in unit tests). - // - // Precondition: The global lock is already acquired. - static void InitLogOnShutdownWhileLocked(); + void InitLogOnShutdownWithoutLock(); - HistogramMap histograms_; - CallbackMap callbacks_; - RangesMap ranges_; - HistogramProviders providers_; - std::unique_ptr<RecordHistogramChecker> record_checker_; + // These are copies of everything that existed when the (test) Statistics- + // Recorder was created. The global ones have to be moved aside to create a + // clean environment. + std::unique_ptr<HistogramMap> existing_histograms_; + std::unique_ptr<CallbackMap> existing_callbacks_; + std::unique_ptr<RangesMap> existing_ranges_; + std::unique_ptr<HistogramProviders> existing_providers_; + std::unique_ptr<RecordHistogramChecker> existing_record_checker_; - // Previous global recorder that existed when this one was created. - StatisticsRecorder* previous_ = nullptr; + bool vlog_initialized_ = false; - // Global lock for internal synchronization. - static LazyInstance<Lock>::Leaky lock_; + static void Reset(); + static void DumpHistogramsToVlog(void* instance); - // Current global recorder. This recorder is used by static methods. When a - // new global recorder is created by CreateTemporaryForTesting(), then the - // previous global recorder is referenced by top_->previous_. - static StatisticsRecorder* top_; + static HistogramMap* histograms_; + static CallbackMap* callbacks_; + static RangesMap* ranges_; + static HistogramProviders* providers_; + static RecordHistogramChecker* record_checker_; - // Tracks whether InitLogOnShutdownWhileLocked() has registered a logging - // function that will be called when the program finishes. - static bool is_vlog_initialized_; + // Lock protects access to above maps. This is a LazyInstance to avoid races + // when the above methods are used before Initialize(). Previously each method + // would do |if (!lock_) return;| which would race with + // |lock_ = new Lock;| in StatisticsRecorder(). http://crbug.com/672852. + static base::LazyInstance<base::Lock>::Leaky lock_; DISALLOW_COPY_AND_ASSIGN(StatisticsRecorder); };
diff --git a/base/metrics/statistics_recorder_unittest.cc b/base/metrics/statistics_recorder_unittest.cc index ada0523..92d1bba6 100644 --- a/base/metrics/statistics_recorder_unittest.cc +++ b/base/metrics/statistics_recorder_unittest.cc
@@ -30,7 +30,9 @@ public: LogStateSaver() : old_min_log_level_(logging::GetMinLogLevel()) {} - ~LogStateSaver() { logging::SetMinLogLevel(old_min_log_level_); } + ~LogStateSaver() { + logging::SetMinLogLevel(old_min_log_level_); + } private: int old_min_log_level_; @@ -68,8 +70,8 @@ // Use persistent memory for histograms if so indicated by test parameter. if (use_persistent_histogram_allocator_) { - GlobalHistogramAllocator::CreateWithLocalMemory(kAllocatorMemorySize, 0, - "StatisticsRecorderTest"); + GlobalHistogramAllocator::CreateWithLocalMemory( + kAllocatorMemorySize, 0, "StatisticsRecorderTest"); } } @@ -80,10 +82,14 @@ void InitializeStatisticsRecorder() { DCHECK(!statistics_recorder_); + StatisticsRecorder::UninitializeForTesting(); statistics_recorder_ = StatisticsRecorder::CreateTemporaryForTesting(); } - void UninitializeStatisticsRecorder() { statistics_recorder_.reset(); } + void UninitializeStatisticsRecorder() { + statistics_recorder_.reset(); + StatisticsRecorder::UninitializeForTesting(); + } Histogram* CreateHistogram(const char* name, HistogramBase::Sample min, @@ -96,15 +102,18 @@ return new Histogram(name, min, max, registered_ranges); } - void DeleteHistogram(HistogramBase* histogram) { delete histogram; } + void DeleteHistogram(HistogramBase* histogram) { + delete histogram; + } - void InitLogOnShutdown() { StatisticsRecorder::InitLogOnShutdown(); } + void InitLogOnShutdown() { + DCHECK(statistics_recorder_); + statistics_recorder_->InitLogOnShutdownWithoutLock(); + } - bool IsVLogInitialized() { return StatisticsRecorder::is_vlog_initialized_; } - - void ResetVLogInitialized() { - UninitializeStatisticsRecorder(); - StatisticsRecorder::is_vlog_initialized_ = false; + bool VLogInitialized() { + DCHECK(statistics_recorder_); + return statistics_recorder_->vlog_initialized_; } const bool use_persistent_histogram_allocator_; @@ -268,8 +277,8 @@ ASSERT_EQ(0u, registered_histograms.size()); // Create a histogram. - HistogramBase* histogram = Histogram::FactoryGet("TestHistogram", 1, 1000, 10, - HistogramBase::kNoFlags); + HistogramBase* histogram = Histogram::FactoryGet( + "TestHistogram", 1, 1000, 10, HistogramBase::kNoFlags); registered_histograms.clear(); StatisticsRecorder::GetHistograms(®istered_histograms); EXPECT_EQ(1u, registered_histograms.size()); @@ -283,15 +292,15 @@ EXPECT_EQ(histogram, histogram2); // Create a LinearHistogram. - histogram = LinearHistogram::FactoryGet("TestLinearHistogram", 1, 1000, 10, - HistogramBase::kNoFlags); + histogram = LinearHistogram::FactoryGet( + "TestLinearHistogram", 1, 1000, 10, HistogramBase::kNoFlags); registered_histograms.clear(); StatisticsRecorder::GetHistograms(®istered_histograms); EXPECT_EQ(2u, registered_histograms.size()); // Create a BooleanHistogram. - histogram = BooleanHistogram::FactoryGet("TestBooleanHistogram", - HistogramBase::kNoFlags); + histogram = BooleanHistogram::FactoryGet( + "TestBooleanHistogram", HistogramBase::kNoFlags); registered_histograms.clear(); StatisticsRecorder::GetHistograms(®istered_histograms); EXPECT_EQ(3u, registered_histograms.size()); @@ -300,8 +309,8 @@ std::vector<int> custom_ranges; custom_ranges.push_back(1); custom_ranges.push_back(5); - histogram = CustomHistogram::FactoryGet("TestCustomHistogram", custom_ranges, - HistogramBase::kNoFlags); + histogram = CustomHistogram::FactoryGet( + "TestCustomHistogram", custom_ranges, HistogramBase::kNoFlags); registered_histograms.clear(); StatisticsRecorder::GetHistograms(®istered_histograms); EXPECT_EQ(4u, registered_histograms.size()); @@ -615,33 +624,33 @@ } TEST_P(StatisticsRecorderTest, LogOnShutdownNotInitialized) { - ResetVLogInitialized(); + UninitializeStatisticsRecorder(); logging::SetMinLogLevel(logging::LOG_WARNING); InitializeStatisticsRecorder(); EXPECT_FALSE(VLOG_IS_ON(1)); - EXPECT_FALSE(IsVLogInitialized()); + EXPECT_FALSE(VLogInitialized()); InitLogOnShutdown(); - EXPECT_FALSE(IsVLogInitialized()); + EXPECT_FALSE(VLogInitialized()); } TEST_P(StatisticsRecorderTest, LogOnShutdownInitializedExplicitly) { - ResetVLogInitialized(); + UninitializeStatisticsRecorder(); logging::SetMinLogLevel(logging::LOG_WARNING); InitializeStatisticsRecorder(); EXPECT_FALSE(VLOG_IS_ON(1)); - EXPECT_FALSE(IsVLogInitialized()); + EXPECT_FALSE(VLogInitialized()); logging::SetMinLogLevel(logging::LOG_VERBOSE); EXPECT_TRUE(VLOG_IS_ON(1)); InitLogOnShutdown(); - EXPECT_TRUE(IsVLogInitialized()); + EXPECT_TRUE(VLogInitialized()); } TEST_P(StatisticsRecorderTest, LogOnShutdownInitialized) { - ResetVLogInitialized(); + UninitializeStatisticsRecorder(); logging::SetMinLogLevel(logging::LOG_VERBOSE); InitializeStatisticsRecorder(); EXPECT_TRUE(VLOG_IS_ON(1)); - EXPECT_TRUE(IsVLogInitialized()); + EXPECT_TRUE(VLogInitialized()); } class TestHistogramProvider : public StatisticsRecorder::HistogramProvider {
diff --git a/base/optional.h b/base/optional.h index fbc62893..7e039c6f 100644 --- a/base/optional.h +++ b/base/optional.h
@@ -134,7 +134,7 @@ template <class... Args> void Init(Args&&... args) { DCHECK(storage_.is_null_); - new (&storage_.value_) T(std::forward<Args>(args)...); + ::new (&storage_.value_) T(std::forward<Args>(args)...); storage_.is_null_ = false; }
diff --git a/base/optional_unittest.cc b/base/optional_unittest.cc index 479424d6..60347d5e 100644 --- a/base/optional_unittest.cc +++ b/base/optional_unittest.cc
@@ -104,6 +104,25 @@ ~NonTriviallyDestructible() {} }; +class DeletedDefaultConstructor { + public: + DeletedDefaultConstructor() = delete; + DeletedDefaultConstructor(int foo) : foo_(foo) {} + + int foo() const { return foo_; } + + private: + int foo_; +}; + +class DeleteNewOperators { + public: + void* operator new(size_t) = delete; + void* operator new(size_t, void*) = delete; + void* operator new[](size_t) = delete; + void* operator new[](size_t, void*) = delete; +}; + } // anonymous namespace static_assert(std::is_trivially_destructible<Optional<int>>::value, @@ -1535,4 +1554,21 @@ EXPECT_EQ(1, a->move_ctors_count()); } +TEST(OptionalTest, DontCallDefaultCtor) { + Optional<DeletedDefaultConstructor> a; + EXPECT_FALSE(a.has_value()); + + a = base::make_optional<DeletedDefaultConstructor>(42); + EXPECT_TRUE(a.has_value()); + EXPECT_EQ(42, a->foo()); +} + +TEST(OptionalTest, DontCallNewMemberFunction) { + Optional<DeleteNewOperators> a; + EXPECT_FALSE(a.has_value()); + + a = DeleteNewOperators(); + EXPECT_TRUE(a.has_value()); +} + } // namespace base
diff --git a/base/strings/string_number_conversions.cc b/base/strings/string_number_conversions.cc index 5b133d4..46c229a 100644 --- a/base/strings/string_number_conversions.cc +++ b/base/strings/string_number_conversions.cc
@@ -284,23 +284,6 @@ typedef BaseHexIteratorRangeToUInt64Traits<StringPiece::const_iterator> HexIteratorRangeToUInt64Traits; -template <typename STR> -bool HexStringToBytesT(const STR& input, std::vector<uint8_t>* output) { - DCHECK_EQ(output->size(), 0u); - size_t count = input.size(); - if (count == 0 || (count % 2) != 0) - return false; - for (uintptr_t i = 0; i < count / 2; ++i) { - uint8_t msb = 0; // most significant 4 bits - uint8_t lsb = 0; // least significant 4 bits - if (!CharToDigit<16>(input[i * 2], &msb) || - !CharToDigit<16>(input[i * 2 + 1], &lsb)) - return false; - output->push_back((msb << 4) | lsb); - } - return true; -} - template <typename VALUE, int BASE> class StringPieceToNumberTraits : public BaseIteratorRangeToNumberTraits<StringPiece::const_iterator, @@ -498,8 +481,21 @@ input.begin(), input.end(), output); } -bool HexStringToBytes(const std::string& input, std::vector<uint8_t>* output) { - return HexStringToBytesT(input, output); +bool HexStringToBytes(const StringPiece& input, std::vector<uint8_t>* output) { + DCHECK_EQ(output->size(), 0u); + size_t count = input.size(); + if (count == 0 || (count % 2) != 0) + return false; + for (uintptr_t i = 0; i < count / 2; ++i) { + uint8_t msb = 0; // most significant 4 bits + uint8_t lsb = 0; // least significant 4 bits + if (!CharToDigit<16>(input[i * 2], &msb) || + !CharToDigit<16>(input[i * 2 + 1], &lsb)) { + return false; + } + output->push_back((msb << 4) | lsb); + } + return true; } } // namespace base
diff --git a/base/strings/string_number_conversions.h b/base/strings/string_number_conversions.h index f334b308..798ce2f 100644 --- a/base/strings/string_number_conversions.h +++ b/base/strings/string_number_conversions.h
@@ -158,7 +158,7 @@ // |*output| will contain as many bytes as were successfully parsed prior to the // error. There is no overflow, but input.size() must be evenly divisible by 2. // Leading 0x or +/- are not allowed. -BASE_EXPORT bool HexStringToBytes(const std::string& input, +BASE_EXPORT bool HexStringToBytes(const StringPiece& input, std::vector<uint8_t>* output); } // namespace base
diff --git a/base/task_scheduler/task_tracker.cc b/base/task_scheduler/task_tracker.cc index ca03f7f..2069f4d 100644 --- a/base/task_scheduler/task_tracker.cc +++ b/base/task_scheduler/task_tracker.cc
@@ -477,8 +477,8 @@ } #endif -int TaskTracker::GetNumIncompleteUndelayedTasksForTesting() const { - return subtle::NoBarrier_Load(&num_incomplete_undelayed_tasks_); +bool TaskTracker::HasIncompleteUndelayedTasksForTesting() const { + return subtle::Acquire_Load(&num_incomplete_undelayed_tasks_) != 0; } bool TaskTracker::BeforePostTask(TaskShutdownBehavior shutdown_behavior) {
diff --git a/base/task_scheduler/task_tracker.h b/base/task_scheduler/task_tracker.h index f1ef25c..d425027 100644 --- a/base/task_scheduler/task_tracker.h +++ b/base/task_scheduler/task_tracker.h
@@ -164,9 +164,10 @@ virtual bool IsPostingBlockShutdownTaskAfterShutdownAllowed(); #endif - // Returns the number of undelayed tasks that haven't completed their - // execution (still queued or in progress). - int GetNumIncompleteUndelayedTasksForTesting() const; + // Returns true if there are undelayed tasks that haven't completed their + // execution (still queued or in progress). If it returns false: the side- + // effects of all completed tasks are guaranteed to be visible to the caller. + bool HasIncompleteUndelayedTasksForTesting() const; private: class State;
diff --git a/base/test/android/javatests/src/org/chromium/base/test/util/CommandLineFlags.java b/base/test/android/javatests/src/org/chromium/base/test/util/CommandLineFlags.java index 353f72b..edbcbbbf 100644 --- a/base/test/android/javatests/src/org/chromium/base/test/util/CommandLineFlags.java +++ b/base/test/android/javatests/src/org/chromium/base/test/util/CommandLineFlags.java
@@ -10,8 +10,8 @@ import org.junit.Assert; import org.junit.Rule; -import org.chromium.base.BaseChromiumApplication; import org.chromium.base.CommandLine; +import org.chromium.base.CommandLineInitUtil; import org.chromium.base.test.BaseTestResult.PreTestHook; import java.lang.annotation.ElementType; @@ -91,7 +91,7 @@ public static void setUp(Context targetContext, AnnotatedElement element) { Assert.assertNotNull("Unable to get a non-null target context.", targetContext); CommandLine.reset(); - BaseChromiumApplication.initCommandLine(targetContext); + CommandLineInitUtil.initCommandLine(targetContext, getTestCmdLineFile()); Set<String> enableFeatures = new HashSet<String>(); Set<String> disableFeatures = new HashSet<String>(); Set<String> flags = getFlags(element); @@ -189,4 +189,8 @@ }; } + + public static String getTestCmdLineFile() { + return "test-cmdline-file"; + } }
diff --git a/base/test/scoped_task_environment.cc b/base/test/scoped_task_environment.cc index a9fe5ac..e93ad5b 100644 --- a/base/test/scoped_task_environment.cc +++ b/base/test/scoped_task_environment.cc
@@ -209,10 +209,10 @@ // the above logic as it'd then be possible for a TaskScheduler task to be // running during the DisallowRunTasks() test, causing it to fail, but then // post to the main thread and complete before the loop's condition is - // verified which could result in GetNumIncompleteUndelayedTasksForTesting() - // returning 0 and the loop erroneously exiting with a pending task on the - // main thread. - if (task_tracker_->GetNumIncompleteUndelayedTasksForTesting() == 0) + // verified which could result in HasIncompleteUndelayedTasksForTesting() + // returning false and the loop erroneously exiting with a pending task on + // the main thread. + if (!task_tracker_->HasIncompleteUndelayedTasksForTesting()) break; }
diff --git a/base/trace_event/trace_config.h b/base/trace_event/trace_config.h index 2e7f6c0..5460489 100644 --- a/base/trace_event/trace_config.h +++ b/base/trace_event/trace_config.h
@@ -26,6 +26,8 @@ class ConvertableToTraceFormat; // Options determines how the trace buffer stores data. +// A Java counterpart will be generated for this enum. +// GENERATED_JAVA_ENUM_PACKAGE: org.chromium.base enum TraceRecordMode { // Record until the trace buffer is full. RECORD_UNTIL_FULL,
diff --git a/build/android/pylib/local/device/local_device_instrumentation_test_run.py b/build/android/pylib/local/device/local_device_instrumentation_test_run.py index f079468c..f2ff5e27 100644 --- a/build/android/pylib/local/device/local_device_instrumentation_test_run.py +++ b/build/android/pylib/local/device/local_device_instrumentation_test_run.py
@@ -241,15 +241,10 @@ @trace_event.traced def create_flag_changer(dev): if self._test_instance.flags: - if not self._test_instance.package_info: - logging.error("Couldn't set flags: no package info") - elif not self._test_instance.package_info.cmdline_file: - logging.error("Couldn't set flags: no cmdline_file") - else: - self._CreateFlagChangerIfNeeded(dev) - logging.debug('Attempting to set flags: %r', - self._test_instance.flags) - self._flag_changers[str(dev)].AddFlags(self._test_instance.flags) + self._CreateFlagChangerIfNeeded(dev) + logging.debug('Attempting to set flags: %r', + self._test_instance.flags) + self._flag_changers[str(dev)].AddFlags(self._test_instance.flags) valgrind_tools.SetChromeTimeoutScale( dev, self._test_instance.timeout_scale) @@ -328,7 +323,7 @@ def _CreateFlagChangerIfNeeded(self, device): if not str(device) in self._flag_changers: self._flag_changers[str(device)] = flag_changer.FlagChanger( - device, self._test_instance.package_info.cmdline_file) + device, "test-cmdline-file") #override def _CreateShards(self, tests):
diff --git a/build/android/pylib/results/presentation/test_results_presentation.py b/build/android/pylib/results/presentation/test_results_presentation.py index cb3f1ae..21137fe 100755 --- a/build/android/pylib/results/presentation/test_results_presentation.py +++ b/build/android/pylib/results/presentation/test_results_presentation.py
@@ -386,6 +386,10 @@ '(Output of the swarming.py collect ' '--task-summary-json=XXX command.)') parser.add_argument( + '--task-output-dir', + help='(Swarming Merge Script API) ' + 'Directory containing all swarming task results.') + parser.add_argument( 'positional', nargs='*', help='output.json from shards.')
diff --git a/build/android/pylib/symbols/stack_symbolizer.py b/build/android/pylib/symbols/stack_symbolizer.py index c1c9afbb..05e40657 100644 --- a/build/android/pylib/symbols/stack_symbolizer.py +++ b/build/android/pylib/symbols/stack_symbolizer.py
@@ -7,6 +7,7 @@ import re import shutil import tempfile +import time import zipfile from devil.utils import cmd_helper @@ -38,6 +39,7 @@ self._libs_dir = None self._apk_libs = [] self._has_unzipped = False + self._time_spent_symbolizing = 0 def __del__(self): @@ -52,6 +54,9 @@ if self._libs_dir: shutil.rmtree(self._libs_dir) self._libs_dir = None + if self._time_spent_symbolizing > 0: + logging.info( + 'Total time spent symbolizing: %.2fs', self._time_spent_symbolizing) def UnzipAPKIfNecessary(self): @@ -97,7 +102,11 @@ with tempfile.NamedTemporaryFile() as f: f.write('\n'.join(data_to_symbolize)) f.flush() - _, output = cmd_helper.GetCmdStatusAndOutput(cmd + [f.name], env=env) + start = time.time() + try: + _, output = cmd_helper.GetCmdStatusAndOutput(cmd + [f.name], env=env) + finally: + self._time_spent_symbolizing += time.time() - start for line in output.splitlines(): if not include_stack and 'Stack Data:' in line: break
diff --git a/build/cipd/android/android.ensure b/build/cipd/android/android.ensure index 9a2c705c..cee2bf1 100644 --- a/build/cipd/android/android.ensure +++ b/build/cipd/android/android.ensure
@@ -135,3 +135,10 @@ @Subdir third_party/xstream chromium/third_party/xstream version:1.4.8-cr0 +# Three unchanging lines +# avoid the horror that is +# endless merge conflicts + +@Subdir chrome/android/profiles +chromium/afdo/profiles/android version:3309 +
diff --git a/build/config/BUILDCONFIG.gn b/build/config/BUILDCONFIG.gn index b8d515426..853c849 100644 --- a/build/config/BUILDCONFIG.gn +++ b/build/config/BUILDCONFIG.gn
@@ -525,6 +525,9 @@ "//build/config/compiler:default_optimization", "//build/config/compiler:default_stack_frames", "//build/config/compiler:default_symbols", + + # TODO(crbug.com/795158): Remove once libwidevinecdmadapter.so is fixed. + "//build/config/compiler:default_fatal_linker_warnings", "//build/config/compiler:no_exceptions", "//build/config/compiler:no_rtti", "//build/config/compiler:runtime_library",
diff --git a/build/config/compiler/BUILD.gn b/build/config/compiler/BUILD.gn index a894a39..5154ead 100644 --- a/build/config/compiler/BUILD.gn +++ b/build/config/compiler/BUILD.gn
@@ -265,16 +265,6 @@ cflags += [ "-fstack-protector" ] } } - - # Linker warnings. - if (fatal_linker_warnings && !(is_chromeos && current_cpu == "arm") && - !(is_android && use_order_profiling) && !is_mac && !is_ios && - current_os != "aix") { - # TODO(jochen): Enable this on chromeos on arm. http://crbug.com/356580 - # TODO(lizeb,pasko): Fix link errors when linking with order_profiling=1 - # crbug.com/485542 - ldflags += [ "-Wl,--fatal-warnings" ] - } } # Eliminate build metadata (__DATE__, __TIME__ and __TIMESTAMP__) for @@ -2050,3 +2040,19 @@ cflags_objcc = common_flags } } + +# Default linker warnings. +config("default_fatal_linker_warnings") { + ldflags = [] + + # Linker warnings. + if (!is_win && fatal_linker_warnings && + !(is_chromeos && current_cpu == "arm") && + !(is_android && use_order_profiling) && !is_mac && !is_ios && + current_os != "aix") { + # TODO(jochen): Enable this on chromeos on arm. http://crbug.com/356580 + # TODO(lizeb,pasko): Fix link errors when linking with order_profiling=1 + # crbug.com/485542 + ldflags += [ "-Wl,--fatal-warnings" ] + } +}
diff --git a/build/fuchsia/runner_common.py b/build/fuchsia/runner_common.py index 7c7f2c6..bb8eaad7 100755 --- a/build/fuchsia/runner_common.py +++ b/build/fuchsia/runner_common.py
@@ -146,8 +146,9 @@ symbols_mapping[os.path.basename(target)] = source symbols_mapping[target] = source - if dry_run: - print 'Symbols:', binary_name, '->', symbols_mapping[target] + if dry_run: + for target, path in symbols_mapping.iteritems(): + print 'Symbols:', target, '->', path return symbols_mapping
diff --git a/build/toolchain/toolchain.gni b/build/toolchain/toolchain.gni index ebb98fe..949aa09f 100644 --- a/build/toolchain/toolchain.gni +++ b/build/toolchain/toolchain.gni
@@ -48,7 +48,12 @@ declare_args() { if (is_clang) { # Clang compiler version. Clang files are placed at version-dependent paths. - clang_version = "6.0.0" + if (llvm_force_head_revision) { + clang_version = "7.0.0" + } else { + # TODO(hans): Trunk was updated; remove after the next roll. + clang_version = "6.0.0" + } } }
diff --git a/cc/BUILD.gn b/cc/BUILD.gn index f7e50d1..300b84b 100644 --- a/cc/BUILD.gn +++ b/cc/BUILD.gn
@@ -241,6 +241,8 @@ "tiles/raster_tile_priority_queue_required.h", "tiles/software_image_decode_cache.cc", "tiles/software_image_decode_cache.h", + "tiles/software_image_decode_cache_utils.cc", + "tiles/software_image_decode_cache_utils.h", "tiles/tile.cc", "tiles/tile.h", "tiles/tile_draw_info.cc",
diff --git a/cc/resources/video_resource_updater.cc b/cc/resources/video_resource_updater.cc index dac835d..5036233 100644 --- a/cc/resources/video_resource_updater.cc +++ b/cc/resources/video_resource_updater.cc
@@ -486,21 +486,20 @@ // The |resource_size_pixels| is the size of the resource we want to // upload to. - gfx::Size resource_size_pixels = plane_resource.resource_size(); + const gfx::Size resource_size_pixels = plane_resource.resource_size(); // The |video_stride_bytes| is the width of the video frame we are // uploading (including non-frame data to fill in the stride). - int video_stride_bytes = video_frame->stride(i); + const int video_stride_bytes = video_frame->stride(i); - size_t bytes_per_row = ResourceUtil::CheckedWidthInBytes<size_t>( + const size_t bytes_per_row = ResourceUtil::CheckedWidthInBytes<size_t>( resource_size_pixels.width(), plane_resource.resource_format()); // Use 4-byte row alignment (OpenGL default) for upload performance. // Assuming that GL_UNPACK_ALIGNMENT has not changed from default. - size_t upload_image_stride = + const size_t upload_image_stride = MathUtil::CheckedRoundUp<size_t>(bytes_per_row, 4u); // R16_EXT can represent 16-bit int, so we don't need a conversion step. bool needs_conversion = false; - int shift = 0; // viz::LUMINANCE_F16 uses half-floats, so we always need a conversion // step. @@ -511,7 +510,6 @@ // If bits_per_channel > 8 and we can't use viz::LUMINANCE_F16 or // R16_EXT we need to shift the data down and create an 8-bit texture. needs_conversion = true; - shift = bits_per_channel - 8; } const uint8_t* pixels; if (static_cast<int>(upload_image_stride) == video_stride_bytes && @@ -519,35 +517,35 @@ pixels = video_frame->data(i); } else { // Avoid malloc for each frame/plane if possible. - size_t needed_size = + const size_t needed_size = upload_image_stride * resource_size_pixels.height(); if (upload_pixels_.size() < needed_size) upload_pixels_.resize(needed_size); - for (int row = 0; row < resource_size_pixels.height(); ++row) { - if (plane_resource.resource_format() == viz::LUMINANCE_F16) { + if (plane_resource.resource_format() == viz::LUMINANCE_F16) { + for (int row = 0; row < resource_size_pixels.height(); ++row) { uint16_t* dst = reinterpret_cast<uint16_t*>( &upload_pixels_[upload_image_stride * row]); const uint16_t* src = reinterpret_cast<uint16_t*>( video_frame->data(i) + (video_stride_bytes * row)); half_float_maker->MakeHalfFloats(src, bytes_per_row / 2, dst); - } else if (shift != 0) { - // We have more-than-8-bit input which we need to shift - // down to fit it into an 8-bit texture. - uint8_t* dst = &upload_pixels_[upload_image_stride * row]; - const uint16_t* src = reinterpret_cast<uint16_t*>( - video_frame->data(i) + (video_stride_bytes * row)); - for (size_t i = 0; i < bytes_per_row; i++) - dst[i] = src[i] >> shift; - } else { - // Input and output are the same size and format, but - // differ in stride, copy one row at a time. - uint8_t* dst = &upload_pixels_[upload_image_stride * row]; - const uint8_t* src = - video_frame->data(i) + (video_stride_bytes * row); - memcpy(dst, src, bytes_per_row); } + } else if (bits_per_channel > 8) { + const int scale = 0x10000 >> (bits_per_channel - 8); + libyuv::Convert16To8Plane( + reinterpret_cast<uint16_t*>(video_frame->data(i)), + video_stride_bytes / 2, upload_pixels_.data(), + upload_image_stride, scale, bytes_per_row, + resource_size_pixels.height()); + } else { + // Make a copy because input and output are the same size and + // format, but differ in stride. + libyuv::CopyPlane(video_frame->data(i), video_stride_bytes, + upload_pixels_.data(), upload_image_stride, + resource_size_pixels.width(), + resource_size_pixels.height()); } + pixels = &upload_pixels_[0]; }
diff --git a/cc/test/layer_tree_pixel_test.cc b/cc/test/layer_tree_pixel_test.cc index eb7e641..e246ede7 100644 --- a/cc/test/layer_tree_pixel_test.cc +++ b/cc/test/layer_tree_pixel_test.cc
@@ -54,12 +54,16 @@ bool synchronous_composite = !HasImplThread() && !layer_tree_host()->GetSettings().single_thread_proxy_scheduler; + viz::RendererSettings test_settings = renderer_settings; + // Keep texture sizes exactly matching the bounds of the RenderPass to avoid + // floating point badness in texcoords. + test_settings.dont_round_texture_sizes_for_pixel_tests = true; auto delegating_output_surface = std::make_unique<viz::TestLayerTreeFrameSink>( compositor_context_provider, worker_context_provider, - shared_bitmap_manager(), gpu_memory_buffer_manager(), - renderer_settings, ImplThreadTaskRunner(), synchronous_composite, - disable_display_vsync, refresh_rate); + shared_bitmap_manager(), gpu_memory_buffer_manager(), test_settings, + ImplThreadTaskRunner(), synchronous_composite, disable_display_vsync, + refresh_rate); delegating_output_surface->SetEnlargePassTextureAmount( enlarge_texture_amount_); return delegating_output_surface;
diff --git a/cc/test/pixel_test.cc b/cc/test/pixel_test.cc index 3c974b7..8d3e23e4 100644 --- a/cc/test/pixel_test.cc +++ b/cc/test/pixel_test.cc
@@ -36,7 +36,11 @@ PixelTest::PixelTest() : device_viewport_size_(gfx::Size(200, 200)), disable_picture_quad_image_filtering_(false), - output_surface_client_(new FakeOutputSurfaceClient) {} + output_surface_client_(new FakeOutputSurfaceClient) { + // Keep texture sizes exactly matching the bounds of the RenderPass to avoid + // floating point badness in texcoords. + renderer_settings_.dont_round_texture_sizes_for_pixel_tests = true; +} PixelTest::~PixelTest() = default;
diff --git a/cc/tiles/decoded_image_tracker_unittest.cc b/cc/tiles/decoded_image_tracker_unittest.cc index 6f409f9e..f5bb5a37 100644 --- a/cc/tiles/decoded_image_tracker_unittest.cc +++ b/cc/tiles/decoded_image_tracker_unittest.cc
@@ -21,8 +21,10 @@ void UnlockImageDecode(ImageDecodeRequestId id) override { auto it = std::find_if( locked_ids_.begin(), locked_ids_.end(), - [id](const std::pair<const ImageDecodeRequestId, ImageDecodeCacheKey>& - item) { return item.first == id; }); + [id](const std::pair<const ImageDecodeRequestId, + SoftwareImageDecodeCache::CacheKey>& item) { + return item.first == id; + }); ASSERT_FALSE(it == locked_ids_.end()); locked_ids_.erase(it); } @@ -31,27 +33,32 @@ const DrawImage& image, const ImageDecodedCallback& callback) override { auto id = next_id_++; - locked_ids_.insert(std::make_pair( - id, ImageDecodeCacheKey::FromDrawImage(image, kRGBA_8888_SkColorType))); + locked_ids_.insert( + std::make_pair(id, SoftwareImageDecodeCache::CacheKey::FromDrawImage( + image, kRGBA_8888_SkColorType))); callback.Run(id, ImageDecodeResult::SUCCESS); return id; } bool IsDrawImageLocked(const DrawImage& image) { - ImageDecodeCacheKey key = - ImageDecodeCacheKey::FromDrawImage(image, kRGBA_8888_SkColorType); - return std::find_if(locked_ids_.begin(), locked_ids_.end(), - [&key](const std::pair<const ImageDecodeRequestId, - ImageDecodeCacheKey>& item) { - return item.second == key; - }) != locked_ids_.end(); + SoftwareImageDecodeCache::CacheKey key = + SoftwareImageDecodeCache::CacheKey::FromDrawImage( + image, kRGBA_8888_SkColorType); + return std::find_if( + locked_ids_.begin(), locked_ids_.end(), + [&key]( + const std::pair<const ImageDecodeRequestId, + SoftwareImageDecodeCache::CacheKey>& item) { + return item.second == key; + }) != locked_ids_.end(); } size_t num_locked_images() { return locked_ids_.size(); } private: ImageDecodeRequestId next_id_ = 1; - std::unordered_map<ImageDecodeRequestId, ImageDecodeCacheKey> locked_ids_; + std::unordered_map<ImageDecodeRequestId, SoftwareImageDecodeCache::CacheKey> + locked_ids_; }; class DecodedImageTrackerTest : public testing::Test {
diff --git a/cc/tiles/software_image_decode_cache.cc b/cc/tiles/software_image_decode_cache.cc index 6c5df401..765d94a 100644 --- a/cc/tiles/software_image_decode_cache.cc +++ b/cc/tiles/software_image_decode_cache.cc
@@ -4,28 +4,18 @@ #include "cc/tiles/software_image_decode_cache.h" -#include <inttypes.h> #include <stdint.h> -#include <algorithm> -#include <functional> - #include "base/format_macros.h" #include "base/macros.h" -#include "base/memory/discardable_memory.h" #include "base/memory/memory_coordinator_client_registry.h" -#include "base/memory/ptr_util.h" #include "base/metrics/histogram_macros.h" #include "base/strings/stringprintf.h" -#include "base/threading/thread_task_runner_handle.h" #include "base/trace_event/memory_dump_manager.h" #include "cc/base/devtools_instrumentation.h" #include "cc/base/histograms.h" #include "cc/raster/tile_task.h" #include "cc/tiles/mipmap_util.h" -#include "third_party/skia/include/core/SkCanvas.h" -#include "third_party/skia/include/core/SkImage.h" -#include "third_party/skia/include/core/SkPixmap.h" #include "ui/gfx/skia_util.h" using base::trace_event::MemoryAllocatorDump; @@ -42,42 +32,28 @@ const size_t kThrottledMaxItemsInCacheForSoftware = 100; const size_t kSuspendedMaxItemsInCacheForSoftware = 0; -// If the size of the original sized image breaches kMemoryRatioToSubrect but we -// don't need to scale the image, consider caching only the needed subrect. -// The second part that much be true is that we cache only the needed subrect if -// the total size needed for the subrect is at most kMemoryRatioToSubrect * -// (size needed for the full original image). -// Note that at least one of the dimensions has to be at least -// kMinDimensionToSubrect before an image can breach the threshold. -const size_t kMemoryThresholdToSubrect = 64 * 1024 * 1024; -const int kMinDimensionToSubrect = 4 * 1024; -const float kMemoryRatioToSubrect = 0.5f; - -// Tracing ID sequence for use in CacheEntry. -base::AtomicSequenceNumber g_next_tracing_id_; - class AutoRemoveKeyFromTaskMap { public: AutoRemoveKeyFromTaskMap( - std::unordered_map<SoftwareImageDecodeCache::ImageKey, + std::unordered_map<SoftwareImageDecodeCache::CacheKey, scoped_refptr<TileTask>, - SoftwareImageDecodeCache::ImageKeyHash>* task_map, - const SoftwareImageDecodeCache::ImageKey& key) + SoftwareImageDecodeCache::CacheKeyHash>* task_map, + const SoftwareImageDecodeCache::CacheKey& key) : task_map_(task_map), key_(key) {} ~AutoRemoveKeyFromTaskMap() { task_map_->erase(key_); } private: - std::unordered_map<SoftwareImageDecodeCache::ImageKey, + std::unordered_map<SoftwareImageDecodeCache::CacheKey, scoped_refptr<TileTask>, - SoftwareImageDecodeCache::ImageKeyHash>* task_map_; - const SoftwareImageDecodeCache::ImageKey& key_; + SoftwareImageDecodeCache::CacheKeyHash>* task_map_; + const SoftwareImageDecodeCache::CacheKey& key_; }; class SoftwareImageDecodeTaskImpl : public TileTask { public: SoftwareImageDecodeTaskImpl( SoftwareImageDecodeCache* cache, - const SoftwareImageDecodeCache::ImageKey& image_key, + const SoftwareImageDecodeCache::CacheKey& image_key, const PaintImage& paint_image, SoftwareImageDecodeCache::DecodeTaskType task_type, const ImageDecodeCache::TracingInfo& tracing_info) @@ -110,7 +86,7 @@ private: SoftwareImageDecodeCache* cache_; - SoftwareImageDecodeCache::ImageKey image_key_; + SoftwareImageDecodeCache::CacheKey image_key_; PaintImage paint_image_; SoftwareImageDecodeCache::DecodeTaskType task_type_; const ImageDecodeCache::TracingInfo tracing_info_; @@ -118,10 +94,10 @@ DISALLOW_COPY_AND_ASSIGN(SoftwareImageDecodeTaskImpl); }; -SkSize GetScaleAdjustment(const ImageDecodeCacheKey& key) { +SkSize GetScaleAdjustment(const SoftwareImageDecodeCache::CacheKey& key) { // If the requested filter quality did not require scale, then the adjustment // is identity. - if (key.type() != ImageDecodeCacheKey::kSubrectAndScale) { + if (key.type() != SoftwareImageDecodeCache::CacheKey::kSubrectAndScale) { return SkSize::Make(1.f, 1.f); } else { return MipMapUtil::GetScaleAdjustmentForSize(key.src_rect().size(), @@ -136,16 +112,12 @@ // to do a bilinear interpolation. The exception to this is if the developer // specified a pixelated effect, which results in a None filter quality (nearest // neighbor). -SkFilterQuality GetDecodedFilterQuality(const ImageDecodeCacheKey& key) { +SkFilterQuality GetDecodedFilterQuality( + const SoftwareImageDecodeCache::CacheKey& key) { return key.is_nearest_neighbor() ? kNone_SkFilterQuality : kLow_SkFilterQuality; } -SkImageInfo CreateImageInfo(const SkISize& size, SkColorType color_type) { - return SkImageInfo::Make(size.width(), size.height(), color_type, - kPremul_SkAlphaType); -} - void RecordLockExistingCachedImageHistogram(TilePriority::PriorityBin bin, bool success) { switch (bin) { @@ -161,24 +133,6 @@ } } -gfx::Rect GetSrcRect(const DrawImage& image) { - const SkIRect& src_rect = image.src_rect(); - int x = std::max(0, src_rect.x()); - int y = std::max(0, src_rect.y()); - int right = std::min(image.paint_image().width(), src_rect.right()); - int bottom = std::min(image.paint_image().height(), src_rect.bottom()); - if (x >= right || y >= bottom) - return gfx::Rect(); - return gfx::Rect(x, y, right - x, bottom - y); -} - -std::unique_ptr<base::DiscardableMemory> AllocateDiscardable( - const SkImageInfo& info) { - TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("cc.debug"), "AllocateDiscardable"); - return base::DiscardableMemoryAllocator::GetInstance() - ->AllocateLockedDiscardableMemory(info.minRowBytes() * info.height()); -} - } // namespace SoftwareImageDecodeCache::SoftwareImageDecodeCache( @@ -239,7 +193,7 @@ const DrawImage& image, const TracingInfo& tracing_info, DecodeTaskType task_type) { - ImageKey key = ImageKey::FromDrawImage(image, color_type_); + CacheKey key = CacheKey::FromDrawImage(image, color_type_); TRACE_EVENT1(TRACE_DISABLED_BY_DEFAULT("cc.debug"), "SoftwareImageDecodeCache::GetTaskForImageAndRefInternal", "key", key.ToString()); @@ -301,7 +255,7 @@ return TaskResult(task); } -void SoftwareImageDecodeCache::AddBudgetForImage(const ImageKey& key, +void SoftwareImageDecodeCache::AddBudgetForImage(const CacheKey& key, CacheEntry* entry) { TRACE_EVENT1(TRACE_DISABLED_BY_DEFAULT("cc.debug"), "SoftwareImageDecodeCache::AddBudgetForImage", "key", @@ -314,7 +268,7 @@ entry->is_budgeted = true; } -void SoftwareImageDecodeCache::RemoveBudgetForImage(const ImageKey& key, +void SoftwareImageDecodeCache::RemoveBudgetForImage(const CacheKey& key, CacheEntry* entry) { TRACE_EVENT1(TRACE_DISABLED_BY_DEFAULT("cc.debug"), "SoftwareImageDecodeCache::RemoveBudgetForImage", "key", @@ -327,7 +281,7 @@ } void SoftwareImageDecodeCache::UnrefImage(const DrawImage& image) { - const ImageKey& key = ImageKey::FromDrawImage(image, color_type_); + const CacheKey& key = CacheKey::FromDrawImage(image, color_type_); TRACE_EVENT1(TRACE_DISABLED_BY_DEFAULT("cc.debug"), "SoftwareImageDecodeCache::UnrefImage", "key", key.ToString()); @@ -335,7 +289,7 @@ UnrefImage(key); } -void SoftwareImageDecodeCache::UnrefImage(const ImageKey& key) { +void SoftwareImageDecodeCache::UnrefImage(const CacheKey& key) { lock_.AssertAcquired(); auto decoded_image_it = decoded_images_.Peek(key); DCHECK(decoded_image_it != decoded_images_.end()); @@ -349,7 +303,7 @@ } } -void SoftwareImageDecodeCache::DecodeImageInTask(const ImageKey& key, +void SoftwareImageDecodeCache::DecodeImageInTask(const CacheKey& key, const PaintImage& paint_image, DecodeTaskType task_type) { TRACE_EVENT1("cc", "SoftwareImageDecodeCache::DecodeImageInTask", "key", @@ -372,7 +326,7 @@ } void SoftwareImageDecodeCache::DecodeImageIfNecessary( - const ImageKey& key, + const CacheKey& key, const PaintImage& paint_image, CacheEntry* entry) { TRACE_EVENT1(TRACE_DISABLED_BY_DEFAULT("cc.debug"), @@ -401,13 +355,13 @@ std::unique_ptr<CacheEntry> local_cache_entry; // If we can use the original decode, we'll definitely need a decode. - if (key.type() == ImageDecodeCacheKey::kOriginal) { + if (key.type() == CacheKey::kOriginal) { base::AutoUnlock release(lock_); - local_cache_entry = DoDecodeImage(key, paint_image); + local_cache_entry = Utils::DoDecodeImage(key, paint_image, color_type_); } else { // Use the full image decode to generate a scaled/subrected decode. // TODO(vmpstr): This part needs to handle decode to scale. - base::Optional<ImageKey> candidate_key; + base::Optional<CacheKey> candidate_key; auto image_keys_it = frame_key_to_image_keys_.find(key.frame_key()); // We know that we must have at least our own |entry| in this list, so it // won't be empty. @@ -415,7 +369,7 @@ auto& available_keys = image_keys_it->second; std::sort(available_keys.begin(), available_keys.end(), - [](const ImageKey& one, const ImageKey& two) { + [](const CacheKey& one, const CacheKey& two) { // Return true if |one| scale is less than |two| scale. return one.target_size().width() < two.target_size().width() && one.target_size().height() < two.target_size().height(); @@ -458,14 +412,14 @@ // This way the GenerateCacheEntryFromCandidate() function will simply // extract the subset and be done with it. auto src_rect = - key.type() == ImageDecodeCacheKey::kSubrectOriginal + key.type() == CacheKey::kSubrectOriginal ? SkIRect::MakeWH(paint_image.width(), paint_image.height()) : gfx::RectToSkIRect(key.src_rect()); DrawImage candidate_draw_image( paint_image, src_rect, kNone_SkFilterQuality, SkMatrix::I(), key.frame_key().frame_index(), key.target_color_space()); candidate_key.emplace( - ImageKey::FromDrawImage(candidate_draw_image, color_type_)); + CacheKey::FromDrawImage(candidate_draw_image, color_type_)); } CHECK(*candidate_key != key) << key.ToString(); @@ -479,9 +433,9 @@ // If the candidate could have used the original decode, that means we // need to extractSubset from it. In all other cases, this would have // already been done to generate the candidate. - local_cache_entry = GenerateCacheEntryFromCandidate( - key, decoded_draw_image, - candidate_key->type() == ImageDecodeCacheKey::kOriginal); + local_cache_entry = Utils::GenerateCacheEntryFromCandidate( + key, decoded_draw_image, candidate_key->type() == CacheKey::kOriginal, + color_type_); } // Unref to balance the GetDecodedImageForDrawInternal() call. @@ -510,100 +464,16 @@ } } -std::unique_ptr<SoftwareImageDecodeCache::CacheEntry> -SoftwareImageDecodeCache::DoDecodeImage(const ImageKey& key, - const PaintImage& paint_image) { - SkISize target_size = - SkISize::Make(key.target_size().width(), key.target_size().height()); - DCHECK(target_size == paint_image.GetSupportedDecodeSize(target_size)); - - SkImageInfo target_info = CreateImageInfo(target_size, color_type_); - std::unique_ptr<base::DiscardableMemory> target_pixels = - AllocateDiscardable(target_info); - DCHECK(target_pixels); - - TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("cc.debug"), - "SoftwareImageDecodeCache::DoDecodeImage - " - "decode"); - DCHECK_EQ(key.type(), ImageDecodeCacheKey::kOriginal); - bool result = paint_image.Decode(target_pixels->data(), &target_info, - key.target_color_space().ToSkColorSpace(), - key.frame_key().frame_index()); - if (!result) { - target_pixels->Unlock(); - return nullptr; - } - return std::make_unique<CacheEntry>(target_info, std::move(target_pixels), - SkSize::Make(0, 0)); -} - -std::unique_ptr<SoftwareImageDecodeCache::CacheEntry> -SoftwareImageDecodeCache::GenerateCacheEntryFromCandidate( - const ImageKey& key, - const DecodedDrawImage& candidate_image, - bool needs_extract_subset) { - SkISize target_size = - SkISize::Make(key.target_size().width(), key.target_size().height()); - SkImageInfo target_info = CreateImageInfo(target_size, color_type_); - std::unique_ptr<base::DiscardableMemory> target_pixels = - AllocateDiscardable(target_info); - DCHECK(target_pixels); - - if (key.type() == ImageDecodeCacheKey::kSubrectOriginal) { - DCHECK(needs_extract_subset); - TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("cc.debug"), - "SoftwareImageDecodeCache::GenerateCacheEntryFromCandidate - " - "subrect"); - bool result = candidate_image.image()->readPixels( - target_info, target_pixels->data(), target_info.minRowBytes(), - key.src_rect().x(), key.src_rect().y(), SkImage::kDisallow_CachingHint); - // We have a decoded image, and we're reading into already allocated memory. - // This should never fail. - DCHECK(result) << key.ToString(); - return std::make_unique<CacheEntry>( - target_info.makeColorSpace(candidate_image.image()->refColorSpace()), - std::move(target_pixels), - SkSize::Make(-key.src_rect().x(), -key.src_rect().y())); - } - - DCHECK_EQ(key.type(), ImageDecodeCacheKey::kSubrectAndScale); - TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("cc.debug"), - "SoftwareImageDecodeCache::GenerateCacheEntryFromCandidate - " - "scale"); - SkPixmap decoded_pixmap; - // We don't need to subrect this image, since all candidates passed in would - // already have a src_rect applied to them. - bool result = candidate_image.image()->peekPixels(&decoded_pixmap); - DCHECK(result) << key.ToString(); - if (needs_extract_subset) { - result = decoded_pixmap.extractSubset(&decoded_pixmap, - gfx::RectToSkIRect(key.src_rect())); - DCHECK(result) << key.ToString(); - } - - // Nearest neighbor would only be set in the unscaled case. - DCHECK(!key.is_nearest_neighbor()); - SkPixmap target_pixmap(target_info, target_pixels->data(), - target_info.minRowBytes()); - // Always use medium quality for scaling. - result = decoded_pixmap.scalePixels(target_pixmap, kMedium_SkFilterQuality); - DCHECK(result) << key.ToString(); - return std::make_unique<CacheEntry>( - target_info.makeColorSpace(candidate_image.image()->refColorSpace()), - std::move(target_pixels), - SkSize::Make(-key.src_rect().x(), -key.src_rect().y())); -} - DecodedDrawImage SoftwareImageDecodeCache::GetDecodedImageForDraw( const DrawImage& draw_image) { base::AutoLock hold(lock_); return GetDecodedImageForDrawInternal( - ImageKey::FromDrawImage(draw_image, color_type_), + CacheKey::FromDrawImage(draw_image, color_type_), draw_image.paint_image()); } DecodedDrawImage SoftwareImageDecodeCache::GetDecodedImageForDrawInternal( - const ImageKey& key, + const CacheKey& key, const PaintImage& paint_image) { TRACE_EVENT1(TRACE_DISABLED_BY_DEFAULT("cc.debug"), "SoftwareImageDecodeCache::GetDecodedImageForDrawInternal", @@ -633,7 +503,7 @@ const DecodedDrawImage& decoded_image) { TRACE_EVENT1(TRACE_DISABLED_BY_DEFAULT("cc.debug"), "SoftwareImageDecodeCache::DrawWithImageFinished", "key", - ImageKey::FromDrawImage(image, color_type_).ToString()); + CacheKey::FromDrawImage(image, color_type_).ToString()); UnrefImage(image); } @@ -649,7 +519,7 @@ continue; } - const ImageKey& key = it->first; + const CacheKey& key = it->first; auto vector_it = frame_key_to_image_keys_.find(key.frame_key()); auto item_it = std::find(vector_it->second.begin(), vector_it->second.end(), key); @@ -685,7 +555,7 @@ return; for (auto key_it = it->second.begin(); key_it != it->second.end();) { - // This iterates over the ImageKey vector for the given skimage_id, + // This iterates over the CacheKey vector for the given skimage_id, // and deletes all entries from decoded_images_ corresponding to the // skimage_id. auto image_it = decoded_images_.Peek(*key_it); @@ -702,7 +572,7 @@ } void SoftwareImageDecodeCache::OnImageDecodeTaskCompleted( - const ImageKey& key, + const CacheKey& key, DecodeTaskType task_type) { base::AutoLock hold(lock_); @@ -786,7 +656,7 @@ } SoftwareImageDecodeCache::CacheEntry* SoftwareImageDecodeCache::AddCacheEntry( - const ImageKey& key) { + const CacheKey& key) { lock_.AssertAcquired(); frame_key_to_image_keys_[key.frame_key()].push_back(key); auto it = decoded_images_.Put(key, std::make_unique<CacheEntry>()); @@ -794,270 +664,6 @@ return it->second.get(); } -// SoftwareImageDecodeCacheKey ------------------------------------------------- -// static -ImageDecodeCacheKey ImageDecodeCacheKey::FromDrawImage(const DrawImage& image, - SkColorType color_type) { - const PaintImage::FrameKey frame_key = image.frame_key(); - - const SkSize& scale = image.scale(); - // If the src_rect falls outside of the image, we need to clip it since - // otherwise we might end up with uninitialized memory in the decode process. - // Note that the scale is still unchanged and the target size is now a - // function of the new src_rect. - const gfx::Rect& src_rect = GetSrcRect(image); - - // Start with the exact target size. However, this will be adjusted below to - // be either a mip level, the original size, or a subrect size. This is done - // to keep memory accounting correct. - gfx::Size target_size( - SkScalarRoundToInt(std::abs(src_rect.width() * scale.width())), - SkScalarRoundToInt(std::abs(src_rect.height() * scale.height()))); - - // If the target size is empty, then we'll be skipping the decode anyway, so - // the filter quality doesn't matter. Early out instead. - if (target_size.IsEmpty()) { - return ImageDecodeCacheKey(frame_key, kOriginal, false, src_rect, - target_size, image.target_color_space()); - } - - ProcessingType type = kOriginal; - bool is_nearest_neighbor = image.filter_quality() == kNone_SkFilterQuality; - int mip_level = MipMapUtil::GetLevelForSize(src_rect.size(), target_size); - // If any of the following conditions hold, then use at most low filter - // quality and adjust the target size to match the original image: - // - Quality is none: We need a pixelated image, so we can't upgrade it. - // - Format is 4444: Skia doesn't support scaling these, so use low - // filter quality. - // - Mip level is 0: The required mip is the original image, so just use low - // filter quality. - // - Matrix is not decomposable: There's perspective on this image and we - // can't determine the size, so use the original. - if (is_nearest_neighbor || color_type == kARGB_4444_SkColorType || - mip_level == 0 || !image.matrix_is_decomposable()) { - type = kOriginal; - // Update the size to be the original image size. - target_size = - gfx::Size(image.paint_image().width(), image.paint_image().height()); - } else { - type = kSubrectAndScale; - // Update the target size to be a mip level size. - // TODO(vmpstr): MipMapUtil and JPEG decoders disagree on what to do with - // odd sizes. If width = 2k + 1, and the mip level is 1, then this will - // return width = k; JPEG decoder, however, will support decoding to width = - // k + 1. We need to figure out what to do in this case. - SkSize mip_scale_adjustment = - MipMapUtil::GetScaleAdjustmentForLevel(src_rect.size(), mip_level); - target_size.set_width(src_rect.width() * mip_scale_adjustment.width()); - target_size.set_height(src_rect.height() * mip_scale_adjustment.height()); - } - - // If the original image is large, we might want to do a subrect instead if - // the subrect would be kMemoryRatioToSubrect times smaller. - if (type == kOriginal && - (image.paint_image().width() >= kMinDimensionToSubrect || - image.paint_image().height() >= kMinDimensionToSubrect)) { - base::CheckedNumeric<size_t> checked_original_size = 4u; - checked_original_size *= image.paint_image().width(); - checked_original_size *= image.paint_image().height(); - size_t original_size = checked_original_size.ValueOrDefault( - std::numeric_limits<size_t>::max()); - - base::CheckedNumeric<size_t> checked_src_rect_size = 4u; - checked_src_rect_size *= src_rect.width(); - checked_src_rect_size *= src_rect.height(); - size_t src_rect_size = checked_src_rect_size.ValueOrDefault( - std::numeric_limits<size_t>::max()); - - // If the sizes are such that we get good savings by subrecting, then do - // that. Also update the target size to be the src rect size since that's - // the rect we want to use. - if (original_size > kMemoryThresholdToSubrect && - src_rect_size <= original_size * kMemoryRatioToSubrect) { - type = kSubrectOriginal; - target_size = src_rect.size(); - } - } - - return ImageDecodeCacheKey(frame_key, type, is_nearest_neighbor, src_rect, - target_size, image.target_color_space()); -} - -ImageDecodeCacheKey::ImageDecodeCacheKey( - PaintImage::FrameKey frame_key, - ProcessingType type, - bool is_nearest_neighbor, - const gfx::Rect& src_rect, - const gfx::Size& target_size, - const gfx::ColorSpace& target_color_space) - : frame_key_(frame_key), - type_(type), - is_nearest_neighbor_(is_nearest_neighbor), - src_rect_(src_rect), - target_size_(target_size), - target_color_space_(target_color_space) { - if (type == kOriginal) { - hash_ = frame_key_.hash(); - } else { - // TODO(vmpstr): This is a mess. Maybe it's faster to just search the vector - // always (forwards or backwards to account for LRU). - uint64_t src_rect_hash = base::HashInts( - static_cast<uint64_t>(base::HashInts(src_rect_.x(), src_rect_.y())), - static_cast<uint64_t>( - base::HashInts(src_rect_.width(), src_rect_.height()))); - - uint64_t target_size_hash = - base::HashInts(target_size_.width(), target_size_.height()); - - hash_ = base::HashInts(base::HashInts(src_rect_hash, target_size_hash), - frame_key_.hash()); - } - // Include the target color space in the hash regardless of scaling. - hash_ = base::HashInts(hash_, target_color_space.GetHash()); -} - -ImageDecodeCacheKey::ImageDecodeCacheKey(const ImageDecodeCacheKey& other) = - default; - -std::string ImageDecodeCacheKey::ToString() const { - std::ostringstream str; - str << "frame_key[" << frame_key_.ToString() << "]\ntype["; - switch (type_) { - case kOriginal: - str << "Original"; - break; - case kSubrectOriginal: - str << "SubrectOriginal"; - break; - case kSubrectAndScale: - str << "SubrectAndScale"; - break; - } - str << "]\nis_nearest_neightbor[" << is_nearest_neighbor_ << "]\nsrc_rect[" - << src_rect_.ToString() << "]\ntarget_size[" << target_size_.ToString() - << "]\ntarget_color_space[" << target_color_space_.ToString() - << "]\nhash[" << hash_ << "]"; - return str.str(); -} - -// CacheEntry ------------------------------------------------------------------ -SoftwareImageDecodeCache::CacheEntry::CacheEntry() - : tracing_id_(g_next_tracing_id_.GetNext()) {} -SoftwareImageDecodeCache::CacheEntry::CacheEntry( - const SkImageInfo& info, - std::unique_ptr<base::DiscardableMemory> in_memory, - const SkSize& src_rect_offset) - : is_locked(true), - memory(std::move(in_memory)), - image_info_(info), - src_rect_offset_(src_rect_offset), - tracing_id_(g_next_tracing_id_.GetNext()) { - DCHECK(memory); - SkPixmap pixmap(image_info_, memory->data(), image_info_.minRowBytes()); - image_ = SkImage::MakeFromRaster( - pixmap, [](const void* pixels, void* context) {}, nullptr); -} - -SoftwareImageDecodeCache::CacheEntry::~CacheEntry() { - DCHECK(!is_locked); - - // We create temporary CacheEntries as a part of decoding. However, we move - // the memory to cache entries that actually live in the cache. Destroying the - // temporaries should not cause any of the stats to be recorded. Specifically, - // if allowed to report, they would report every single temporary entry as - // wasted, which is misleading. As a fix, don't report on a cache entry that - // has never been in the cache. - if (!cached_) - return; - - // lock_count | used | last lock failed | result state - // ===========+=======+==================+================== - // 1 | false | false | WASTED - // 1 | false | true | WASTED - // 1 | true | false | USED - // 1 | true | true | USED_RELOCK_FAILED - // >1 | false | false | WASTED_RELOCKED - // >1 | false | true | WASTED_RELOCKED - // >1 | true | false | USED_RELOCKED - // >1 | true | true | USED_RELOCKED - // Note that it's important not to reorder the following enums, since the - // numerical values are used in the histogram code. - enum State : int { - DECODED_IMAGE_STATE_WASTED, - DECODED_IMAGE_STATE_USED, - DECODED_IMAGE_STATE_USED_RELOCK_FAILED, - DECODED_IMAGE_STATE_WASTED_RELOCKED, - DECODED_IMAGE_STATE_USED_RELOCKED, - DECODED_IMAGE_STATE_COUNT - } state = DECODED_IMAGE_STATE_WASTED; - - if (usage_stats_.lock_count == 1) { - if (!usage_stats_.used) - state = DECODED_IMAGE_STATE_WASTED; - else if (usage_stats_.last_lock_failed) - state = DECODED_IMAGE_STATE_USED_RELOCK_FAILED; - else - state = DECODED_IMAGE_STATE_USED; - } else { - if (usage_stats_.used) - state = DECODED_IMAGE_STATE_USED_RELOCKED; - else - state = DECODED_IMAGE_STATE_WASTED_RELOCKED; - } - - UMA_HISTOGRAM_ENUMERATION("Renderer4.SoftwareImageDecodeState", state, - DECODED_IMAGE_STATE_COUNT); - UMA_HISTOGRAM_BOOLEAN("Renderer4.SoftwareImageDecodeState.FirstLockWasted", - usage_stats_.first_lock_wasted); - if (usage_stats_.first_lock_out_of_raster) - UMA_HISTOGRAM_BOOLEAN( - "Renderer4.SoftwareImageDecodeState.FirstLockWasted.OutOfRaster", - usage_stats_.first_lock_wasted); -} - -void SoftwareImageDecodeCache::CacheEntry::MoveImageMemoryTo( - CacheEntry* entry) { - DCHECK(!is_budgeted); - DCHECK_EQ(ref_count, 0); - - // Copy/move most things except budgeted and ref counts. - entry->decode_failed = decode_failed; - entry->is_locked = is_locked; - is_locked = false; - - entry->memory = std::move(memory); - entry->image_info_ = std::move(image_info_); - entry->src_rect_offset_ = std::move(src_rect_offset_); - entry->image_ = std::move(image_); -} - -bool SoftwareImageDecodeCache::CacheEntry::Lock() { - if (!memory) - return false; - - DCHECK(!is_locked); - bool success = memory->Lock(); - if (!success) { - memory = nullptr; - usage_stats_.last_lock_failed = true; - return false; - } - is_locked = true; - ++usage_stats_.lock_count; - return true; -} - -void SoftwareImageDecodeCache::CacheEntry::Unlock() { - if (!memory) - return; - - DCHECK(is_locked); - memory->Unlock(); - is_locked = false; - if (usage_stats_.lock_count == 1) - usage_stats_.first_lock_wasted = !usage_stats_.used; -} - // MemoryBudget ---------------------------------------------------------------- SoftwareImageDecodeCache::MemoryBudget::MemoryBudget(size_t limit_bytes) : limit_bytes_(limit_bytes), current_usage_bytes_(0u) {}
diff --git a/cc/tiles/software_image_decode_cache.h b/cc/tiles/software_image_decode_cache.h index 951b1d5..98d1832 100644 --- a/cc/tiles/software_image_decode_cache.h +++ b/cc/tiles/software_image_decode_cache.h
@@ -9,117 +9,27 @@ #include <memory> #include <unordered_map> -#include <unordered_set> -#include "base/atomic_sequence_num.h" #include "base/containers/mru_cache.h" -#include "base/hash.h" -#include "base/memory/discardable_memory_allocator.h" #include "base/memory/memory_coordinator_client.h" #include "base/memory/ref_counted.h" #include "base/numerics/safe_math.h" -#include "base/threading/thread_checker.h" #include "base/trace_event/memory_dump_provider.h" #include "cc/cc_export.h" #include "cc/paint/draw_image.h" #include "cc/tiles/image_decode_cache.h" -#include "third_party/skia/include/core/SkRefCnt.h" -#include "ui/gfx/geometry/rect.h" +#include "cc/tiles/software_image_decode_cache_utils.h" namespace cc { -// ImageDecodeCacheKey is a class that gets a cache key out of a given draw -// image. That is, this key uniquely identifies an image in the cache. Note that -// it's insufficient to use SkImage's unique id, since the same image can appear -// in the cache multiple times at different scales and filter qualities. -class CC_EXPORT ImageDecodeCacheKey { - public: - // Enum indicating the type of processing to do for this key: - // kOriginal - use the original decode without any subrecting or scaling. - // kSubrectOriginal - extract a subrect from the original decode but do not - // scale it. - // kSubrectAndScale - extract a subrect (if needed) from the original decode - // and scale it. - enum ProcessingType { kOriginal, kSubrectOriginal, kSubrectAndScale }; - - static ImageDecodeCacheKey FromDrawImage(const DrawImage& image, - SkColorType color_type); - - ImageDecodeCacheKey(const ImageDecodeCacheKey& other); - - bool operator==(const ImageDecodeCacheKey& other) const { - // The frame_key always has to be the same. However, after that all original - // decodes are the same, so if we can use the original decode, return true. - // If not, then we have to compare every field. - // Note we don't compare |nearest_neighbor_| because we would only use - // kOriginal type in that case (dchecked below), which implies no scale. The - // returned scale to Skia would respect the nearest neighbor value of the - // requested image. - DCHECK(!is_nearest_neighbor_ || type_ == kOriginal); - return frame_key_ == other.frame_key_ && type_ == other.type_ && - target_color_space_ == other.target_color_space_ && - (type_ == kOriginal || (src_rect_ == other.src_rect_ && - target_size_ == other.target_size_)); - } - - bool operator!=(const ImageDecodeCacheKey& other) const { - return !(*this == other); - } - - const PaintImage::FrameKey& frame_key() const { return frame_key_; } - ProcessingType type() const { return type_; } - bool is_nearest_neighbor() const { return is_nearest_neighbor_; } - gfx::Rect src_rect() const { return src_rect_; } - gfx::Size target_size() const { return target_size_; } - const gfx::ColorSpace& target_color_space() const { - return target_color_space_; - } - - size_t get_hash() const { return hash_; } - - // Helper to figure out how much memory the locked image represented by this - // key would take. - size_t locked_bytes() const { - // TODO(vmpstr): Handle formats other than RGBA. - base::CheckedNumeric<size_t> result = 4; - result *= target_size_.width(); - result *= target_size_.height(); - return result.ValueOrDefault(std::numeric_limits<size_t>::max()); - } - - std::string ToString() const; - - private: - ImageDecodeCacheKey(PaintImage::FrameKey frame_key, - ProcessingType type, - bool is_nearest_neighbor, - const gfx::Rect& src_rect, - const gfx::Size& size, - const gfx::ColorSpace& target_color_space); - - PaintImage::FrameKey frame_key_; - ProcessingType type_; - bool is_nearest_neighbor_; - gfx::Rect src_rect_; - gfx::Size target_size_; - gfx::ColorSpace target_color_space_; - size_t hash_; -}; - -// Hash function for the above ImageDecodeCacheKey. -struct ImageDecodeCacheKeyHash { - size_t operator()(const ImageDecodeCacheKey& key) const { - return key.get_hash(); - } -}; - class CC_EXPORT SoftwareImageDecodeCache : public ImageDecodeCache, public base::trace_event::MemoryDumpProvider, public base::MemoryCoordinatorClient { public: - using ImageKey = ImageDecodeCacheKey; - using ImageKeyHash = ImageDecodeCacheKeyHash; + using Utils = SoftwareImageDecodeCacheUtils; + using CacheKey = Utils::CacheKey; + using CacheKeyHash = Utils::CacheKeyHash; enum class DecodeTaskType { USE_IN_RASTER_TASKS, USE_OUT_OF_RASTER_TASKS }; @@ -146,11 +56,11 @@ // Decode the given image and store it in the cache. This is only called by an // image decode task from a worker thread. - void DecodeImageInTask(const ImageKey& key, + void DecodeImageInTask(const CacheKey& key, const PaintImage& paint_image, DecodeTaskType task_type); - void OnImageDecodeTaskCompleted(const ImageKey& key, + void OnImageDecodeTaskCompleted(const CacheKey& key, DecodeTaskType task_type); // MemoryDumpProvider overrides. @@ -160,73 +70,7 @@ size_t GetNumCacheEntriesForTesting() const { return decoded_images_.size(); } private: - // CacheEntry is a convenience storage for discardable memory. It can also - // construct an image out of SkImageInfo and stored discardable memory. - class CacheEntry { - public: - CacheEntry(); - CacheEntry(const SkImageInfo& info, - std::unique_ptr<base::DiscardableMemory> memory, - const SkSize& src_rect_offset); - ~CacheEntry(); - - void MoveImageMemoryTo(CacheEntry* entry); - - sk_sp<SkImage> image() const { - if (!memory) - return nullptr; - DCHECK(is_locked); - return image_; - } - const SkSize& src_rect_offset() const { return src_rect_offset_; } - - bool Lock(); - void Unlock(); - - // An ID which uniquely identifies this CacheEntry within the image decode - // cache. Used in memory tracing. - uint64_t tracing_id() const { return tracing_id_; } - // Mark this image as being used in either a draw or as a source for a - // scaled image. Either case represents this decode as being valuable and - // not wasted. - void mark_used() { usage_stats_.used = true; } - void mark_cached() { cached_ = true; } - void mark_out_of_raster() { usage_stats_.first_lock_out_of_raster = true; } - - // Since this is an inner class, we expose these variables publicly for - // simplicity. - // TODO(vmpstr): A good simple clean-up would be to rethink this class - // and its interactions to instead expose a few functions which would also - // facilitate easier DCHECKs. - int ref_count = 0; - bool decode_failed = false; - bool is_locked = false; - bool is_budgeted = false; - - scoped_refptr<TileTask> in_raster_task; - scoped_refptr<TileTask> out_of_raster_task; - - std::unique_ptr<base::DiscardableMemory> memory; - - private: - struct UsageStats { - // We can only create a decoded image in a locked state, so the initial - // lock count is 1. - int lock_count = 1; - bool used = false; - bool last_lock_failed = false; - bool first_lock_wasted = false; - bool first_lock_out_of_raster = false; - }; - - SkImageInfo image_info_; - sk_sp<SkImage> image_; - SkSize src_rect_offset_; - uint64_t tracing_id_; - UsageStats usage_stats_; - // Indicates whether this entry was ever in the cache. - bool cached_ = false; - }; + using CacheEntry = Utils::CacheEntry; // MemoryBudget is a convenience class for memory bookkeeping and ensuring // that we don't go over the limit when pre-decoding. @@ -247,12 +91,12 @@ }; using ImageMRUCache = base:: - HashingMRUCache<ImageKey, std::unique_ptr<CacheEntry>, ImageKeyHash>; + HashingMRUCache<CacheKey, std::unique_ptr<CacheEntry>, CacheKeyHash>; // Actually decode the image. Note that this function can (and should) be // called with no lock acquired, since it can do a lot of work. Note that it // can also return nullptr to indicate the decode failed. - std::unique_ptr<CacheEntry> DecodeImageInternal(const ImageKey& key, + std::unique_ptr<CacheEntry> DecodeImageInternal(const CacheKey& key, const DrawImage& draw_image); // Get the decoded draw image for the given key and paint_image. Note that @@ -261,7 +105,7 @@ // when used internally, we still require that DrawWithImageFinished() is // called afterwards. DecodedDrawImage GetDecodedImageForDrawInternal( - const ImageKey& key, + const CacheKey& key, const PaintImage& paint_image); // Removes unlocked decoded images until the number of decoded images is @@ -278,26 +122,19 @@ const TracingInfo& tracing_info, DecodeTaskType type); - CacheEntry* AddCacheEntry(const ImageKey& key); + CacheEntry* AddCacheEntry(const CacheKey& key); - void DecodeImageIfNecessary(const ImageKey& key, + void DecodeImageIfNecessary(const CacheKey& key, const PaintImage& paint_image, CacheEntry* cache_entry); - void AddBudgetForImage(const ImageKey& key, CacheEntry* entry); - void RemoveBudgetForImage(const ImageKey& key, CacheEntry* entry); + void AddBudgetForImage(const CacheKey& key, CacheEntry* entry); + void RemoveBudgetForImage(const CacheKey& key, CacheEntry* entry); - std::unique_ptr<CacheEntry> DoDecodeImage(const ImageKey& key, - const PaintImage& image); - std::unique_ptr<CacheEntry> GenerateCacheEntryFromCandidate( - const ImageKey& key, - const DecodedDrawImage& candidate, - bool needs_extract_subset); + void UnrefImage(const CacheKey& key); - void UnrefImage(const ImageKey& key); - - std::unordered_map<ImageKey, scoped_refptr<TileTask>, ImageKeyHash> + std::unordered_map<CacheKey, scoped_refptr<TileTask>, CacheKeyHash> pending_in_raster_image_tasks_; - std::unordered_map<ImageKey, scoped_refptr<TileTask>, ImageKeyHash> + std::unordered_map<CacheKey, scoped_refptr<TileTask>, CacheKeyHash> pending_out_of_raster_image_tasks_; // The members below this comment can only be accessed if the lock is held to @@ -312,7 +149,7 @@ // A map of PaintImage::FrameKey to the ImageKeys for cached decodes of this // PaintImage. std::unordered_map<PaintImage::FrameKey, - std::vector<ImageKey>, + std::vector<CacheKey>, PaintImage::FrameKeyHash> frame_key_to_image_keys_;
diff --git a/cc/tiles/software_image_decode_cache_perftest.cc b/cc/tiles/software_image_decode_cache_perftest.cc index 24bae70..b3c9787a 100644 --- a/cc/tiles/software_image_decode_cache_perftest.cc +++ b/cc/tiles/software_image_decode_cache_perftest.cc
@@ -70,8 +70,10 @@ timer_.Reset(); do { - for (auto& image : images) - ImageDecodeCacheKey::FromDrawImage(image, kN32_SkColorType); + for (auto& image : images) { + SoftwareImageDecodeCache::CacheKey::FromDrawImage(image, + kN32_SkColorType); + } timer_.NextLap(); } while (!timer_.HasTimeLimitExpired());
diff --git a/cc/tiles/software_image_decode_cache_unittest.cc b/cc/tiles/software_image_decode_cache_unittest.cc index 5508946b..2dbd35d 100644 --- a/cc/tiles/software_image_decode_cache_unittest.cc +++ b/cc/tiles/software_image_decode_cache_unittest.cc
@@ -54,12 +54,13 @@ CreateMatrix(SkSize::Make(0.5f, 1.5f), is_decomposable), PaintImage::kDefaultFrameIndex, DefaultColorSpace()); - auto key = ImageDecodeCacheKey::FromDrawImage(draw_image, kN32_SkColorType); + auto key = SoftwareImageDecodeCache::CacheKey::FromDrawImage( + draw_image, kN32_SkColorType); EXPECT_EQ(draw_image.frame_key(), key.frame_key()); EXPECT_TRUE(key.is_nearest_neighbor()); EXPECT_EQ(100, key.target_size().width()); EXPECT_EQ(100, key.target_size().height()); - EXPECT_EQ(key.type(), ImageDecodeCacheKey::kOriginal); + EXPECT_EQ(key.type(), SoftwareImageDecodeCache::CacheKey::kOriginal); // Since the original decode will be used, the locked_bytes is that of the // original image. EXPECT_EQ(100u * 100u * 4u, key.locked_bytes()); @@ -75,9 +76,10 @@ CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable), PaintImage::kDefaultFrameIndex, DefaultColorSpace()); - auto key = ImageDecodeCacheKey::FromDrawImage(draw_image, kN32_SkColorType); + auto key = SoftwareImageDecodeCache::CacheKey::FromDrawImage( + draw_image, kN32_SkColorType); EXPECT_EQ(draw_image.frame_key(), key.frame_key()); - EXPECT_EQ(key.type(), ImageDecodeCacheKey::kSubrectAndScale); + EXPECT_EQ(key.type(), SoftwareImageDecodeCache::CacheKey::kSubrectAndScale); EXPECT_EQ(50, key.target_size().width()); EXPECT_EQ(50, key.target_size().height()); EXPECT_EQ(50u * 50u * 4u, key.locked_bytes()); @@ -92,12 +94,13 @@ CreateMatrix(SkSize::Make(0.75f, 0.75f), is_decomposable), PaintImage::kDefaultFrameIndex, DefaultColorSpace()); - auto key = ImageDecodeCacheKey::FromDrawImage(draw_image, kN32_SkColorType); + auto key = SoftwareImageDecodeCache::CacheKey::FromDrawImage( + draw_image, kN32_SkColorType); EXPECT_EQ(draw_image.frame_key(), key.frame_key()); EXPECT_FALSE(key.is_nearest_neighbor()); EXPECT_EQ(100, key.target_size().width()); EXPECT_EQ(100, key.target_size().height()); - EXPECT_EQ(key.type(), ImageDecodeCacheKey::kOriginal); + EXPECT_EQ(key.type(), SoftwareImageDecodeCache::CacheKey::kOriginal); EXPECT_EQ(100u * 100u * 4u, key.locked_bytes()); } @@ -110,13 +113,13 @@ CreateMatrix(SkSize::Make(0.5f, 1.5f), is_decomposable), PaintImage::kDefaultFrameIndex, DefaultColorSpace()); - auto key = - ImageDecodeCacheKey::FromDrawImage(draw_image, kARGB_4444_SkColorType); + auto key = SoftwareImageDecodeCache::CacheKey::FromDrawImage( + draw_image, kARGB_4444_SkColorType); EXPECT_EQ(draw_image.frame_key(), key.frame_key()); EXPECT_FALSE(key.is_nearest_neighbor()); EXPECT_EQ(100, key.target_size().width()); EXPECT_EQ(100, key.target_size().height()); - EXPECT_EQ(key.type(), ImageDecodeCacheKey::kOriginal); + EXPECT_EQ(key.type(), SoftwareImageDecodeCache::CacheKey::kOriginal); EXPECT_EQ(100u * 100u * 4u, key.locked_bytes()); } @@ -129,13 +132,13 @@ CreateMatrix(SkSize::Make(1.5f, 1.5f), is_decomposable), PaintImage::kDefaultFrameIndex, DefaultColorSpace()); - auto key = - ImageDecodeCacheKey::FromDrawImage(draw_image, kARGB_4444_SkColorType); + auto key = SoftwareImageDecodeCache::CacheKey::FromDrawImage( + draw_image, kARGB_4444_SkColorType); EXPECT_EQ(draw_image.frame_key(), key.frame_key()); EXPECT_FALSE(key.is_nearest_neighbor()); EXPECT_EQ(100, key.target_size().width()); EXPECT_EQ(100, key.target_size().height()); - EXPECT_EQ(key.type(), ImageDecodeCacheKey::kOriginal); + EXPECT_EQ(key.type(), SoftwareImageDecodeCache::CacheKey::kOriginal); EXPECT_EQ(100u * 100u * 4u, key.locked_bytes()); } @@ -148,12 +151,13 @@ CreateMatrix(SkSize::Make(1.5f, 1.5f), is_decomposable), PaintImage::kDefaultFrameIndex, DefaultColorSpace()); - auto key = ImageDecodeCacheKey::FromDrawImage(draw_image, kN32_SkColorType); + auto key = SoftwareImageDecodeCache::CacheKey::FromDrawImage( + draw_image, kN32_SkColorType); EXPECT_EQ(draw_image.frame_key(), key.frame_key()); EXPECT_FALSE(key.is_nearest_neighbor()); EXPECT_EQ(100, key.target_size().width()); EXPECT_EQ(100, key.target_size().height()); - EXPECT_EQ(key.type(), ImageDecodeCacheKey::kOriginal); + EXPECT_EQ(key.type(), SoftwareImageDecodeCache::CacheKey::kOriginal); EXPECT_EQ(100u * 100u * 4u, key.locked_bytes()); } @@ -167,9 +171,10 @@ quality, CreateMatrix(SkSize::Make(0.5f, 0.4f), is_decomposable), PaintImage::kDefaultFrameIndex, DefaultColorSpace()); - auto key = ImageDecodeCacheKey::FromDrawImage(draw_image, kN32_SkColorType); + auto key = SoftwareImageDecodeCache::CacheKey::FromDrawImage( + draw_image, kN32_SkColorType); EXPECT_EQ(draw_image.frame_key(), key.frame_key()); - EXPECT_EQ(key.type(), ImageDecodeCacheKey::kSubrectAndScale); + EXPECT_EQ(key.type(), SoftwareImageDecodeCache::CacheKey::kSubrectAndScale); EXPECT_EQ(50, key.target_size().width()); EXPECT_EQ(50, key.target_size().height()); EXPECT_EQ(50u * 50u * 4u, key.locked_bytes()); @@ -185,12 +190,13 @@ quality, CreateMatrix(SkSize::Make(1.5f, 1.5f), is_decomposable), PaintImage::kDefaultFrameIndex, DefaultColorSpace()); - auto key = ImageDecodeCacheKey::FromDrawImage(draw_image, kN32_SkColorType); + auto key = SoftwareImageDecodeCache::CacheKey::FromDrawImage( + draw_image, kN32_SkColorType); EXPECT_EQ(draw_image.frame_key(), key.frame_key()); EXPECT_FALSE(key.is_nearest_neighbor()); EXPECT_EQ(100, key.target_size().width()); EXPECT_EQ(100, key.target_size().height()); - EXPECT_EQ(key.type(), ImageDecodeCacheKey::kOriginal); + EXPECT_EQ(key.type(), SoftwareImageDecodeCache::CacheKey::kOriginal); EXPECT_EQ(100u * 100u * 4u, key.locked_bytes()); } @@ -204,12 +210,13 @@ quality, CreateMatrix(SkSize::Make(1.f, 1.f), is_decomposable), PaintImage::kDefaultFrameIndex, DefaultColorSpace()); - auto key = ImageDecodeCacheKey::FromDrawImage(draw_image, kN32_SkColorType); + auto key = SoftwareImageDecodeCache::CacheKey::FromDrawImage( + draw_image, kN32_SkColorType); EXPECT_EQ(draw_image.frame_key(), key.frame_key()); EXPECT_FALSE(key.is_nearest_neighbor()); EXPECT_EQ(100, key.target_size().width()); EXPECT_EQ(100, key.target_size().height()); - EXPECT_EQ(key.type(), ImageDecodeCacheKey::kOriginal); + EXPECT_EQ(key.type(), SoftwareImageDecodeCache::CacheKey::kOriginal); EXPECT_EQ(100u * 100u * 4u, key.locked_bytes()); } @@ -224,12 +231,13 @@ quality, CreateMatrix(SkSize::Make(1.001f, 1.001f), is_decomposable), PaintImage::kDefaultFrameIndex, DefaultColorSpace()); - auto key = ImageDecodeCacheKey::FromDrawImage(draw_image, kN32_SkColorType); + auto key = SoftwareImageDecodeCache::CacheKey::FromDrawImage( + draw_image, kN32_SkColorType); EXPECT_EQ(draw_image.frame_key(), key.frame_key()); EXPECT_FALSE(key.is_nearest_neighbor()); EXPECT_EQ(100, key.target_size().width()); EXPECT_EQ(100, key.target_size().height()); - EXPECT_EQ(key.type(), ImageDecodeCacheKey::kOriginal); + EXPECT_EQ(key.type(), SoftwareImageDecodeCache::CacheKey::kOriginal); EXPECT_EQ(100u * 100u * 4u, key.locked_bytes()); } @@ -244,12 +252,13 @@ quality, CreateMatrix(SkSize::Make(0.999f, 0.999f), is_decomposable), PaintImage::kDefaultFrameIndex, DefaultColorSpace()); - auto key = ImageDecodeCacheKey::FromDrawImage(draw_image, kN32_SkColorType); + auto key = SoftwareImageDecodeCache::CacheKey::FromDrawImage( + draw_image, kN32_SkColorType); EXPECT_EQ(draw_image.frame_key(), key.frame_key()); EXPECT_FALSE(key.is_nearest_neighbor()); EXPECT_EQ(100, key.target_size().width()); EXPECT_EQ(100, key.target_size().height()); - EXPECT_EQ(key.type(), ImageDecodeCacheKey::kOriginal); + EXPECT_EQ(key.type(), SoftwareImageDecodeCache::CacheKey::kOriginal); EXPECT_EQ(100u * 100u * 4u, key.locked_bytes()); } @@ -264,13 +273,14 @@ quality, CreateMatrix(SkSize::Make(0.5f, 1.5f), is_decomposable), PaintImage::kDefaultFrameIndex, DefaultColorSpace()); - auto key = ImageDecodeCacheKey::FromDrawImage(draw_image, kN32_SkColorType); + auto key = SoftwareImageDecodeCache::CacheKey::FromDrawImage( + draw_image, kN32_SkColorType); EXPECT_EQ(draw_image.frame_key(), key.frame_key()); EXPECT_FALSE(key.is_nearest_neighbor()); EXPECT_EQ(100, key.target_size().width()); EXPECT_EQ(100, key.target_size().height()); - EXPECT_EQ(key.type(), ImageDecodeCacheKey::kOriginal); + EXPECT_EQ(key.type(), SoftwareImageDecodeCache::CacheKey::kOriginal); EXPECT_EQ(100u * 100u * 4u, key.locked_bytes()); } @@ -284,12 +294,13 @@ quality, CreateMatrix(SkSize::Make(1.5f, 1.5f), is_decomposable), PaintImage::kDefaultFrameIndex, DefaultColorSpace()); - auto key = ImageDecodeCacheKey::FromDrawImage(draw_image, kN32_SkColorType); + auto key = SoftwareImageDecodeCache::CacheKey::FromDrawImage( + draw_image, kN32_SkColorType); EXPECT_EQ(draw_image.frame_key(), key.frame_key()); EXPECT_FALSE(key.is_nearest_neighbor()); EXPECT_EQ(500, key.target_size().width()); EXPECT_EQ(200, key.target_size().height()); - EXPECT_EQ(key.type(), ImageDecodeCacheKey::kOriginal); + EXPECT_EQ(key.type(), SoftwareImageDecodeCache::CacheKey::kOriginal); EXPECT_EQ(500u * 200u * 4u, key.locked_bytes()); } @@ -303,12 +314,13 @@ quality, CreateMatrix(SkSize::Make(1.f, 1.f), is_decomposable), PaintImage::kDefaultFrameIndex, DefaultColorSpace()); - auto key = ImageDecodeCacheKey::FromDrawImage(draw_image, kN32_SkColorType); + auto key = SoftwareImageDecodeCache::CacheKey::FromDrawImage( + draw_image, kN32_SkColorType); EXPECT_EQ(draw_image.frame_key(), key.frame_key()); EXPECT_FALSE(key.is_nearest_neighbor()); EXPECT_EQ(500, key.target_size().width()); EXPECT_EQ(200, key.target_size().height()); - EXPECT_EQ(key.type(), ImageDecodeCacheKey::kOriginal); + EXPECT_EQ(key.type(), SoftwareImageDecodeCache::CacheKey::kOriginal); EXPECT_EQ(500u * 200u * 4u, key.locked_bytes()); } @@ -322,12 +334,13 @@ quality, CreateMatrix(SkSize::Make(0.75f, 0.75f), is_decomposable), PaintImage::kDefaultFrameIndex, DefaultColorSpace()); - auto key = ImageDecodeCacheKey::FromDrawImage(draw_image, kN32_SkColorType); + auto key = SoftwareImageDecodeCache::CacheKey::FromDrawImage( + draw_image, kN32_SkColorType); EXPECT_EQ(draw_image.frame_key(), key.frame_key()); EXPECT_FALSE(key.is_nearest_neighbor()); EXPECT_EQ(500, key.target_size().width()); EXPECT_EQ(200, key.target_size().height()); - EXPECT_EQ(key.type(), ImageDecodeCacheKey::kOriginal); + EXPECT_EQ(key.type(), SoftwareImageDecodeCache::CacheKey::kOriginal); EXPECT_EQ(500u * 200u * 4u, key.locked_bytes()); } @@ -341,9 +354,10 @@ quality, CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable), PaintImage::kDefaultFrameIndex, DefaultColorSpace()); - auto key = ImageDecodeCacheKey::FromDrawImage(draw_image, kN32_SkColorType); + auto key = SoftwareImageDecodeCache::CacheKey::FromDrawImage( + draw_image, kN32_SkColorType); EXPECT_EQ(draw_image.frame_key(), key.frame_key()); - EXPECT_EQ(key.type(), ImageDecodeCacheKey::kSubrectAndScale); + EXPECT_EQ(key.type(), SoftwareImageDecodeCache::CacheKey::kSubrectAndScale); EXPECT_EQ(250, key.target_size().width()); EXPECT_EQ(100, key.target_size().height()); EXPECT_EQ(250u * 100u * 4u, key.locked_bytes()); @@ -359,9 +373,10 @@ quality, CreateMatrix(SkSize::Make(0.49f, 0.49f), is_decomposable), PaintImage::kDefaultFrameIndex, DefaultColorSpace()); - auto key = ImageDecodeCacheKey::FromDrawImage(draw_image, kN32_SkColorType); + auto key = SoftwareImageDecodeCache::CacheKey::FromDrawImage( + draw_image, kN32_SkColorType); EXPECT_EQ(draw_image.frame_key(), key.frame_key()); - EXPECT_EQ(key.type(), ImageDecodeCacheKey::kSubrectAndScale); + EXPECT_EQ(key.type(), SoftwareImageDecodeCache::CacheKey::kSubrectAndScale); EXPECT_EQ(250, key.target_size().width()); EXPECT_EQ(100, key.target_size().height()); EXPECT_EQ(250u * 100u * 4u, key.locked_bytes()); @@ -377,9 +392,10 @@ quality, CreateMatrix(SkSize::Make(0.1f, 0.1f), is_decomposable), PaintImage::kDefaultFrameIndex, DefaultColorSpace()); - auto key = ImageDecodeCacheKey::FromDrawImage(draw_image, kN32_SkColorType); + auto key = SoftwareImageDecodeCache::CacheKey::FromDrawImage( + draw_image, kN32_SkColorType); EXPECT_EQ(draw_image.frame_key(), key.frame_key()); - EXPECT_EQ(key.type(), ImageDecodeCacheKey::kSubrectAndScale); + EXPECT_EQ(key.type(), SoftwareImageDecodeCache::CacheKey::kSubrectAndScale); EXPECT_EQ(62, key.target_size().width()); EXPECT_EQ(25, key.target_size().height()); EXPECT_EQ(62u * 25u * 4u, key.locked_bytes()); @@ -395,9 +411,10 @@ quality, CreateMatrix(SkSize::Make(0.01f, 0.01f), is_decomposable), PaintImage::kDefaultFrameIndex, DefaultColorSpace()); - auto key = ImageDecodeCacheKey::FromDrawImage(draw_image, kN32_SkColorType); + auto key = SoftwareImageDecodeCache::CacheKey::FromDrawImage( + draw_image, kN32_SkColorType); EXPECT_EQ(draw_image.frame_key(), key.frame_key()); - EXPECT_EQ(key.type(), ImageDecodeCacheKey::kSubrectAndScale); + EXPECT_EQ(key.type(), SoftwareImageDecodeCache::CacheKey::kSubrectAndScale); EXPECT_EQ(7, key.target_size().width()); EXPECT_EQ(3, key.target_size().height()); EXPECT_EQ(7u * 3u * 4u, key.locked_bytes()); @@ -414,9 +431,10 @@ quality, CreateMatrix(SkSize::Make(0.5f, 0.2f), is_decomposable), PaintImage::kDefaultFrameIndex, DefaultColorSpace()); - auto key = ImageDecodeCacheKey::FromDrawImage(draw_image, kN32_SkColorType); + auto key = SoftwareImageDecodeCache::CacheKey::FromDrawImage( + draw_image, kN32_SkColorType); EXPECT_EQ(draw_image.frame_key(), key.frame_key()); - EXPECT_EQ(key.type(), ImageDecodeCacheKey::kSubrectAndScale); + EXPECT_EQ(key.type(), SoftwareImageDecodeCache::CacheKey::kSubrectAndScale); EXPECT_EQ(50, key.target_size().width()); EXPECT_EQ(50, key.target_size().height()); EXPECT_EQ(50u * 50u * 4u, key.locked_bytes()); @@ -432,12 +450,13 @@ quality, CreateMatrix(SkSize::Make(2.5f, 1.5f), is_decomposable), PaintImage::kDefaultFrameIndex, DefaultColorSpace()); - auto key = ImageDecodeCacheKey::FromDrawImage(draw_image, kN32_SkColorType); + auto key = SoftwareImageDecodeCache::CacheKey::FromDrawImage( + draw_image, kN32_SkColorType); EXPECT_EQ(draw_image.frame_key(), key.frame_key()); EXPECT_FALSE(key.is_nearest_neighbor()); EXPECT_EQ(100, key.target_size().width()); EXPECT_EQ(100, key.target_size().height()); - EXPECT_EQ(key.type(), ImageDecodeCacheKey::kOriginal); + EXPECT_EQ(key.type(), SoftwareImageDecodeCache::CacheKey::kOriginal); EXPECT_EQ(100u * 100u * 4u, key.locked_bytes()); } @@ -454,9 +473,10 @@ quality, CreateMatrix(SkSize::Make(0.45f, 0.45f), is_decomposable), PaintImage::kDefaultFrameIndex, DefaultColorSpace()); - auto key = ImageDecodeCacheKey::FromDrawImage(draw_image, kN32_SkColorType); + auto key = SoftwareImageDecodeCache::CacheKey::FromDrawImage( + draw_image, kN32_SkColorType); EXPECT_EQ(draw_image.frame_key(), key.frame_key()); - EXPECT_EQ(key.type(), ImageDecodeCacheKey::kSubrectAndScale); + EXPECT_EQ(key.type(), SoftwareImageDecodeCache::CacheKey::kSubrectAndScale); EXPECT_EQ(2277, key.target_size().width()); EXPECT_EQ(1024, key.target_size().height()); EXPECT_EQ(2277u * 1024u * 4u, key.locked_bytes()); @@ -473,12 +493,13 @@ quality, CreateMatrix(SkSize::Make(0.5f, 1.5f), is_decomposable), PaintImage::kDefaultFrameIndex, DefaultColorSpace()); - auto key = ImageDecodeCacheKey::FromDrawImage(draw_image, kN32_SkColorType); + auto key = SoftwareImageDecodeCache::CacheKey::FromDrawImage( + draw_image, kN32_SkColorType); EXPECT_EQ(draw_image.frame_key(), key.frame_key()); EXPECT_FALSE(key.is_nearest_neighbor()); EXPECT_EQ(100, key.target_size().width()); EXPECT_EQ(100, key.target_size().height()); - EXPECT_EQ(key.type(), ImageDecodeCacheKey::kOriginal); + EXPECT_EQ(key.type(), SoftwareImageDecodeCache::CacheKey::kOriginal); EXPECT_EQ(100u * 100u * 4u, key.locked_bytes()); } @@ -492,12 +513,13 @@ quality, CreateMatrix(SkSize::Make(1.f, 1.f), is_decomposable), PaintImage::kDefaultFrameIndex, DefaultColorSpace()); - auto key = ImageDecodeCacheKey::FromDrawImage(draw_image, kN32_SkColorType); + auto key = SoftwareImageDecodeCache::CacheKey::FromDrawImage( + draw_image, kN32_SkColorType); EXPECT_EQ(draw_image.frame_key(), key.frame_key()); EXPECT_FALSE(key.is_nearest_neighbor()); EXPECT_EQ(100, key.target_size().width()); EXPECT_EQ(100, key.target_size().height()); - EXPECT_EQ(key.type(), ImageDecodeCacheKey::kOriginal); + EXPECT_EQ(key.type(), SoftwareImageDecodeCache::CacheKey::kOriginal); EXPECT_EQ(100u * 100u * 4u, key.locked_bytes()); } @@ -512,12 +534,13 @@ quality, CreateMatrix(SkSize::Make(1.001f, 1.001f), is_decomposable), PaintImage::kDefaultFrameIndex, DefaultColorSpace()); - auto key = ImageDecodeCacheKey::FromDrawImage(draw_image, kN32_SkColorType); + auto key = SoftwareImageDecodeCache::CacheKey::FromDrawImage( + draw_image, kN32_SkColorType); EXPECT_EQ(draw_image.frame_key(), key.frame_key()); EXPECT_FALSE(key.is_nearest_neighbor()); EXPECT_EQ(100, key.target_size().width()); EXPECT_EQ(100, key.target_size().height()); - EXPECT_EQ(key.type(), ImageDecodeCacheKey::kOriginal); + EXPECT_EQ(key.type(), SoftwareImageDecodeCache::CacheKey::kOriginal); EXPECT_EQ(100u * 100u * 4u, key.locked_bytes()); } @@ -532,12 +555,13 @@ quality, CreateMatrix(SkSize::Make(0.999f, 0.999f), is_decomposable), PaintImage::kDefaultFrameIndex, DefaultColorSpace()); - auto key = ImageDecodeCacheKey::FromDrawImage(draw_image, kN32_SkColorType); + auto key = SoftwareImageDecodeCache::CacheKey::FromDrawImage( + draw_image, kN32_SkColorType); EXPECT_EQ(draw_image.frame_key(), key.frame_key()); EXPECT_FALSE(key.is_nearest_neighbor()); EXPECT_EQ(100, key.target_size().width()); EXPECT_EQ(100, key.target_size().height()); - EXPECT_EQ(key.type(), ImageDecodeCacheKey::kOriginal); + EXPECT_EQ(key.type(), SoftwareImageDecodeCache::CacheKey::kOriginal); EXPECT_EQ(100u * 100u * 4u, key.locked_bytes()); } @@ -551,12 +575,13 @@ quality, CreateMatrix(SkSize::Make(0.5f, 0.5), is_decomposable), PaintImage::kDefaultFrameIndex, DefaultColorSpace()); - auto key = ImageDecodeCacheKey::FromDrawImage(draw_image, kN32_SkColorType); + auto key = SoftwareImageDecodeCache::CacheKey::FromDrawImage( + draw_image, kN32_SkColorType); EXPECT_EQ(draw_image.frame_key(), key.frame_key()); EXPECT_TRUE(key.is_nearest_neighbor()); EXPECT_EQ(100, key.target_size().width()); EXPECT_EQ(100, key.target_size().height()); - EXPECT_EQ(key.type(), ImageDecodeCacheKey::kOriginal); + EXPECT_EQ(key.type(), SoftwareImageDecodeCache::CacheKey::kOriginal); EXPECT_EQ(100u * 100u * 4u, key.locked_bytes()); DrawImage another_draw_image( @@ -564,13 +589,13 @@ quality, CreateMatrix(SkSize::Make(1.5f, 1.5), is_decomposable), PaintImage::kDefaultFrameIndex, DefaultColorSpace()); - auto another_key = - ImageDecodeCacheKey::FromDrawImage(another_draw_image, kN32_SkColorType); + auto another_key = SoftwareImageDecodeCache::CacheKey::FromDrawImage( + another_draw_image, kN32_SkColorType); EXPECT_EQ(another_draw_image.frame_key(), another_key.frame_key()); EXPECT_TRUE(another_key.is_nearest_neighbor()); EXPECT_EQ(100, another_key.target_size().width()); EXPECT_EQ(100, another_key.target_size().height()); - EXPECT_EQ(another_key.type(), ImageDecodeCacheKey::kOriginal); + EXPECT_EQ(another_key.type(), SoftwareImageDecodeCache::CacheKey::kOriginal); EXPECT_EQ(100u * 100u * 4u, another_key.locked_bytes()); EXPECT_TRUE(key == another_key); @@ -587,7 +612,8 @@ quality, CreateMatrix(SkSize::Make(1.f, 1.f), is_decomposable), PaintImage::kDefaultFrameIndex, DefaultColorSpace()); - auto key = ImageDecodeCacheKey::FromDrawImage(draw_image, kN32_SkColorType); + auto key = SoftwareImageDecodeCache::CacheKey::FromDrawImage( + draw_image, kN32_SkColorType); EXPECT_EQ(draw_image.frame_key(), key.frame_key()); EXPECT_FALSE(key.is_nearest_neighbor()); EXPECT_EQ(100, key.target_size().width()); @@ -607,9 +633,10 @@ quality, CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable), PaintImage::kDefaultFrameIndex, DefaultColorSpace()); - auto key = ImageDecodeCacheKey::FromDrawImage(draw_image, kN32_SkColorType); + auto key = SoftwareImageDecodeCache::CacheKey::FromDrawImage( + draw_image, kN32_SkColorType); EXPECT_EQ(draw_image.frame_key(), key.frame_key()); - EXPECT_EQ(key.type(), ImageDecodeCacheKey::kSubrectAndScale); + EXPECT_EQ(key.type(), SoftwareImageDecodeCache::CacheKey::kSubrectAndScale); EXPECT_EQ(40, key.target_size().width()); EXPECT_EQ(35, key.target_size().height()); EXPECT_EQ(gfx::Rect(20, 30, 80, 70), key.src_rect());
diff --git a/cc/tiles/software_image_decode_cache_utils.cc b/cc/tiles/software_image_decode_cache_utils.cc new file mode 100644 index 0000000..1272668 --- /dev/null +++ b/cc/tiles/software_image_decode_cache_utils.cc
@@ -0,0 +1,411 @@ +// 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 "cc/tiles/software_image_decode_cache_utils.h" + +#include "base/atomic_sequence_num.h" +#include "base/hash.h" +#include "base/memory/discardable_memory_allocator.h" +#include "base/metrics/histogram_macros.h" +#include "base/trace_event/trace_event.h" +#include "cc/tiles/mipmap_util.h" +#include "ui/gfx/skia_util.h" + +namespace cc { +namespace { +// If the size of the original sized image breaches kMemoryRatioToSubrect but we +// don't need to scale the image, consider caching only the needed subrect. +// The second part that much be true is that we cache only the needed subrect if +// the total size needed for the subrect is at most kMemoryRatioToSubrect * +// (size needed for the full original image). +// Note that at least one of the dimensions has to be at least +// kMinDimensionToSubrect before an image can breach the threshold. +const size_t kMemoryThresholdToSubrect = 64 * 1024 * 1024; +const int kMinDimensionToSubrect = 4 * 1024; +const float kMemoryRatioToSubrect = 0.5f; + +// Tracing ID sequence for use in CacheEntry. +base::AtomicSequenceNumber g_next_tracing_id_; + +gfx::Rect GetSrcRect(const DrawImage& image) { + const SkIRect& src_rect = image.src_rect(); + int x = std::max(0, src_rect.x()); + int y = std::max(0, src_rect.y()); + int right = std::min(image.paint_image().width(), src_rect.right()); + int bottom = std::min(image.paint_image().height(), src_rect.bottom()); + if (x >= right || y >= bottom) + return gfx::Rect(); + return gfx::Rect(x, y, right - x, bottom - y); +} + +SkImageInfo CreateImageInfo(const SkISize& size, SkColorType color_type) { + return SkImageInfo::Make(size.width(), size.height(), color_type, + kPremul_SkAlphaType); +} + +std::unique_ptr<base::DiscardableMemory> AllocateDiscardable( + const SkImageInfo& info) { + TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("cc.debug"), "AllocateDiscardable"); + return base::DiscardableMemoryAllocator::GetInstance() + ->AllocateLockedDiscardableMemory(info.minRowBytes() * info.height()); +} + +} // namespace + +// static +std::unique_ptr<SoftwareImageDecodeCacheUtils::CacheEntry> +SoftwareImageDecodeCacheUtils::DoDecodeImage(const CacheKey& key, + const PaintImage& paint_image, + SkColorType color_type) { + SkISize target_size = + SkISize::Make(key.target_size().width(), key.target_size().height()); + DCHECK(target_size == paint_image.GetSupportedDecodeSize(target_size)); + + SkImageInfo target_info = CreateImageInfo(target_size, color_type); + std::unique_ptr<base::DiscardableMemory> target_pixels = + AllocateDiscardable(target_info); + DCHECK(target_pixels); + + TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("cc.debug"), + "SoftwareImageDecodeCacheUtils::DoDecodeImage - " + "decode"); + DCHECK_EQ(key.type(), CacheKey::kOriginal); + bool result = paint_image.Decode(target_pixels->data(), &target_info, + key.target_color_space().ToSkColorSpace(), + key.frame_key().frame_index()); + if (!result) { + target_pixels->Unlock(); + return nullptr; + } + return std::make_unique<CacheEntry>(target_info, std::move(target_pixels), + SkSize::Make(0, 0)); +} + +// static +std::unique_ptr<SoftwareImageDecodeCacheUtils::CacheEntry> +SoftwareImageDecodeCacheUtils::GenerateCacheEntryFromCandidate( + const CacheKey& key, + const DecodedDrawImage& candidate_image, + bool needs_extract_subset, + SkColorType color_type) { + SkISize target_size = + SkISize::Make(key.target_size().width(), key.target_size().height()); + SkImageInfo target_info = CreateImageInfo(target_size, color_type); + std::unique_ptr<base::DiscardableMemory> target_pixels = + AllocateDiscardable(target_info); + DCHECK(target_pixels); + + if (key.type() == CacheKey::kSubrectOriginal) { + DCHECK(needs_extract_subset); + TRACE_EVENT0( + TRACE_DISABLED_BY_DEFAULT("cc.debug"), + "SoftwareImageDecodeCacheUtils::GenerateCacheEntryFromCandidate - " + "subrect"); + bool result = candidate_image.image()->readPixels( + target_info, target_pixels->data(), target_info.minRowBytes(), + key.src_rect().x(), key.src_rect().y(), SkImage::kDisallow_CachingHint); + // We have a decoded image, and we're reading into already allocated memory. + // This should never fail. + DCHECK(result) << key.ToString(); + return std::make_unique<CacheEntry>( + target_info.makeColorSpace(candidate_image.image()->refColorSpace()), + std::move(target_pixels), + SkSize::Make(-key.src_rect().x(), -key.src_rect().y())); + } + + DCHECK_EQ(key.type(), CacheKey::kSubrectAndScale); + TRACE_EVENT0( + TRACE_DISABLED_BY_DEFAULT("cc.debug"), + "SoftwareImageDecodeCacheUtils::GenerateCacheEntryFromCandidate - " + "scale"); + SkPixmap decoded_pixmap; + // We don't need to subrect this image, since all candidates passed in would + // already have a src_rect applied to them. + bool result = candidate_image.image()->peekPixels(&decoded_pixmap); + DCHECK(result) << key.ToString(); + if (needs_extract_subset) { + result = decoded_pixmap.extractSubset(&decoded_pixmap, + gfx::RectToSkIRect(key.src_rect())); + DCHECK(result) << key.ToString(); + } + + // Nearest neighbor would only be set in the unscaled case. + DCHECK(!key.is_nearest_neighbor()); + SkPixmap target_pixmap(target_info, target_pixels->data(), + target_info.minRowBytes()); + // Always use medium quality for scaling. + result = decoded_pixmap.scalePixels(target_pixmap, kMedium_SkFilterQuality); + DCHECK(result) << key.ToString(); + return std::make_unique<CacheEntry>( + target_info.makeColorSpace(candidate_image.image()->refColorSpace()), + std::move(target_pixels), + SkSize::Make(-key.src_rect().x(), -key.src_rect().y())); +} + +// CacheKey -------------------------------------------------------------------- +// static +SoftwareImageDecodeCacheUtils::CacheKey +SoftwareImageDecodeCacheUtils::CacheKey::FromDrawImage(const DrawImage& image, + SkColorType color_type) { + const PaintImage::FrameKey frame_key = image.frame_key(); + + const SkSize& scale = image.scale(); + // If the src_rect falls outside of the image, we need to clip it since + // otherwise we might end up with uninitialized memory in the decode process. + // Note that the scale is still unchanged and the target size is now a + // function of the new src_rect. + const gfx::Rect& src_rect = GetSrcRect(image); + + // Start with the exact target size. However, this will be adjusted below to + // be either a mip level, the original size, or a subrect size. This is done + // to keep memory accounting correct. + gfx::Size target_size( + SkScalarRoundToInt(std::abs(src_rect.width() * scale.width())), + SkScalarRoundToInt(std::abs(src_rect.height() * scale.height()))); + + // If the target size is empty, then we'll be skipping the decode anyway, so + // the filter quality doesn't matter. Early out instead. + if (target_size.IsEmpty()) { + return CacheKey(frame_key, kOriginal, false, src_rect, target_size, + image.target_color_space()); + } + + ProcessingType type = kOriginal; + bool is_nearest_neighbor = image.filter_quality() == kNone_SkFilterQuality; + int mip_level = MipMapUtil::GetLevelForSize(src_rect.size(), target_size); + // If any of the following conditions hold, then use at most low filter + // quality and adjust the target size to match the original image: + // - Quality is none: We need a pixelated image, so we can't upgrade it. + // - Format is 4444: Skia doesn't support scaling these, so use low + // filter quality. + // - Mip level is 0: The required mip is the original image, so just use low + // filter quality. + // - Matrix is not decomposable: There's perspective on this image and we + // can't determine the size, so use the original. + if (is_nearest_neighbor || color_type == kARGB_4444_SkColorType || + mip_level == 0 || !image.matrix_is_decomposable()) { + type = kOriginal; + // Update the size to be the original image size. + target_size = + gfx::Size(image.paint_image().width(), image.paint_image().height()); + } else { + type = kSubrectAndScale; + // Update the target size to be a mip level size. + // TODO(vmpstr): MipMapUtil and JPEG decoders disagree on what to do with + // odd sizes. If width = 2k + 1, and the mip level is 1, then this will + // return width = k; JPEG decoder, however, will support decoding to width = + // k + 1. We need to figure out what to do in this case. + SkSize mip_scale_adjustment = + MipMapUtil::GetScaleAdjustmentForLevel(src_rect.size(), mip_level); + target_size.set_width(src_rect.width() * mip_scale_adjustment.width()); + target_size.set_height(src_rect.height() * mip_scale_adjustment.height()); + } + + // If the original image is large, we might want to do a subrect instead if + // the subrect would be kMemoryRatioToSubrect times smaller. + if (type == kOriginal && + (image.paint_image().width() >= kMinDimensionToSubrect || + image.paint_image().height() >= kMinDimensionToSubrect)) { + base::CheckedNumeric<size_t> checked_original_size = 4u; + checked_original_size *= image.paint_image().width(); + checked_original_size *= image.paint_image().height(); + size_t original_size = checked_original_size.ValueOrDefault( + std::numeric_limits<size_t>::max()); + + base::CheckedNumeric<size_t> checked_src_rect_size = 4u; + checked_src_rect_size *= src_rect.width(); + checked_src_rect_size *= src_rect.height(); + size_t src_rect_size = checked_src_rect_size.ValueOrDefault( + std::numeric_limits<size_t>::max()); + + // If the sizes are such that we get good savings by subrecting, then do + // that. Also update the target size to be the src rect size since that's + // the rect we want to use. + if (original_size > kMemoryThresholdToSubrect && + src_rect_size <= original_size * kMemoryRatioToSubrect) { + type = kSubrectOriginal; + target_size = src_rect.size(); + } + } + + return CacheKey(frame_key, type, is_nearest_neighbor, src_rect, target_size, + image.target_color_space()); +} + +SoftwareImageDecodeCacheUtils::CacheKey::CacheKey( + PaintImage::FrameKey frame_key, + ProcessingType type, + bool is_nearest_neighbor, + const gfx::Rect& src_rect, + const gfx::Size& target_size, + const gfx::ColorSpace& target_color_space) + : frame_key_(frame_key), + type_(type), + is_nearest_neighbor_(is_nearest_neighbor), + src_rect_(src_rect), + target_size_(target_size), + target_color_space_(target_color_space) { + if (type == kOriginal) { + hash_ = frame_key_.hash(); + } else { + // TODO(vmpstr): This is a mess. Maybe it's faster to just search the vector + // always (forwards or backwards to account for LRU). + uint64_t src_rect_hash = base::HashInts( + static_cast<uint64_t>(base::HashInts(src_rect_.x(), src_rect_.y())), + static_cast<uint64_t>( + base::HashInts(src_rect_.width(), src_rect_.height()))); + + uint64_t target_size_hash = + base::HashInts(target_size_.width(), target_size_.height()); + + hash_ = base::HashInts(base::HashInts(src_rect_hash, target_size_hash), + frame_key_.hash()); + } + // Include the target color space in the hash regardless of scaling. + hash_ = base::HashInts(hash_, target_color_space.GetHash()); +} + +SoftwareImageDecodeCacheUtils::CacheKey::CacheKey(const CacheKey& other) = + default; + +std::string SoftwareImageDecodeCacheUtils::CacheKey::ToString() const { + std::ostringstream str; + str << "frame_key[" << frame_key_.ToString() << "]\ntype["; + switch (type_) { + case kOriginal: + str << "Original"; + break; + case kSubrectOriginal: + str << "SubrectOriginal"; + break; + case kSubrectAndScale: + str << "SubrectAndScale"; + break; + } + str << "]\nis_nearest_neightbor[" << is_nearest_neighbor_ << "]\nsrc_rect[" + << src_rect_.ToString() << "]\ntarget_size[" << target_size_.ToString() + << "]\ntarget_color_space[" << target_color_space_.ToString() + << "]\nhash[" << hash_ << "]"; + return str.str(); +} + +// CacheEntry ------------------------------------------------------------------ +SoftwareImageDecodeCacheUtils::CacheEntry::CacheEntry() + : tracing_id_(g_next_tracing_id_.GetNext()) {} +SoftwareImageDecodeCacheUtils::CacheEntry::CacheEntry( + const SkImageInfo& info, + std::unique_ptr<base::DiscardableMemory> in_memory, + const SkSize& src_rect_offset) + : is_locked(true), + memory(std::move(in_memory)), + image_info_(info), + src_rect_offset_(src_rect_offset), + tracing_id_(g_next_tracing_id_.GetNext()) { + DCHECK(memory); + SkPixmap pixmap(image_info_, memory->data(), image_info_.minRowBytes()); + image_ = SkImage::MakeFromRaster( + pixmap, [](const void* pixels, void* context) {}, nullptr); +} + +SoftwareImageDecodeCacheUtils::CacheEntry::~CacheEntry() { + DCHECK(!is_locked); + + // We create temporary CacheEntries as a part of decoding. However, we move + // the memory to cache entries that actually live in the cache. Destroying the + // temporaries should not cause any of the stats to be recorded. Specifically, + // if allowed to report, they would report every single temporary entry as + // wasted, which is misleading. As a fix, don't report on a cache entry that + // has never been in the cache. + if (!cached_) + return; + + // lock_count | used | last lock failed | result state + // ===========+=======+==================+================== + // 1 | false | false | WASTED + // 1 | false | true | WASTED + // 1 | true | false | USED + // 1 | true | true | USED_RELOCK_FAILED + // >1 | false | false | WASTED_RELOCKED + // >1 | false | true | WASTED_RELOCKED + // >1 | true | false | USED_RELOCKED + // >1 | true | true | USED_RELOCKED + // Note that it's important not to reorder the following enums, since the + // numerical values are used in the histogram code. + enum State : int { + DECODED_IMAGE_STATE_WASTED, + DECODED_IMAGE_STATE_USED, + DECODED_IMAGE_STATE_USED_RELOCK_FAILED, + DECODED_IMAGE_STATE_WASTED_RELOCKED, + DECODED_IMAGE_STATE_USED_RELOCKED, + DECODED_IMAGE_STATE_COUNT + } state = DECODED_IMAGE_STATE_WASTED; + + if (usage_stats_.lock_count == 1) { + if (!usage_stats_.used) + state = DECODED_IMAGE_STATE_WASTED; + else if (usage_stats_.last_lock_failed) + state = DECODED_IMAGE_STATE_USED_RELOCK_FAILED; + else + state = DECODED_IMAGE_STATE_USED; + } else { + if (usage_stats_.used) + state = DECODED_IMAGE_STATE_USED_RELOCKED; + else + state = DECODED_IMAGE_STATE_WASTED_RELOCKED; + } + + UMA_HISTOGRAM_ENUMERATION("Renderer4.SoftwareImageDecodeState", state, + DECODED_IMAGE_STATE_COUNT); + UMA_HISTOGRAM_BOOLEAN("Renderer4.SoftwareImageDecodeState.FirstLockWasted", + usage_stats_.first_lock_wasted); + if (usage_stats_.first_lock_out_of_raster) + UMA_HISTOGRAM_BOOLEAN( + "Renderer4.SoftwareImageDecodeState.FirstLockWasted.OutOfRaster", + usage_stats_.first_lock_wasted); +} + +void SoftwareImageDecodeCacheUtils::CacheEntry::MoveImageMemoryTo( + CacheEntry* entry) { + DCHECK(!is_budgeted); + DCHECK_EQ(ref_count, 0); + + // Copy/move most things except budgeted and ref counts. + entry->decode_failed = decode_failed; + entry->is_locked = is_locked; + is_locked = false; + + entry->memory = std::move(memory); + entry->image_info_ = std::move(image_info_); + entry->src_rect_offset_ = std::move(src_rect_offset_); + entry->image_ = std::move(image_); +} + +bool SoftwareImageDecodeCacheUtils::CacheEntry::Lock() { + if (!memory) + return false; + + DCHECK(!is_locked); + bool success = memory->Lock(); + if (!success) { + memory = nullptr; + usage_stats_.last_lock_failed = true; + return false; + } + is_locked = true; + ++usage_stats_.lock_count; + return true; +} + +void SoftwareImageDecodeCacheUtils::CacheEntry::Unlock() { + if (!memory) + return; + + DCHECK(is_locked); + memory->Unlock(); + is_locked = false; + if (usage_stats_.lock_count == 1) + usage_stats_.first_lock_wasted = !usage_stats_.used; +} + +} // namespace cc
diff --git a/cc/tiles/software_image_decode_cache_utils.h b/cc/tiles/software_image_decode_cache_utils.h new file mode 100644 index 0000000..875a889 --- /dev/null +++ b/cc/tiles/software_image_decode_cache_utils.h
@@ -0,0 +1,190 @@ +// 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 CC_TILES_SOFTWARE_IMAGE_DECODE_CACHE_UTILS_H_ +#define CC_TILES_SOFTWARE_IMAGE_DECODE_CACHE_UTILS_H_ + +#include "base/memory/discardable_memory.h" +#include "base/memory/scoped_refptr.h" +#include "cc/cc_export.h" +#include "cc/paint/decoded_draw_image.h" +#include "cc/paint/draw_image.h" +#include "cc/paint/paint_image.h" +#include "cc/raster/tile_task.h" +#include "third_party/skia/include/core/SkImage.h" +#include "third_party/skia/include/core/SkImageInfo.h" +#include "third_party/skia/include/core/SkSize.h" +#include "ui/gfx/color_space.h" +#include "ui/gfx/geometry/rect.h" +#include "ui/gfx/geometry/size.h" + +namespace cc { + +class SoftwareImageDecodeCacheUtils { + private: + // The following should only be accessed by the software image cache. + friend class SoftwareImageDecodeCache; + + // CacheKey is a class that gets a cache key out of a given draw + // image. That is, this key uniquely identifies an image in the cache. Note + // that it's insufficient to use SkImage's unique id, since the same image can + // appear in the cache multiple times at different scales and filter + // qualities. + class CC_EXPORT CacheKey { + public: + // Enum indicating the type of processing to do for this key: + // kOriginal - use the original decode without any subrecting or scaling. + // kSubrectOriginal - extract a subrect from the original decode but do not + // scale it. + // kSubrectAndScale - extract a subrect (if needed) from the original decode + // and scale it. + enum ProcessingType { kOriginal, kSubrectOriginal, kSubrectAndScale }; + + static CacheKey FromDrawImage(const DrawImage& image, + SkColorType color_type); + + CacheKey(const CacheKey& other); + + bool operator==(const CacheKey& other) const { + // The frame_key always has to be the same. However, after that all + // original decodes are the same, so if we can use the original decode, + // return true. If not, then we have to compare every field. Note we don't + // compare |nearest_neighbor_| because we would only use kOriginal type in + // that case (dchecked below), which implies no scale. The returned scale + // to Skia would respect the nearest neighbor value of the requested + // image. + DCHECK(!is_nearest_neighbor_ || type_ == kOriginal); + return frame_key_ == other.frame_key_ && type_ == other.type_ && + target_color_space_ == other.target_color_space_ && + (type_ == kOriginal || (src_rect_ == other.src_rect_ && + target_size_ == other.target_size_)); + } + + bool operator!=(const CacheKey& other) const { return !(*this == other); } + + const PaintImage::FrameKey& frame_key() const { return frame_key_; } + ProcessingType type() const { return type_; } + bool is_nearest_neighbor() const { return is_nearest_neighbor_; } + gfx::Rect src_rect() const { return src_rect_; } + gfx::Size target_size() const { return target_size_; } + const gfx::ColorSpace& target_color_space() const { + return target_color_space_; + } + + size_t get_hash() const { return hash_; } + + // Helper to figure out how much memory the locked image represented by this + // key would take. + size_t locked_bytes() const { + // TODO(vmpstr): Handle formats other than RGBA. + base::CheckedNumeric<size_t> result = 4; + result *= target_size_.width(); + result *= target_size_.height(); + return result.ValueOrDefault(std::numeric_limits<size_t>::max()); + } + + std::string ToString() const; + + private: + CacheKey(PaintImage::FrameKey frame_key, + ProcessingType type, + bool is_nearest_neighbor, + const gfx::Rect& src_rect, + const gfx::Size& size, + const gfx::ColorSpace& target_color_space); + + PaintImage::FrameKey frame_key_; + ProcessingType type_; + bool is_nearest_neighbor_; + gfx::Rect src_rect_; + gfx::Size target_size_; + gfx::ColorSpace target_color_space_; + size_t hash_; + }; + + struct CacheKeyHash { + size_t operator()(const CacheKey& key) const { return key.get_hash(); } + }; + + // CacheEntry is a convenience storage for discardable memory. It can also + // construct an image out of SkImageInfo and stored discardable memory. + class CC_EXPORT CacheEntry { + public: + CacheEntry(); + CacheEntry(const SkImageInfo& info, + std::unique_ptr<base::DiscardableMemory> memory, + const SkSize& src_rect_offset); + ~CacheEntry(); + + void MoveImageMemoryTo(CacheEntry* entry); + + sk_sp<SkImage> image() const { + if (!memory) + return nullptr; + DCHECK(is_locked); + return image_; + } + const SkSize& src_rect_offset() const { return src_rect_offset_; } + + bool Lock(); + void Unlock(); + + // An ID which uniquely identifies this CacheEntry within the image decode + // cache. Used in memory tracing. + uint64_t tracing_id() const { return tracing_id_; } + // Mark this image as being used in either a draw or as a source for a + // scaled image. Either case represents this decode as being valuable and + // not wasted. + void mark_used() { usage_stats_.used = true; } + void mark_cached() { cached_ = true; } + void mark_out_of_raster() { usage_stats_.first_lock_out_of_raster = true; } + + // Since this is an inner class, we expose these variables publicly for + // simplicity. + // TODO(vmpstr): A good simple clean-up would be to rethink this class + // and its interactions to instead expose a few functions which would also + // facilitate easier DCHECKs. + int ref_count = 0; + bool decode_failed = false; + bool is_locked = false; + bool is_budgeted = false; + + scoped_refptr<TileTask> in_raster_task; + scoped_refptr<TileTask> out_of_raster_task; + + std::unique_ptr<base::DiscardableMemory> memory; + + private: + struct UsageStats { + // We can only create a decoded image in a locked state, so the initial + // lock count is 1. + int lock_count = 1; + bool used = false; + bool last_lock_failed = false; + bool first_lock_wasted = false; + bool first_lock_out_of_raster = false; + }; + + SkImageInfo image_info_; + sk_sp<SkImage> image_; + SkSize src_rect_offset_; + uint64_t tracing_id_; + UsageStats usage_stats_; + // Indicates whether this entry was ever in the cache. + bool cached_ = false; + }; + + static std::unique_ptr<CacheEntry> DoDecodeImage(const CacheKey& key, + const PaintImage& image, + SkColorType color_type); + static std::unique_ptr<CacheEntry> GenerateCacheEntryFromCandidate( + const CacheKey& key, + const DecodedDrawImage& candidate, + bool needs_extract_subset, + SkColorType color_type); +}; + +} // namespace cc + +#endif // CC_TILES_SOFTWARE_IMAGE_DECODE_CACHE_UTILS_H_
diff --git a/chrome/android/java/res/layout/main.xml b/chrome/android/java/res/layout/main.xml index 055165e..c7602447 100644 --- a/chrome/android/java/res/layout/main.xml +++ b/chrome/android/java/res/layout/main.xml
@@ -54,6 +54,19 @@ android:inflatedId="@+id/bottombar" android:layout="@layout/custom_tabs_bottombar" /> + <ViewStub + android:id="@+id/tab_modal_dialog_container_stub" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:inflatedId="@+id/tab_modal_dialog_container" /> + + <!-- Please do not add anything in between tab_modal_dialog_container_stub and + tab_modal_dialog_container_sibling_view. --> + <ViewStub + android:id="@+id/tab_modal_dialog_container_sibling_view" + android:layout_width="0dp" + android:layout_height="0dp" /> + <org.chromium.chrome.browser.widget.FadingBackgroundView android:id="@+id/fading_focus_target" android:layout_width="match_parent"
diff --git a/chrome/android/java/res/layout/modal_dialog_container.xml b/chrome/android/java/res/layout/modal_dialog_container.xml new file mode 100644 index 0000000..e7a9623 --- /dev/null +++ b/chrome/android/java/res/layout/modal_dialog_container.xml
@@ -0,0 +1,17 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright 2017 The Chromium Authors. All rights reserved. + Use of this source code is governed by a BSD-style license that can be + found in the LICENSE file. --> + +<FrameLayout + xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="match_parent" + android:layout_height="match_parent"> + + <View + android:id="@+id/scrim" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:background="@color/modal_dialog_scrim_color" /> + +</FrameLayout> \ No newline at end of file
diff --git a/chrome/android/java/res/layout/modal_dialog_view.xml b/chrome/android/java/res/layout/modal_dialog_view.xml new file mode 100644 index 0000000..fe5cf07a --- /dev/null +++ b/chrome/android/java/res/layout/modal_dialog_view.xml
@@ -0,0 +1,60 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright 2017 The Chromium Authors. All rights reserved. + Use of this source code is governed by a BSD-style license that can be + found in the LICENSE file. --> + +<!-- TODO(huayinz): rename menu_bg or change the dialog background to the desired one. --> +<org.chromium.chrome.browser.widget.BoundedLinearLayout + xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:chrome="http://schemas.android.com/apk/res-auto" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:orientation="vertical" + android:background="@drawable/menu_bg" + chrome:maxWidth="@dimen/dialog_max_width"> + + <android.support.v7.widget.DialogTitle + android:id="@+id/title" + android:textAppearance="@style/BlackHeadline2" + style="@style/AlertDialogContent" /> + + <ScrollView + android:layout_height="0dp" + android:layout_weight="1" + style="@style/AlertDialogContent"> + + <org.chromium.ui.widget.TextViewWithLeading + android:id="@+id/message" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:textAppearance="@style/BlackBody" + chrome:leading="20sp" /> + + </ScrollView> + + <FrameLayout + android:id="@+id/custom" + android:layout_width="match_parent" + android:layout_height="0dp" + android:layout_weight="1" /> + + <android.support.v7.widget.ButtonBarLayout + android:layout_width="match_parent" + android:layout_height="wrap_content" + style="?attr/buttonBarStyle" > + + <Button + android:id="@+id/negative_button" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + style="?attr/buttonBarNegativeButtonStyle" /> + + <Button + android:id="@+id/positive_button" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + style="?attr/buttonBarPositiveButtonStyle" /> + + </android.support.v7.widget.ButtonBarLayout> + +</org.chromium.chrome.browser.widget.BoundedLinearLayout> \ No newline at end of file
diff --git a/chrome/android/java/res/layout/promo_dialog_layout.xml b/chrome/android/java/res/layout/promo_dialog_layout.xml index a9653c7..ce46e3a 100644 --- a/chrome/android/java/res/layout/promo_dialog_layout.xml +++ b/chrome/android/java/res/layout/promo_dialog_layout.xml
@@ -19,7 +19,7 @@ android:layout_gravity="center" android:orientation="vertical" android:background="@drawable/menu_bg" - chrome:maxWidth="@dimen/promo_dialog_max_width" > + chrome:maxWidth="@dimen/dialog_max_width" > <org.chromium.chrome.browser.widget.FadingEdgeScrollView android:id="@+id/promo_container"
diff --git a/chrome/android/java/res/values-v17/styles.xml b/chrome/android/java/res/values-v17/styles.xml index 78901f8..b9de644e 100644 --- a/chrome/android/java/res/values-v17/styles.xml +++ b/chrome/android/java/res/values-v17/styles.xml
@@ -124,6 +124,29 @@ <item name="chrometint">@color/dark_mode_tint</item> </style> + <style name="ModalDialogTheme" parent="AlertDialogTheme"> + <item name="android:windowFrame">@null</item> + <item name="android:backgroundDimEnabled">false</item> + <item name="android:windowBackground">@android:color/transparent</item> + <item name="android:windowMinWidthMajor">100%</item> + <item name="android:windowMinWidthMinor">100%</item> + <item name="buttonBarStyle">@style/ModalDialogButtonBarStyle</item> + <item name="buttonBarButtonStyle">@style/ModalDialogButtonStyle</item> + </style> + + <style name="ModalDialogButtonBarStyle" parent="Widget.AppCompat.ButtonBar.AlertDialog"> + <item name="android:orientation">horizontal</item> + <item name="android:gravity">bottom|end</item> + <item name="android:paddingStart">@dimen/modal_dialog_control_padding_horizontal</item> + <item name="android:paddingEnd">@dimen/modal_dialog_control_padding_horizontal</item> + <item name="android:paddingTop">@dimen/modal_dialog_control_padding_vertical</item> + <item name="android:paddingBottom">@dimen/modal_dialog_control_padding_vertical</item> + </style> + + <style name="ModalDialogButtonStyle" parent="Widget.AppCompat.Button.ButtonBar.AlertDialog"> + <item name="android:textColor">@color/light_active_color</item> + </style> + <style name="SimpleDialog" parent="AlertDialogTheme"> <item name="windowNoTitle">true</item> <item name="windowActionBar">false</item>
diff --git a/chrome/android/java/res/values/dimens.xml b/chrome/android/java/res/values/dimens.xml index 46f34d4..9558983f 100644 --- a/chrome/android/java/res/values/dimens.xml +++ b/chrome/android/java/res/values/dimens.xml
@@ -139,7 +139,6 @@ <dimen name="promo_dialog_illustration_margin">24dp</dimen> <dimen name="promo_dialog_illustration_width">150dp</dimen> <dimen name="promo_dialog_padding">16dp</dimen> - <dimen name="promo_dialog_max_width">600dp</dimen> <dimen name="promo_dialog_max_content_width">320dp</dimen> <dimen name="promo_dialog_min_scrollable_height">100dp</dimen> <dimen name="promo_dialog_title_text_size">23sp</dimen> @@ -190,6 +189,12 @@ <!-- Alert dialog --> <dimen name="dialog_padding_top">@dimen/abc_dialog_padding_top_material</dimen> <dimen name="dialog_padding_sides">@dimen/abc_dialog_padding_material</dimen> + <dimen name="dialog_max_width">600dp</dimen> + + <!-- ModalDialogView dimensions --> + <dimen name="modal_dialog_control_padding_vertical">4dp</dimen> + <dimen name="modal_dialog_control_padding_horizontal">12dp</dimen> + <dimen name="tab_modal_scrim_vertical_margin">16dp</dimen> <!-- Tab Strip Dimensions --> <dimen name="tab_strip_height">0dp</dimen>
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ApplicationInitialization.java b/chrome/android/java/src/org/chromium/chrome/browser/ApplicationInitialization.java index 9f15f0e..74dd974e 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/ApplicationInitialization.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/ApplicationInitialization.java
@@ -10,7 +10,6 @@ import org.chromium.base.CommandLine; import org.chromium.chrome.R; -import org.chromium.content.app.ContentApplication; import org.chromium.content.common.ContentSwitches; @@ -29,7 +28,7 @@ */ public static void enableFullscreenFlags( Resources resources, Context context, int resControlContainerHeight) { - ContentApplication.initCommandLine(context); + ((ChromeApplication) context.getApplicationContext()).initCommandLine(); CommandLine commandLine = CommandLine.getInstance(); if (commandLine.hasSwitch(ChromeSwitches.DISABLE_FULLSCREEN)) return;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ChromeActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/ChromeActivity.java index 87f328ff..4801a7c 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/ChromeActivity.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/ChromeActivity.java
@@ -93,6 +93,8 @@ import org.chromium.chrome.browser.metrics.StartupMetrics; import org.chromium.chrome.browser.metrics.UmaSessionStats; import org.chromium.chrome.browser.metrics.WebApkUma; +import org.chromium.chrome.browser.modaldialog.AppModalPresenter; +import org.chromium.chrome.browser.modaldialog.ModalDialogManager; import org.chromium.chrome.browser.multiwindow.MultiWindowUtils; import org.chromium.chrome.browser.net.spdyproxy.DataReductionProxySettings; import org.chromium.chrome.browser.nfc.BeamController; @@ -246,6 +248,7 @@ private ContextualSearchManager mContextualSearchManager; protected ReaderModeManager mReaderModeManager; private SnackbarManager mSnackbarManager; + private ModalDialogManager mModalDialogManager; private DataUseSnackbarController mDataUseSnackbarController; private DataReductionPromoSnackbarController mDataReductionPromoSnackbarController; private AppMenuPropertiesDelegate mAppMenuPropertiesDelegate; @@ -390,6 +393,8 @@ mBottomSheetContentController.init(mBottomSheet, mTabModelSelector, this); } ((BottomContainer) findViewById(R.id.bottom_container)).initialize(mFullscreenManager); + + mModalDialogManager = createModalDialogManager(); } @Override @@ -1180,6 +1185,21 @@ return mSnackbarManager; } + /** + * @return The {@link ModalDialogManager} created for this class. + */ + protected ModalDialogManager createModalDialogManager() { + return new ModalDialogManager(new AppModalPresenter(this), ModalDialogManager.APP_MODAL); + } + + /** + * @return The {@link ModalDialogManager} that manages the display of modal dialogs (e.g. + * JavaScript dialogs). + */ + public ModalDialogManager getModalDialogManager() { + return mModalDialogManager; + } + protected Drawable getBackgroundDrawable() { return new ColorDrawable( ApiCompatibilityUtils.getColor(getResources(), R.color.light_background_color));
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 689b2689..53eb1f5 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/ChromeApplication.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/ChromeApplication.java
@@ -98,7 +98,6 @@ InvalidStartupDialog.show(activity, e.getErrorCode()); } - @Override public void initCommandLine() { CommandLineInitUtil.initCommandLine(this, COMMAND_LINE_FILE); }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ChromeSwitches.java b/chrome/android/java/src/org/chromium/chrome/browser/ChromeSwitches.java index da1c84a2..a21a4963 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/ChromeSwitches.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/ChromeSwitches.java
@@ -184,6 +184,10 @@ /** Switch for enabling the Chrome Home Survey. */ public static final String CHROME_HOME_FORCE_ENABLE_SURVEY = "force-enable-chrome-home-survey"; + /** Switch to enable incognito tabs to be seen in Android Recents. */ + public static final String ENABLE_INCOGNITO_SNAPSHOTS_IN_ANDROID_RECENTS = + "enable-incognito-snapshots-in-android-recents"; + /** * Don't crash on undispatched VIEW intents sent to .Main. * See ChromeTabbedActivity.maybeDispatchExplicitMainViewIntent() for more info.
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java index d2b60139..869cf8c 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java
@@ -78,6 +78,7 @@ import org.chromium.chrome.browser.fullscreen.ChromeFullscreenManager; import org.chromium.chrome.browser.fullscreen.ComposedBrowserControlsVisibilityDelegate; import org.chromium.chrome.browser.incognito.IncognitoNotificationManager; +import org.chromium.chrome.browser.incognito.IncognitoTabSnapshotController; import org.chromium.chrome.browser.infobar.DataReductionPromoInfoBar; import org.chromium.chrome.browser.locale.LocaleManager; import org.chromium.chrome.browser.metrics.ActivityStopMetrics; @@ -85,6 +86,8 @@ import org.chromium.chrome.browser.metrics.MainIntentBehaviorMetrics; import org.chromium.chrome.browser.metrics.StartupMetrics; import org.chromium.chrome.browser.metrics.UmaUtils; +import org.chromium.chrome.browser.modaldialog.ModalDialogManager; +import org.chromium.chrome.browser.modaldialog.TabModalLifetimeHandler; import org.chromium.chrome.browser.multiwindow.MultiInstanceChromeTabbedActivity; import org.chromium.chrome.browser.multiwindow.MultiWindowUtils; import org.chromium.chrome.browser.net.spdyproxy.DataReductionProxySettings; @@ -261,6 +264,8 @@ private ScreenshotMonitor mScreenshotMonitor; + private TabModalLifetimeHandler mTabModalHandler; + private boolean mUIInitialized; private Boolean mMergeTabsOnResume; @@ -893,6 +898,12 @@ mScreenshotMonitor = ScreenshotMonitor.create(ChromeTabbedActivity.this); + if (!CommandLine.getInstance().hasSwitch( + ChromeSwitches.ENABLE_INCOGNITO_SNAPSHOTS_IN_ANDROID_RECENTS)) { + IncognitoTabSnapshotController.createIncognitoTabSnapshotController( + getWindow(), mLayoutManager, mTabModelSelectorImpl); + } + mUIInitialized = true; } finally { TraceEvent.end("ChromeTabbedActivity.initializeUI"); @@ -1901,6 +1912,8 @@ super.onOmniboxFocusChanged(hasFocus); mMainIntentMetrics.onOmniboxFocused(); + + mTabModalHandler.onOmniboxFocusChanged(hasFocus); } private void recordBackPressedUma(String logMessage, @BackPressedResult int action) { @@ -1942,6 +1955,8 @@ if (getBottomSheet() != null && getBottomSheet().handleBackPress()) return true; + if (mTabModalHandler.handleBackPress()) return true; + if (currentTab == null) { recordBackPressedUma("currentTab is null", BACK_PRESSED_TAB_IS_NULL); moveTaskToBack(true); @@ -2158,6 +2173,11 @@ mUndoBarPopupController = null; } + if (mTabModalHandler != null) { + mTabModalHandler.destroy(); + mTabModalHandler = null; + } + super.onDestroyInternal(); FeatureUtilities.finalizePendingFeatures(); @@ -2212,6 +2232,13 @@ return getLayoutManager().getOverviewListLayout(); } + @Override + protected ModalDialogManager createModalDialogManager() { + ModalDialogManager manager = super.createModalDialogManager(); + mTabModalHandler = new TabModalLifetimeHandler(this, manager); + return manager; + } + // App Menu related code ----------------------------------------------------------------------- @Override
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabsConnection.java b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabsConnection.java index c76f8d38..22eeaeb8 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabsConnection.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabsConnection.java
@@ -29,7 +29,6 @@ import org.json.JSONException; import org.json.JSONObject; -import org.chromium.base.BaseChromiumApplication; import org.chromium.base.CommandLine; import org.chromium.base.ContextUtils; import org.chromium.base.Log; @@ -219,7 +218,7 @@ super(); mContext = ContextUtils.getApplicationContext(); // Command line switch values are used below. - BaseChromiumApplication.initCommandLine(mContext); + ((ChromeApplication) mContext).initCommandLine(); mClientManager = new ClientManager(mContext); mLogRequests = CommandLine.getInstance().hasSwitch(LOG_SERVICE_REQUESTS); }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/incognito/IncognitoTabSnapshotController.java b/chrome/android/java/src/org/chromium/chrome/browser/incognito/IncognitoTabSnapshotController.java new file mode 100644 index 0000000..ec4049c --- /dev/null +++ b/chrome/android/java/src/org/chromium/chrome/browser/incognito/IncognitoTabSnapshotController.java
@@ -0,0 +1,110 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package org.chromium.chrome.browser.incognito; + +import android.view.Window; +import android.view.WindowManager; + +import org.chromium.base.VisibleForTesting; +import org.chromium.chrome.browser.compositor.layouts.LayoutManagerChrome; +import org.chromium.chrome.browser.compositor.layouts.OverviewModeBehavior.OverviewModeObserver; +import org.chromium.chrome.browser.tabmodel.EmptyTabModelSelectorObserver; +import org.chromium.chrome.browser.tabmodel.TabModelSelector; + +/** + * This is the controller that prevents incognito tabs from being visible in Android Recents. + */ +public class IncognitoTabSnapshotController + extends EmptyTabModelSelectorObserver implements OverviewModeObserver { + private final Window mWindow; + private final TabModelSelector mTabModelSelector; + private boolean mInOverviewMode; + + /** + * Creates and registers a new {@link IncognitoTabSnapshotController}. + * @param window The {@link Window} containing the flags to which the secure flag will be added + * and cleared. + * @param layoutManager The {@link LayoutManagerChrome} where this controller will be added. + * @param tabModelSelector The {@link TabModelSelector} from where tab information will be + * extracted. + */ + public static void createIncognitoTabSnapshotController( + Window window, LayoutManagerChrome layoutManager, TabModelSelector tabModelSelector) { + new IncognitoTabSnapshotController(window, layoutManager, tabModelSelector); + } + + @VisibleForTesting + IncognitoTabSnapshotController( + Window window, LayoutManagerChrome layoutManager, TabModelSelector tabModelSelector) { + mWindow = window; + mTabModelSelector = tabModelSelector; + + layoutManager.addOverviewModeObserver(this); + tabModelSelector.addObserver(this); + } + + @Override + public void onOverviewModeStartedShowing(boolean showToolbar) { + mInOverviewMode = true; + updateIncognitoState(); + } + + @Override + public void onOverviewModeFinishedShowing() {} + + @Override + public void onOverviewModeStartedHiding(boolean showToolbar, boolean delayAnimation) { + mInOverviewMode = false; + } + + @Override + public void onOverviewModeFinishedHiding() {} + + @Override + public void onChange() { + updateIncognitoState(); + } + + /** + * Sets the attributes flags to secure if there is an incognito tab visible. + */ + @VisibleForTesting + void updateIncognitoState() { + WindowManager.LayoutParams attributes = mWindow.getAttributes(); + boolean currentSecureState = (attributes.flags & WindowManager.LayoutParams.FLAG_SECURE) + == WindowManager.LayoutParams.FLAG_SECURE; + boolean expectedSecureState = isShowingIncognito(); + if (currentSecureState == expectedSecureState) return; + + if (expectedSecureState) { + mWindow.addFlags(WindowManager.LayoutParams.FLAG_SECURE); + } else { + mWindow.clearFlags(WindowManager.LayoutParams.FLAG_SECURE); + } + } + + /** + * @return Whether an incognito tab is visible. + */ + @VisibleForTesting + boolean isShowingIncognito() { + boolean isInIncognitoModel = mTabModelSelector.getCurrentModel().isIncognito(); + // Chrome Home is in overview mode when creating new tabs. + return isInIncognitoModel || (mInOverviewMode && getIncognitoTabCount() > 0); + } + + // Set in overview mode for testing. + @VisibleForTesting + public void setInOverViewMode(boolean overviewMode) { + mInOverviewMode = overviewMode; + } + + /** + * @return The number of incognito tabs. + */ + private int getIncognitoTabCount() { + return mTabModelSelector.getModel(true).getCount(); + } +}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/init/ChromeBrowserInitializer.java b/chrome/android/java/src/org/chromium/chrome/browser/init/ChromeBrowserInitializer.java index e22e90f..0f6b678 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/init/ChromeBrowserInitializer.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/init/ChromeBrowserInitializer.java
@@ -43,7 +43,6 @@ import org.chromium.chrome.browser.webapps.ActivityAssigner; import org.chromium.chrome.browser.webapps.ChromeWebApkHost; import org.chromium.components.crash.browser.CrashDumpManager; -import org.chromium.content.app.ContentApplication; import org.chromium.content.browser.BrowserStartupController; import org.chromium.content.browser.DeviceUtils; import org.chromium.content.browser.SpeechRecognition; @@ -211,7 +210,7 @@ // Ensure critical files are available, so they aren't blocked on the file-system // behind long-running accesses in next phase. // Don't do any large file access here! - ContentApplication.initCommandLine(mApplication); + mApplication.initCommandLine(); ChromeStrictMode.configureStrictMode(); ChromeWebApkHost.init();
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/jsdialog/JavascriptModalDialogView.java b/chrome/android/java/src/org/chromium/chrome/browser/jsdialog/JavascriptModalDialogView.java new file mode 100644 index 0000000..41f3f76 --- /dev/null +++ b/chrome/android/java/src/org/chromium/chrome/browser/jsdialog/JavascriptModalDialogView.java
@@ -0,0 +1,122 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package org.chromium.chrome.browser.jsdialog; + +import android.support.annotation.StringRes; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.CheckBox; +import android.widget.EditText; +import android.widget.TextView; + +import org.chromium.chrome.R; +import org.chromium.chrome.browser.modaldialog.ModalDialogView; + +/** + * The JavaScript dialog that is either app modal or tab modal. + */ +public class JavascriptModalDialogView extends ModalDialogView { + private final TextView mMessageView; + private final EditText mPromptEditText; + private final CheckBox mSuppressCheckBox; + private final View mScrollView; + + /** + * Create a {@link JavascriptModalDialogView} with the specified properties. + * @param controller The controller for the dialog view. + * @param title The title of the dialog view. + * @param message The message of the dialog view. + * @param promptText The promptText of the dialog view. If null, + * prompt edit text will not be shown. + * @param shouldShowSuppressCheckBox Whether the suppress check box should be shown. + * @param positiveButtonTextId The string resource id of the positive button. + * @param negativeButtonTextId The string resource id of the negative button. + * @return A {@link JavascriptModalDialogView} with the specified properties. + */ + public static JavascriptModalDialogView create(Controller controller, String title, + String message, String promptText, boolean shouldShowSuppressCheckBox, + @StringRes int positiveButtonTextId, @StringRes int negativeButtonTextId) { + Params params = new Params(); + params.title = title; + params.positiveButtonTextId = positiveButtonTextId; + params.negativeButtonTextId = negativeButtonTextId; + return new JavascriptModalDialogView( + controller, params, message, promptText, shouldShowSuppressCheckBox); + } + + private JavascriptModalDialogView(Controller controller, Params params, String message, + String promptText, boolean shouldShowSuppressCheckBox) { + super(controller, params); + + LayoutInflater inflater = LayoutInflater.from(getContext()); + View customLayout = inflater.inflate(R.layout.js_modal_dialog, null); + params.customView = customLayout; + + mScrollView = params.customView.findViewById(R.id.js_modal_dialog_scroll_view); + mMessageView = customLayout.findViewById(R.id.js_modal_dialog_message); + mPromptEditText = customLayout.findViewById(R.id.js_modal_dialog_prompt); + mSuppressCheckBox = customLayout.findViewById(R.id.suppress_js_modal_dialogs); + + mMessageView.setText(message); + setPromptText(promptText); + setSuppressCheckBoxVisibility(shouldShowSuppressCheckBox); + } + + @Override + protected void prepareBeforeShow() { + super.prepareBeforeShow(); + // If the message is null or empty do not display the message text view. + // Hide parent scroll view instead of text view in order to prevent ui discrepancies. + if (mMessageView.getText().length() == 0) { + mScrollView.setVisibility(View.GONE); + } else { + // TODO(huayinz): See if View#canScrollVertictically() can be used for checking if + // scrollView is scrollable. + mScrollView.addOnLayoutChangeListener( + (v, left, top, right, bottom, oldLeft, oldTop, oldRight, oldBottom) -> { + boolean isScrollable = + v.getMeasuredHeight() - v.getPaddingTop() - v.getPaddingBottom() + < ((ViewGroup) v).getChildAt(0).getMeasuredHeight(); + v.setFocusable(isScrollable); + }); + } + } + + /** + * @param promptText Prompt text for prompt dialog. If null, prompt text is not visible. + */ + private void setPromptText(String promptText) { + if (promptText == null) return; + mPromptEditText.setVisibility(View.VISIBLE); + + if (promptText.length() > 0) { + mPromptEditText.setText(promptText); + mPromptEditText.selectAll(); + } + } + + /** + * @return The prompt text edited by user. + */ + public String getPromptText() { + return mPromptEditText.getText().toString(); + } + + /** + * @param visible Whether the suppress check box should be visible. The check box should only + * be set visible if applicable for app modal JavaScript dialogs. + */ + private void setSuppressCheckBoxVisibility(boolean visible) { + mSuppressCheckBox.setVisibility(visible ? View.VISIBLE : View.GONE); + } + + /** + * @return Whether the suppress check box is checked by user. + */ + public boolean isSuppressCheckBoxChecked() { + return mSuppressCheckBox.isChecked(); + } +}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/modaldialog/AppModalPresenter.java b/chrome/android/java/src/org/chromium/chrome/browser/modaldialog/AppModalPresenter.java new file mode 100644 index 0000000..d678a37b --- /dev/null +++ b/chrome/android/java/src/org/chromium/chrome/browser/modaldialog/AppModalPresenter.java
@@ -0,0 +1,47 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package org.chromium.chrome.browser.modaldialog; + +import android.app.Activity; +import android.app.Dialog; +import android.view.Gravity; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.FrameLayout; + +import org.chromium.chrome.R; +import org.chromium.chrome.browser.widget.AlwaysDismissedDialog; + +/** The presenter that shows a {@link ModalDialogView} in an Android dialog. */ +public class AppModalPresenter extends ModalDialogManager.Presenter { + private final Activity mActivity; + private Dialog mDialog; + + public AppModalPresenter(Activity activity) { + mActivity = activity; + } + + @Override + protected void addDialogView(View dialogView) { + mDialog = new AlwaysDismissedDialog(mActivity, R.style.ModalDialogTheme); + mDialog.setOnCancelListener(dialogInterface -> cancelCurrentDialog()); + ViewGroup container = (ViewGroup) LayoutInflater.from(mActivity).inflate( + R.layout.modal_dialog_container, null); + mDialog.setContentView(container); + FrameLayout.LayoutParams params = + new FrameLayout.LayoutParams(ViewGroup.MarginLayoutParams.MATCH_PARENT, + ViewGroup.MarginLayoutParams.WRAP_CONTENT, Gravity.CENTER); + container.addView(dialogView, params); + mDialog.show(); + } + + @Override + protected void removeDialogView(View dialogView) { + // Dismiss the currently showing dialog. + if (mDialog != null) mDialog.dismiss(); + mDialog = null; + } +}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/modaldialog/ModalDialogManager.java b/chrome/android/java/src/org/chromium/chrome/browser/modaldialog/ModalDialogManager.java new file mode 100644 index 0000000..865c2b5f --- /dev/null +++ b/chrome/android/java/src/org/chromium/chrome/browser/modaldialog/ModalDialogManager.java
@@ -0,0 +1,215 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package org.chromium.chrome.browser.modaldialog; + +import android.support.annotation.IntDef; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; +import android.util.Pair; +import android.util.SparseArray; +import android.view.View; + +import org.chromium.base.VisibleForTesting; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.util.ArrayList; +import java.util.List; + +/** + * Manager for managing the display of a queue of {@link ModalDialogView}s. + */ +public class ModalDialogManager { + /** + * Present a {@link ModalDialogView} in a container. + */ + public static abstract class Presenter { + private Runnable mCancelCallback; + private ModalDialogView mModalDialog; + private View mCurrentView; + + /** + * @param dialog The dialog that's currently showing in this presenter. If null, no dialog + * is currently showing. + */ + private void setModalDialog( + @Nullable ModalDialogView dialog, @Nullable Runnable cancelCallback) { + if (dialog == null) { + removeDialogView(mCurrentView); + mModalDialog = null; + mCancelCallback = null; + } else { + assert mModalDialog + == null : "Should call setModalDialog(null) before setting a modal dialog."; + mModalDialog = dialog; + mCurrentView = dialog.getView(); + mCancelCallback = cancelCallback; + addDialogView(mCurrentView); + } + } + + /** + * Run the cached cancel callback and reset the cached callback. + */ + protected final void cancelCurrentDialog() { + if (mCancelCallback == null) return; + + // Set #mCancelCallback to null before calling the callback to avoid it being + // updated during the callback. + Runnable callback = mCancelCallback; + mCancelCallback = null; + callback.run(); + } + + /** + * @return The modal dialog that this presenter is showing. + */ + protected final ModalDialogView getModalDialog() { + return mModalDialog; + } + + /** + * Add the specified {@link ModalDialogView} in a container. + * @param dialogView The {@link ModalDialogView} that needs to be shown. + */ + protected abstract void addDialogView(View dialogView); + + /** + * Remove the specified {@link ModalDialogView} from a container. + * @param dialogView The {@link ModalDialogView} that needs to be removed. + */ + protected abstract void removeDialogView(View dialogView); + } + + @Retention(RetentionPolicy.SOURCE) + @IntDef({APP_MODAL, TAB_MODAL}) + public @interface ModalDialogType {} + public static final int APP_MODAL = 0; + public static final int TAB_MODAL = 1; + + /** Mapping of the {@link Presenter}s and the type of dialogs they are showing. */ + private final SparseArray<Presenter> mPresenters = new SparseArray<>(); + + /** The list of pending dialogs */ + private final List<Pair<ModalDialogView, Integer>> mPendingDialogs = new ArrayList<>(); + + /** The default presenter to be used if a specified type is not supported. */ + private final Presenter mDefaultPresenter; + + /** The presenter of the type of the dialog that is currently showing. */ + private Presenter mCurrentPresenter; + + /** + * Constructor for initializing default {@link Presenter}. + * @param defaultPresenter The default presenter to be used when no presenter specified. + * @param defaultType The dialog type of the default presenter. + */ + public ModalDialogManager( + @NonNull Presenter defaultPresenter, @ModalDialogType int defaultType) { + mDefaultPresenter = defaultPresenter; + registerPresenter(defaultPresenter, defaultType); + } + + /** + * Register a {@link Presenter} that shows a specific type of dialog. Note that only one + * presenter of each type can be registered. + * @param presenter The {@link Presenter} to be registered. + * @param dialogType The type of the dialog shown by the specified presenter. + */ + public void registerPresenter(Presenter presenter, @ModalDialogType int dialogType) { + assert mPresenters.get(dialogType) + == null : "Only one presenter can be registered for each type."; + mPresenters.put(dialogType, presenter); + } + + /** + * @return Whether a dialog is currently showing. + */ + public boolean isShowing() { + return mCurrentPresenter != null; + } + + /** + * Show the specified dialog. If another dialog is currently showing, the specified dialog will + * be added to the pending dialog list. + * @param dialog The dialog to be shown or added to pending list. + * @param dialogType The type of the dialog to be shown. + */ + public void showDialog(ModalDialogView dialog, @ModalDialogType int dialogType) { + if (isShowing()) { + mPendingDialogs.add(Pair.create(dialog, dialogType)); + return; + } + + dialog.prepareBeforeShow(); + mCurrentPresenter = mPresenters.get(dialogType, mDefaultPresenter); + mCurrentPresenter.setModalDialog(dialog, () -> cancelDialog(dialog)); + } + + /** + * Dismiss the specified dialog. If the dialog is not currently showing, it will be removed from + * the pending dialog list. + * @param dialog The dialog to be dismissed or removed from pending list. + */ + public void dismissDialog(ModalDialogView dialog) { + if (dialog != mCurrentPresenter.getModalDialog()) { + for (int i = 0; i < mPendingDialogs.size(); ++i) { + if (mPendingDialogs.get(i).first == dialog) { + mPendingDialogs.remove(i); + break; + } + } + return; + } + + if (!isShowing()) return; + assert dialog == mCurrentPresenter.getModalDialog(); + + mCurrentPresenter.setModalDialog(null, null); + mCurrentPresenter = null; + + if (!mPendingDialogs.isEmpty()) { + Pair<ModalDialogView, Integer> nextDialog = mPendingDialogs.remove(0); + showDialog(nextDialog.first, nextDialog.second); + } + } + + /** + * Cancel showing the specified dialog. This is essentially the same as + * {@link #dismissDialog(ModalDialogView)} but will also call the onCancelled callback from the + * modal dialog. + * @param dialog The dialog to be cancelled. + */ + public void cancelDialog(ModalDialogView dialog) { + dismissDialog(dialog); + dialog.getController().onCancel(); + } + + /** + * Dismiss the dialog currently shown and remove all pending dialogs and call the onCancelled + * callbacks from the modal dialogs. + */ + protected void cancelAllDialogs() { + while (!mPendingDialogs.isEmpty()) { + mPendingDialogs.remove(0).first.getController().onCancel(); + } + if (isShowing()) cancelDialog(mCurrentPresenter.getModalDialog()); + } + + @VisibleForTesting + List getPendingDialogsForTest() { + return mPendingDialogs; + } + + @VisibleForTesting + Presenter getPresenterForTest(@ModalDialogType int dialogType) { + return mPresenters.get(dialogType); + } + + @VisibleForTesting + Presenter getCurrentPresenterForTest() { + return mCurrentPresenter; + } +}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/modaldialog/ModalDialogView.java b/chrome/android/java/src/org/chromium/chrome/browser/modaldialog/ModalDialogView.java new file mode 100644 index 0000000..53d9a5d0 --- /dev/null +++ b/chrome/android/java/src/org/chromium/chrome/browser/modaldialog/ModalDialogView.java
@@ -0,0 +1,172 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package org.chromium.chrome.browser.modaldialog; + +import android.content.Context; +import android.support.annotation.IntDef; +import android.support.annotation.NonNull; +import android.support.annotation.StringRes; +import android.text.TextUtils; +import android.view.ContextThemeWrapper; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.Button; +import android.widget.TextView; + +import org.chromium.base.ContextUtils; +import org.chromium.chrome.R; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +/** + * Generic builder for app modal or tab modal alert dialogs. + */ +public class ModalDialogView implements View.OnClickListener { + /** + * Interface that controls the actions on the modal dialog. + */ + public interface Controller { + /** + * Handle click event of the buttons on the dialog. + * @param buttonType The type of the button. + */ + void onClick(@ButtonType int buttonType); + + /** + * Handle dismiss event when the dialog is not dismissed by actions on the dialog such as + * back press, and on tab modal dialog, tab switcher button click. + */ + void onCancel(); + } + + /** Parameters that can be used to create a new ModalDialogView. */ + public static class Params { + /** Optional: The String to show as the dialog title. */ + public String title; + + /** Optional: The String to show as descriptive text. */ + public String message; + + /** + * Optional: The customized View to show in the dialog. Note that the message and the + * custom view cannot be set together. + */ + public View customView; + + /** Optional: Resource ID of the String to show on the positive button. */ + public @StringRes int positiveButtonTextId; + + /** Optional: Resource ID of the String to show on the negative button. */ + public @StringRes int negativeButtonTextId; + } + + @IntDef({BUTTON_POSITIVE, BUTTON_NEGATIVE}) + @Retention(RetentionPolicy.SOURCE) + public @interface ButtonType {} + public static final int BUTTON_POSITIVE = 0; + public static final int BUTTON_NEGATIVE = 1; + + private final Controller mController; + private final Context mContext; + private final Params mParams; + + private final View mDialogView; + private final TextView mTitleView; + private final TextView mMessageView; + private final ViewGroup mCustomView; + private final Button mPositiveButton; + private final Button mNegativeButton; + + /** + * Constructor for initializing controller and views. + * @param controller The controller for this dialog. + */ + public ModalDialogView(@NonNull Controller controller, @NonNull Params params) { + mController = controller; + mContext = new ContextThemeWrapper( + ContextUtils.getApplicationContext(), R.style.ModalDialogTheme); + mParams = params; + + mDialogView = LayoutInflater.from(mContext).inflate(R.layout.modal_dialog_view, null); + mTitleView = mDialogView.findViewById(R.id.title); + mMessageView = mDialogView.findViewById(R.id.message); + mCustomView = mDialogView.findViewById(R.id.custom); + mPositiveButton = mDialogView.findViewById(R.id.positive_button); + mNegativeButton = mDialogView.findViewById(R.id.negative_button); + } + + @Override + public void onClick(View view) { + if (view == mPositiveButton) { + mController.onClick(BUTTON_POSITIVE); + } else if (view == mNegativeButton) { + mController.onClick(BUTTON_NEGATIVE); + } + } + + /** + * Prepare the contents before showing the dialog. + */ + protected void prepareBeforeShow() { + if (TextUtils.isEmpty(mParams.title)) { + mTitleView.setVisibility(View.GONE); + } else { + mTitleView.setText(mParams.title); + } + + if (TextUtils.isEmpty(mParams.message)) { + ((View) mMessageView.getParent()).setVisibility(View.GONE); + } else { + assert mParams.customView == null; + mMessageView.setText(mParams.message); + } + + if (mParams.customView != null) { + if (mParams.customView.getParent() != null) { + ((ViewGroup) mParams.customView.getParent()).removeView(mParams.customView); + } + mCustomView.addView(mParams.customView); + } else { + mCustomView.setVisibility(View.GONE); + } + + if (mParams.positiveButtonTextId == 0) { + mPositiveButton.setVisibility(View.GONE); + } else { + mPositiveButton.setText(mParams.positiveButtonTextId); + mPositiveButton.setOnClickListener(this); + } + + if (mParams.negativeButtonTextId == 0) { + mNegativeButton.setVisibility(View.GONE); + } else { + mNegativeButton.setText(mParams.negativeButtonTextId); + mNegativeButton.setOnClickListener(this); + } + } + + /** + * @return The {@link Context} with the modal dialog theme set. + */ + public Context getContext() { + return mContext; + } + + /** + * @return The content view of this dialog. + */ + public View getView() { + return mDialogView; + } + + /** + * @return The controller that controls the actions on the dialogs. + */ + public Controller getController() { + return mController; + } +}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/modaldialog/TabModalLifetimeHandler.java b/chrome/android/java/src/org/chromium/chrome/browser/modaldialog/TabModalLifetimeHandler.java new file mode 100644 index 0000000..0a4a2f91 --- /dev/null +++ b/chrome/android/java/src/org/chromium/chrome/browser/modaldialog/TabModalLifetimeHandler.java
@@ -0,0 +1,84 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package org.chromium.chrome.browser.modaldialog; + +import org.chromium.chrome.browser.ChromeActivity; +import org.chromium.chrome.browser.tab.EmptyTabObserver; +import org.chromium.chrome.browser.tab.Tab; +import org.chromium.chrome.browser.tab.TabObserver; +import org.chromium.chrome.browser.tabmodel.TabModel; +import org.chromium.chrome.browser.tabmodel.TabModelSelector; +import org.chromium.chrome.browser.tabmodel.TabModelSelectorTabModelObserver; + +/** + * Class responsible for handling dismissal of a tab modal dialog on user actions outside the tab + * modal dialog. + */ +public class TabModalLifetimeHandler { + /** The observer to dismiss all dialogs when the attached tab is not interactable. */ + private final TabObserver mTabObserver = new EmptyTabObserver() { + @Override + public void onInteractabilityChanged(boolean isInteractable) { + if (!isInteractable && mPresenter.getModalDialog() != null) { + mManager.cancelAllDialogs(); + } + } + }; + + private final ModalDialogManager mManager; + private final TabModalPresenter mPresenter; + private final TabModelSelectorTabModelObserver mTabModelObserver; + private final boolean mHasBottomControls; + + private Tab mActiveTab; + + /** + * @param activity The {@link ChromeActivity} that this handler is attached to. + * @param manager The {@link ModalDialogManager} that this handler handles. + */ + public TabModalLifetimeHandler(ChromeActivity activity, ModalDialogManager manager) { + mManager = manager; + mPresenter = new TabModalPresenter(activity); + mManager.registerPresenter(mPresenter, ModalDialogManager.TAB_MODAL); + mHasBottomControls = activity.getBottomSheet() != null; + + TabModelSelector tabModelSelector = activity.getTabModelSelector(); + mTabModelObserver = new TabModelSelectorTabModelObserver(tabModelSelector) { + @Override + public void didSelectTab(Tab tab, TabModel.TabSelectionType type, int lastId) { + if (mActiveTab != null) mActiveTab.removeObserver(mTabObserver); + mActiveTab = tabModelSelector.getCurrentTab(); + if (mActiveTab != null) mActiveTab.addObserver(mTabObserver); + } + }; + } + + /** + * Notified when the focus of the omnibox has changed. + * @param hasFocus Whether the omnibox currently has focus. + */ + public void onOmniboxFocusChanged(boolean hasFocus) { + // If has bottom controls, the view hierarchy will be updated by mBottomSheetObserver. + if (mPresenter.getModalDialog() != null && !mHasBottomControls) { + mPresenter.updateContainerHierarchy(!hasFocus); + } + } + + /** + * Handle a back press event. + */ + public boolean handleBackPress() { + if (mPresenter.getModalDialog() == null) return false; + mPresenter.cancelCurrentDialog(); + return true; + } + + /** + * Remove any remaining dependencies. + */ + public void destroy() { + mTabModelObserver.destroy(); + } +}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/modaldialog/TabModalPresenter.java b/chrome/android/java/src/org/chromium/chrome/browser/modaldialog/TabModalPresenter.java new file mode 100644 index 0000000..17de173 --- /dev/null +++ b/chrome/android/java/src/org/chromium/chrome/browser/modaldialog/TabModalPresenter.java
@@ -0,0 +1,236 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package org.chromium.chrome.browser.modaldialog; + +import android.content.res.Resources; +import android.view.Gravity; +import android.view.View; +import android.view.ViewGroup; +import android.view.ViewGroup.MarginLayoutParams; +import android.view.ViewStub; +import android.widget.FrameLayout; + +import org.chromium.base.VisibleForTesting; +import org.chromium.chrome.R; +import org.chromium.chrome.browser.ChromeActivity; +import org.chromium.chrome.browser.compositor.bottombar.OverlayPanel; +import org.chromium.chrome.browser.contextualsearch.ContextualSearchManager; +import org.chromium.chrome.browser.tab.Tab; +import org.chromium.chrome.browser.widget.bottomsheet.BottomSheet; +import org.chromium.chrome.browser.widget.bottomsheet.BottomSheetObserver; +import org.chromium.chrome.browser.widget.bottomsheet.EmptyBottomSheetObserver; +import org.chromium.content.browser.ContentViewCore; + +/** + * The presenter that displays a single tab modal dialog. + */ +public class TabModalPresenter extends ModalDialogManager.Presenter { + /** The activity displaying the dialogs. */ + private final ChromeActivity mChromeActivity; + + /** Whether browser controls are at the bottom */ + private final boolean mHasBottomControls; + + /** The active tab of which the dialog will be shown on top. */ + private Tab mActiveTab; + + /** + * The observer to change view hierarchy for the dialog container when the sheet is opened or + * closed. + */ + private BottomSheetObserver mBottomSheetObserver; + + /** The parent view that contains the dialog container. */ + private ViewGroup mContainerParent; + + /** The container view that a dialog to be shown will be attached to. */ + private ViewGroup mDialogContainer; + + /** Whether the dialog container is brought to the front in its parent. */ + private boolean mContainerIsAtFront; + + /** Whether the action bar on selected text is temporarily cleared for showing dialogs. */ + private boolean mDidClearTextControls; + + /** + * The sibling view of the dialog container drawn next in its parent when it should be behind + * browser controls. If BottomSheet is opened or UrlBar is focused, the dialog container should + * be behind the browser controls and the URL suggestions. + */ + private View mDefaultNextSiblingView; + + /** + * Constructor for initializing dialog container. + * @param chromeActivity The activity displaying the dialogs. + */ + public TabModalPresenter(ChromeActivity chromeActivity) { + mChromeActivity = chromeActivity; + mHasBottomControls = mChromeActivity.getBottomSheet() != null; + + if (mHasBottomControls) { + mBottomSheetObserver = new EmptyBottomSheetObserver() { + @Override + public void onSheetOpened(@BottomSheet.StateChangeReason int reason) { + updateContainerHierarchy(false); + } + + @Override + public void onSheetClosed(@BottomSheet.StateChangeReason int reason) { + updateContainerHierarchy(true); + } + }; + } + } + + @Override + protected void addDialogView(View dialogView) { + if (mDialogContainer == null) initDialogContainer(); + setBrowserControlsAccess(true); + mDialogContainer.setVisibility(View.VISIBLE); + + FrameLayout.LayoutParams params = new FrameLayout.LayoutParams( + MarginLayoutParams.MATCH_PARENT, MarginLayoutParams.WRAP_CONTENT, Gravity.CENTER); + mDialogContainer.addView(dialogView, params); + mChromeActivity.addViewObscuringAllTabs(mDialogContainer); + } + + @Override + protected void removeDialogView(View dialogView) { + setBrowserControlsAccess(false); + mDialogContainer.removeView(dialogView); + mDialogContainer.setVisibility(View.GONE); + mChromeActivity.removeViewObscuringAllTabs(mDialogContainer); + } + + /** + * Change view hierarchy for the dialog container to be either the front most or beneath the + * toolbar. + * @param toFront Whether the dialog container should be brought to the front. + */ + void updateContainerHierarchy(boolean toFront) { + if (toFront == mContainerIsAtFront) return; + mContainerIsAtFront = toFront; + if (toFront) { + mDialogContainer.bringToFront(); + } else { + mContainerParent.removeView(mDialogContainer); + mContainerParent.addView( + mDialogContainer, mContainerParent.indexOfChild(mDefaultNextSiblingView)); + } + } + + /** + * Inflate the dialog container in the dialog container view stub. + */ + private void initDialogContainer() { + ViewStub dialogContainerStub = + mChromeActivity.findViewById(R.id.tab_modal_dialog_container_stub); + dialogContainerStub.setLayoutResource(R.layout.modal_dialog_container); + + mDialogContainer = (ViewGroup) dialogContainerStub.inflate(); + mContainerParent = (ViewGroup) mDialogContainer.getParent(); + // The default sibling view is the next view of the dialog container stub in main.xml and + // should not be removed from its parent. + mDefaultNextSiblingView = + mChromeActivity.findViewById(R.id.tab_modal_dialog_container_sibling_view); + assert mDefaultNextSiblingView != null; + + // Set the margin of the container and the dialog scrim so that the scrim doesn't overlap + // the toolbar. + Resources resources = mChromeActivity.getResources(); + int scrimVerticalMargin = + resources.getDimensionPixelSize(R.dimen.tab_modal_scrim_vertical_margin); + int containerVerticalMargin = + resources.getDimensionPixelSize(mChromeActivity.getControlContainerHeightResource()) + - scrimVerticalMargin; + + MarginLayoutParams params = (MarginLayoutParams) mDialogContainer.getLayoutParams(); + params.width = ViewGroup.MarginLayoutParams.MATCH_PARENT; + params.height = ViewGroup.MarginLayoutParams.MATCH_PARENT; + params.topMargin = !mHasBottomControls ? containerVerticalMargin : 0; + params.bottomMargin = mHasBottomControls ? containerVerticalMargin : 0; + mDialogContainer.setLayoutParams(params); + + View scrimView = mDialogContainer.findViewById(R.id.scrim); + params = (MarginLayoutParams) scrimView.getLayoutParams(); + params.width = MarginLayoutParams.MATCH_PARENT; + params.height = MarginLayoutParams.MATCH_PARENT; + params.topMargin = !mHasBottomControls ? scrimVerticalMargin : 0; + params.bottomMargin = mHasBottomControls ? scrimVerticalMargin : 0; + scrimView.setLayoutParams(params); + } + + /** + * Set whether the browser controls access should be restricted. If true, dialogs are expected + * to be showing and overflow menu would be disabled. + * @param restricted Whether the browser controls access should be restricted. + */ + private void setBrowserControlsAccess(boolean restricted) { + BottomSheet bottomSheet = mChromeActivity.getBottomSheet(); + View menuButton = mChromeActivity.getToolbarManager().getMenuButton(); + + if (restricted) { + mActiveTab = mChromeActivity.getActivityTab(); + assert mActiveTab + != null : "Tab modal dialogs should be shown on top of an active tab."; + + // Hide contextual search panel so that bottom toolbar will not be + // obscured and back press is not overridden. + ContextualSearchManager contextualSearchManager = + mChromeActivity.getContextualSearchManager(); + if (contextualSearchManager != null) { + contextualSearchManager.hideContextualSearch( + OverlayPanel.StateChangeReason.UNKNOWN); + } + + // Dismiss the action bar that obscures the dialogs but preserve the text selection. + ContentViewCore contentViewCore = mActiveTab.getContentViewCore(); + if (contentViewCore != null) { + contentViewCore.preserveSelectionOnNextLossOfFocus(); + contentViewCore.getContainerView().clearFocus(); + contentViewCore.updateTextSelectionUI(false); + mDidClearTextControls = true; + } + + // Force toolbar to show and disable overflow menu. + // TODO(huayinz): figure out a way to avoid |UpdateBrowserControlsState| being blocked + // by render process stalled due to javascript dialog. + mActiveTab.onTabModalDialogStateChanged(true); + + if (mHasBottomControls) { + bottomSheet.setSheetState(BottomSheet.SHEET_STATE_PEEK, true); + bottomSheet.addObserver(mBottomSheetObserver); + } else { + mChromeActivity.getToolbarManager().setUrlBarFocus(false); + } + menuButton.setEnabled(false); + updateContainerHierarchy(true); + } else { + // Show the action bar back if it was dismissed when the dialogs were showing. + ContentViewCore contentViewCore = mActiveTab.getContentViewCore(); + if (mDidClearTextControls) { + mDidClearTextControls = false; + if (contentViewCore != null) { + contentViewCore.updateTextSelectionUI(true); + } + } + + mActiveTab.onTabModalDialogStateChanged(false); + menuButton.setEnabled(true); + if (mHasBottomControls) bottomSheet.removeObserver(mBottomSheetObserver); + mActiveTab = null; + } + } + + @VisibleForTesting + View getDialogContainerForTest() { + return mDialogContainer; + } + + @VisibleForTesting + ViewGroup getContainerParentForTest() { + return mContainerParent; + } +}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/provider/ChromeBrowserProvider.java b/chrome/android/java/src/org/chromium/chrome/browser/provider/ChromeBrowserProvider.java index eedc7497a..09b9cf9 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/provider/ChromeBrowserProvider.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/provider/ChromeBrowserProvider.java
@@ -34,11 +34,11 @@ import org.chromium.base.annotations.CalledByNative; import org.chromium.base.library_loader.LibraryProcessType; import org.chromium.base.library_loader.ProcessInitException; +import org.chromium.chrome.browser.ChromeApplication; import org.chromium.chrome.browser.UrlConstants; import org.chromium.chrome.browser.database.SQLiteCursor; import org.chromium.chrome.browser.externalauth.ExternalAuthUtils; import org.chromium.chrome.browser.init.ChromeBrowserInitializer; -import org.chromium.content.app.ContentApplication; import org.chromium.content.browser.BrowserStartupController; import java.util.ArrayList; @@ -249,7 +249,7 @@ ThreadUtils.runOnUiThreadBlocking(new Runnable() { @Override public void run() { - ContentApplication.initCommandLine(getContext()); + ((ChromeApplication) getContext().getApplicationContext()).initCommandLine(); BrowserStartupController.get(LibraryProcessType.PROCESS_BROWSER) .addStartupCompletedObserver(
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/tab/Tab.java b/chrome/android/java/src/org/chromium/chrome/browser/tab/Tab.java index a299b0b..63b82c3 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/tab/Tab.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/tab/Tab.java
@@ -234,6 +234,7 @@ private boolean mIsClosing; private boolean mIsShowingErrorPage; + private boolean mIsShowingTabModalDialog; private Bitmap mFavicon; @@ -806,6 +807,13 @@ } /** + * @return Whether a tab modal dialog is showing. + */ + public boolean isShowingTabModalDialog() { + return mIsShowingTabModalDialog; + } + + /** * @return Whether the {@link Tab} is currently showing an error page. */ public boolean isShowingErrorPage() { @@ -3358,6 +3366,17 @@ hideMediaDownloadInProductHelp(); } + /** + * Handle browser controls when a tab modal dialog is shown. + * @param isShowing Whether a tab modal dialog is showing. + */ + public void onTabModalDialogStateChanged(boolean isShowing) { + mIsShowingTabModalDialog = isShowing; + if (mFullscreenManager == null) return; + mFullscreenManager.setPositionsForTabToNonFullscreen(); + updateBrowserControlsState(BrowserControlsState.SHOWN, false); + } + @CalledByNative private void showMediaDownloadInProductHelp(int x, int y, int width, int height) { // If we are not currently showing the widget, ask the tracker if we can show it.
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/tab/TabStateBrowserControlsVisibilityDelegate.java b/chrome/android/java/src/org/chromium/chrome/browser/tab/TabStateBrowserControlsVisibilityDelegate.java index d022cd3..556c616 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/tab/TabStateBrowserControlsVisibilityDelegate.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/tab/TabStateBrowserControlsVisibilityDelegate.java
@@ -153,6 +153,7 @@ enableHidingBrowserControls &= (mTab.getFullscreenManager() != null); enableHidingBrowserControls &= DeviceClassManager.enableFullscreen(); enableHidingBrowserControls &= !mIsFullscreenWaitingForLoad; + enableHidingBrowserControls &= !mTab.isShowingTabModalDialog(); return enableHidingBrowserControls; }
diff --git a/chrome/android/java_sources.gni b/chrome/android/java_sources.gni index 92038f3..f838d7b 100644 --- a/chrome/android/java_sources.gni +++ b/chrome/android/java_sources.gni
@@ -492,6 +492,7 @@ "java/src/org/chromium/chrome/browser/identity/UuidBasedUniqueIdentificationGenerator.java", "java/src/org/chromium/chrome/browser/incognito/IncognitoNotificationManager.java", "java/src/org/chromium/chrome/browser/incognito/IncognitoNotificationService.java", + "java/src/org/chromium/chrome/browser/incognito/IncognitoTabSnapshotController.java", "java/src/org/chromium/chrome/browser/infobar/AppBannerInfoBarAndroid.java", "java/src/org/chromium/chrome/browser/infobar/AppBannerInfoBarDelegateAndroid.java", "java/src/org/chromium/chrome/browser/infobar/AutofillCreditCardFillingInfoBar.java", @@ -559,6 +560,7 @@ "java/src/org/chromium/chrome/browser/invalidation/InvalidationController.java", "java/src/org/chromium/chrome/browser/invalidation/InvalidationServiceFactory.java", "java/src/org/chromium/chrome/browser/invalidation/UniqueIdInvalidationClientNameGenerator.java", + "java/src/org/chromium/chrome/browser/jsdialog/JavascriptModalDialogView.java", "java/src/org/chromium/chrome/browser/locale/DefaultSearchEngineDialogHelper.java", "java/src/org/chromium/chrome/browser/locale/DefaultSearchEnginePromoDialog.java", "java/src/org/chromium/chrome/browser/locale/LocaleManager.java", @@ -632,6 +634,11 @@ "java/src/org/chromium/chrome/browser/metrics/VariationsSession.java", "java/src/org/chromium/chrome/browser/metrics/WebApkUma.java", "java/src/org/chromium/chrome/browser/metrics/WebappUma.java", + "java/src/org/chromium/chrome/browser/modaldialog/AppModalPresenter.java", + "java/src/org/chromium/chrome/browser/modaldialog/ModalDialogManager.java", + "java/src/org/chromium/chrome/browser/modaldialog/ModalDialogView.java", + "java/src/org/chromium/chrome/browser/modaldialog/TabModalLifetimeHandler.java", + "java/src/org/chromium/chrome/browser/modaldialog/TabModalPresenter.java", "java/src/org/chromium/chrome/browser/mojo/ChromeInterfaceRegistrar.java", "java/src/org/chromium/chrome/browser/multiwindow/MultiInstanceChromeTabbedActivity.java", "java/src/org/chromium/chrome/browser/multiwindow/MultiWindowUtils.java", @@ -1601,6 +1608,7 @@ "javatests/src/org/chromium/chrome/browser/metrics/PageLoadMetricsTest.java", "javatests/src/org/chromium/chrome/browser/metrics/StartupLoadingMetricsTest.java", "javatests/src/org/chromium/chrome/browser/metrics/UkmIncognitoTest.java", + "javatests/src/org/chromium/chrome/browser/modaldialog/ModalDialogManagerTest.java", "javatests/src/org/chromium/chrome/browser/multiwindow/MultiWindowIntegrationTest.java", "javatests/src/org/chromium/chrome/browser/multiwindow/MultiWindowTestHelper.java", "javatests/src/org/chromium/chrome/browser/multiwindow/MultiWindowUtilsTest.java", @@ -1892,6 +1900,7 @@ "junit/src/org/chromium/chrome/browser/firstrun/ToSAckedReceiverTest.java", "junit/src/org/chromium/chrome/browser/fullscreen/BrowserStateBrowserControlsVisibilityDelegateTest.java", "junit/src/org/chromium/chrome/browser/gcore/GoogleApiClientHelperTest.java", + "junit/src/org/chromium/chrome/browser/incognito/IncognitoTabSnapshotControllerTest.java", "junit/src/org/chromium/chrome/browser/infobar/IPHInfoBarSupportTest.java", "junit/src/org/chromium/chrome/browser/init/AsyncInitTaskRunnerTest.java", "junit/src/org/chromium/chrome/browser/installedapp/InstalledAppProviderTest.java",
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/modaldialog/ModalDialogManagerTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/modaldialog/ModalDialogManagerTest.java new file mode 100644 index 0000000..b3745d4 --- /dev/null +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/modaldialog/ModalDialogManagerTest.java
@@ -0,0 +1,395 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package org.chromium.chrome.browser.modaldialog; + +import static android.support.test.espresso.Espresso.onView; +import static android.support.test.espresso.action.ViewActions.click; +import static android.support.test.espresso.assertion.ViewAssertions.doesNotExist; +import static android.support.test.espresso.assertion.ViewAssertions.matches; +import static android.support.test.espresso.matcher.ViewMatchers.hasDescendant; +import static android.support.test.espresso.matcher.ViewMatchers.isDisplayed; +import static android.support.test.espresso.matcher.ViewMatchers.isEnabled; +import static android.support.test.espresso.matcher.ViewMatchers.withId; +import static android.support.test.espresso.matcher.ViewMatchers.withText; + +import static org.hamcrest.Matchers.allOf; +import static org.hamcrest.Matchers.not; + +import android.support.test.espresso.Espresso; +import android.support.test.filters.SmallTest; +import android.view.View; +import android.view.ViewGroup; + +import org.junit.Assert; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; + +import org.chromium.base.ThreadUtils; +import org.chromium.base.test.util.CommandLineFlags; +import org.chromium.chrome.R; +import org.chromium.chrome.browser.ChromeSwitches; +import org.chromium.chrome.browser.ChromeTabbedActivity; +import org.chromium.chrome.test.ChromeJUnit4ClassRunner; +import org.chromium.chrome.test.ChromeTabbedActivityTestRule; + +/** + * Tests for displaying and functioning of modal dialogs on tabs. + */ +@RunWith(ChromeJUnit4ClassRunner.class) +@CommandLineFlags.Add({ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE}) +public class ModalDialogManagerTest { + @Rule + public ChromeTabbedActivityTestRule mActivityTestRule = new ChromeTabbedActivityTestRule(); + + private static final int MAX_DIALOGS = 3; + private ChromeTabbedActivity mActivity; + private ModalDialogManager mManager; + private ModalDialogView[] mModalDialogViews; + + @Before + public void setUp() throws Exception { + mActivityTestRule.startMainActivityOnBlankPage(); + mActivity = mActivityTestRule.getActivity(); + mManager = mActivity.getModalDialogManager(); + mModalDialogViews = new ModalDialogView[MAX_DIALOGS]; + for (int i = 0; i < MAX_DIALOGS; i++) mModalDialogViews[i] = createDialog(i); + } + + @Test + @SmallTest + public void testOneDialog() throws Exception { + // Initially there are no dialogs in the pending list. Browser controls are not restricted. + checkPendingSize(0); + checkBrowserControls(false); + checkCurrentPresenter(null); + + // Show a dialog. The pending list should be empty, and the dialog should be showing. + // Browser controls should be restricted. + showDialog(0, ModalDialogManager.TAB_MODAL); + checkPendingSize(0); + onView(withId(R.id.tab_modal_dialog_container)) + .check(matches(hasDescendant(withText("0")))); + checkBrowserControls(true); + checkCurrentPresenter(ModalDialogManager.TAB_MODAL); + + // Dismiss the dialog by clicking positive button. + onView(withText(R.string.ok)).perform(click()); + checkPendingSize(0); + onView(withId(R.id.tab_modal_dialog_container)) + .check(matches(not(hasDescendant(withText("0"))))); + checkBrowserControls(false); + checkCurrentPresenter(null); + } + + @Test + @SmallTest + public void testTwoDialogs() throws Exception { + // Initially there are no dialogs in the pending list. Browser controls are not restricted. + checkPendingSize(0); + checkBrowserControls(false); + checkCurrentPresenter(null); + + // Show the first dialog. + // The pending list should be empty, and the dialog should be showing. + // The tab modal container shouldn't be in the window hierarchy when an app modal dialog is + // showing. + showDialog(0, ModalDialogManager.APP_MODAL); + checkPendingSize(0); + onView(withText("0")).check(matches(isDisplayed())); + onView(withId(R.id.tab_modal_dialog_container)).check(doesNotExist()); + checkCurrentPresenter(ModalDialogManager.APP_MODAL); + + // Show the second dialog. It should be added to the pending list, and the first dialog + // should still be shown. + showDialog(1, ModalDialogManager.TAB_MODAL); + checkPendingSize(1); + onView(withText("0")).check(matches(isDisplayed())); + onView(withId(R.id.tab_modal_dialog_container)).check(doesNotExist()); + checkCurrentPresenter(ModalDialogManager.APP_MODAL); + + // Dismiss the first dialog by clicking cancel. The second dialog should be removed from + // pending list and shown immediately after. + onView(withText(R.string.cancel)).perform(click()); + checkPendingSize(0); + onView(withText("0")).check(doesNotExist()); + onView(withId(R.id.tab_modal_dialog_container)) + .check(matches( + allOf(not(hasDescendant(withText("0"))), hasDescendant(withText("1"))))); + checkBrowserControls(true); + checkCurrentPresenter(ModalDialogManager.TAB_MODAL); + + // Dismiss the second dialog by clicking ok. Browser controls should no longer be + // restricted. + onView(withText(R.string.ok)).perform(click()); + checkPendingSize(0); + onView(withText("0")).check(doesNotExist()); + onView(withId(R.id.tab_modal_dialog_container)) + .check(matches(allOf( + not(hasDescendant(withText("0"))), not(hasDescendant(withText("1")))))); + checkBrowserControls(false); + checkCurrentPresenter(null); + } + + @Test + @SmallTest + public void testThreeDialogs() throws Exception { + // Initially there are no dialogs in the pending list. Browser controls are not restricted. + checkPendingSize(0); + checkBrowserControls(false); + checkCurrentPresenter(null); + + // Show the first dialog. + // The pending list should be empty, and the dialog should be showing. + // Browser controls should be restricted. + showDialog(0, ModalDialogManager.TAB_MODAL); + checkPendingSize(0); + onView(withId(R.id.tab_modal_dialog_container)) + .check(matches(hasDescendant(withText("0")))); + checkBrowserControls(true); + checkCurrentPresenter(ModalDialogManager.TAB_MODAL); + + // Show the second dialog. It should be added to the pending list, and the first dialog + // should still be shown. + showDialog(1, ModalDialogManager.TAB_MODAL); + checkPendingSize(1); + onView(withId(R.id.tab_modal_dialog_container)) + .check(matches( + allOf(hasDescendant(withText("0")), not(hasDescendant(withText("1")))))); + checkBrowserControls(true); + checkCurrentPresenter(ModalDialogManager.TAB_MODAL); + + // Show the third dialog. It should be added to the pending list, and the first dialog + // should still be shown. + showDialog(2, ModalDialogManager.APP_MODAL); + checkPendingSize(2); + onView(withText("2")).check(doesNotExist()); + onView(withId(R.id.tab_modal_dialog_container)) + .check(matches(allOf(hasDescendant(withText("0")), + not(hasDescendant(withText("1"))), not(hasDescendant(withText("2")))))); + checkBrowserControls(true); + checkCurrentPresenter(ModalDialogManager.TAB_MODAL); + + // Stimulate dismissing the dialog by non-user action. The second dialog should be removed + // from pending list without showing. + dismissDialog(1); + checkPendingSize(1); + onView(withText("2")).check(doesNotExist()); + onView(withId(R.id.tab_modal_dialog_container)) + .check(matches(allOf(hasDescendant(withText("0")), + not(hasDescendant(withText("1"))), not(hasDescendant(withText("2")))))); + checkBrowserControls(true); + checkCurrentPresenter(ModalDialogManager.TAB_MODAL); + + // Dismiss the second dialog twice and verify nothing breaks. + dismissDialog(1); + checkPendingSize(1); + onView(withText("2")).check(doesNotExist()); + onView(withId(R.id.tab_modal_dialog_container)) + .check(matches(allOf(hasDescendant(withText("0")), + not(hasDescendant(withText("1"))), not(hasDescendant(withText("2")))))); + checkCurrentPresenter(ModalDialogManager.TAB_MODAL); + + // Dismiss the first dialog. The third dialog should be removed from pending list and + // shown immediately after. The tab modal container shouldn't be in the window hierarchy + // when an app modal dialog is showing. + dismissDialog(0); + checkPendingSize(0); + onView(withText("2")).check(matches(isDisplayed())); + onView(withId(R.id.tab_modal_dialog_container)).check(doesNotExist()); + checkCurrentPresenter(ModalDialogManager.APP_MODAL); + + // Dismiss the third dialog by clicking OK. Browser controls should no longer be restricted. + onView(withText(R.string.ok)).perform(click()); + checkPendingSize(0); + onView(withText("2")).check(doesNotExist()); + onView(withId(R.id.tab_modal_dialog_container)) + .check(matches(allOf(not(hasDescendant(withText("0"))), + not(hasDescendant(withText("1"))), not(hasDescendant(withText("2")))))); + checkBrowserControls(false); + checkCurrentPresenter(null); + } + + @Test + @SmallTest + public void testShow_UrlBarFocused() throws Exception { + // Show a dialog. The dialog should be shown on top of the toolbar. + showDialog(0, ModalDialogManager.TAB_MODAL); + + TabModalPresenter presenter = + (TabModalPresenter) mManager.getPresenterForTest(ModalDialogManager.TAB_MODAL); + final View dialogContainer = presenter.getDialogContainerForTest(); + final View controlContainer = mActivity.findViewById(R.id.control_container); + final ViewGroup containerParent = presenter.getContainerParentForTest(); + + ThreadUtils.runOnUiThreadBlocking(() -> { + Assert.assertTrue(containerParent.indexOfChild(dialogContainer) + > containerParent.indexOfChild(controlContainer)); + }); + + // When editing URL, it should be shown on top of the dialog. + onView(withId(R.id.url_bar)).perform(click()); + ThreadUtils.runOnUiThreadBlocking(() -> { + Assert.assertTrue(containerParent.indexOfChild(dialogContainer) + < containerParent.indexOfChild(controlContainer)); + }); + + // When URL bar is not focused, the dialog should be shown on top of the toolbar again. + Espresso.pressBack(); + ThreadUtils.runOnUiThreadBlocking(() -> { + Assert.assertTrue(containerParent.indexOfChild(dialogContainer) + > containerParent.indexOfChild(controlContainer)); + }); + + // Dismiss the dialog by clicking OK. + onView(withText(R.string.ok)).perform(click()); + } + + @Test + @SmallTest + public void testDismiss_ToggleOverview() throws Exception { + // Initially there are no dialogs in the pending list. Browser controls are not restricted. + checkPendingSize(0); + checkBrowserControls(false); + checkCurrentPresenter(null); + + // Add two dialogs available for showing. + showDialog(0, ModalDialogManager.TAB_MODAL); + showDialog(1, ModalDialogManager.TAB_MODAL); + checkPendingSize(1); + onView(withId(R.id.tab_modal_dialog_container)) + .check(matches( + allOf(hasDescendant(withText("0")), not(hasDescendant(withText("1")))))); + checkBrowserControls(true); + checkCurrentPresenter(ModalDialogManager.TAB_MODAL); + + // Dialogs should all be dismissed on entering tab switcher. + onView(withId(R.id.tab_switcher_button)).perform(click()); + checkPendingSize(0); + onView(withId(R.id.tab_modal_dialog_container)) + .check(matches(allOf( + not(hasDescendant(withText("0"))), not(hasDescendant(withText("1")))))); + checkBrowserControls(false); + checkCurrentPresenter(null); + } + + @Test + @SmallTest + public void testDismiss_BackPressed() throws Exception { + // Initially there are no dialogs in the pending list. Browser controls are not restricted. + checkPendingSize(0); + checkBrowserControls(false); + checkCurrentPresenter(null); + + // Add two dialogs available for showing. + showDialog(0, ModalDialogManager.TAB_MODAL); + showDialog(1, ModalDialogManager.TAB_MODAL); + showDialog(2, ModalDialogManager.APP_MODAL); + checkPendingSize(2); + onView(withText("2")).check(doesNotExist()); + onView(withId(R.id.tab_modal_dialog_container)) + .check(matches(allOf(hasDescendant(withText("0")), + not(hasDescendant(withText("1"))), not(hasDescendant(withText("2")))))); + checkBrowserControls(true); + checkCurrentPresenter(ModalDialogManager.TAB_MODAL); + + // Perform back press. The first dialog should be dismissed. + // The second dialog should be shown. + Espresso.pressBack(); + checkPendingSize(1); + onView(withText("2")).check(doesNotExist()); + onView(withId(R.id.tab_modal_dialog_container)) + .check(matches(allOf(not(hasDescendant(withText("0"))), + hasDescendant(withText("1")), not(hasDescendant(withText("2")))))); + checkBrowserControls(true); + checkCurrentPresenter(ModalDialogManager.TAB_MODAL); + + // Perform a second back press. The second dialog should be dismissed. + // The tab modal container shouldn't be in the window hierarchy when an app modal dialog is + // showing. + Espresso.pressBack(); + checkPendingSize(0); + onView(withText("2")).check(matches(isDisplayed())); + onView(withId(R.id.tab_modal_dialog_container)).check(doesNotExist()); + checkCurrentPresenter(ModalDialogManager.APP_MODAL); + + // Perform a third back press. The third dialog should be dismissed. + Espresso.pressBack(); + checkPendingSize(0); + onView(withText("2")).check(doesNotExist()); + onView(withId(R.id.tab_modal_dialog_container)) + .check(matches(allOf(not(hasDescendant(withText("0"))), + not(hasDescendant(withText("1"))), not(hasDescendant(withText("2")))))); + checkBrowserControls(false); + checkCurrentPresenter(null); + } + + private ModalDialogView createDialog(final int index) throws Exception { + return ThreadUtils.runOnUiThreadBlocking(() -> { + ModalDialogView.Controller controller = new ModalDialogView.Controller() { + @Override + public void onCancel() {} + + @Override + public void onClick(int buttonType) { + switch (buttonType) { + case ModalDialogView.BUTTON_POSITIVE: + case ModalDialogView.BUTTON_NEGATIVE: + dismissDialog(index); + break; + default: + Assert.fail("Unknown button type: " + buttonType); + } + } + }; + final ModalDialogView.Params p = new ModalDialogView.Params(); + p.title = Integer.toString(index); + p.positiveButtonTextId = R.string.ok; + p.negativeButtonTextId = R.string.cancel; + return new ModalDialogView(controller, p); + }); + } + + private void showDialog( + final int index, final @ModalDialogManager.ModalDialogType int dialogType) { + ThreadUtils.runOnUiThreadBlocking( + () -> { mManager.showDialog(mModalDialogViews[index], dialogType); }); + } + + private void dismissDialog(final int index) { + ThreadUtils.runOnUiThreadBlocking( + () -> { mManager.dismissDialog(mModalDialogViews[index]); }); + } + + private void checkPendingSize(final int expected) { + ThreadUtils.runOnUiThreadBlocking(() -> { + Assert.assertEquals(expected, mManager.getPendingDialogsForTest().size()); + }); + } + + private void checkCurrentPresenter(final Integer dialogType) { + ThreadUtils.runOnUiThreadBlocking(() -> { + if (dialogType == null) { + Assert.assertFalse(mManager.isShowing()); + Assert.assertNull(mManager.getCurrentPresenterForTest()); + } else { + Assert.assertTrue(mManager.isShowing()); + Assert.assertEquals(mManager.getPresenterForTest(dialogType), + mManager.getCurrentPresenterForTest()); + } + }); + } + + private void checkBrowserControls(boolean restricted) { + if (restricted) { + Assert.assertTrue("All tabs should be obscured", mActivity.isViewObscuringAllTabs()); + onView(withId(R.id.menu_button)).check(matches(not(isEnabled()))); + } else { + Assert.assertFalse("Tabs shouldn't be obscured", mActivity.isViewObscuringAllTabs()); + onView(withId(R.id.menu_button)).check(matches(isEnabled())); + } + } +}
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/vr_shell/README.md b/chrome/android/javatests/src/org/chromium/chrome/browser/vr_shell/README.md index ce2a6f9..bdab0f7 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/vr_shell/README.md +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/vr_shell/README.md
@@ -13,7 +13,8 @@ These are the files and directories that are relevant to VR instrumentation testing. Additional information on files in other directories can be found in -those directories' README.md files. +those directories' README.md files (if the files as a whole warrant special +documentation) and the JavaDoc comments in each file. ### Subdirectories @@ -167,7 +168,7 @@ has support for test parameterization. While parameterization has many potential uses, the current use in VR is to allow a test case to be automatically run in multiple different activity types. For specifics, see -`rules/vr_activity_restriction.md`. +`rules/README.md`. If a class has test parameterization enabled, you have three options when adding a new test:
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/vr_shell/rules/README.md b/chrome/android/javatests/src/org/chromium/chrome/browser/vr_shell/rules/README.md new file mode 100644 index 0000000..2182b4f --- /dev/null +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/vr_shell/rules/README.md
@@ -0,0 +1,49 @@ +# VR Instrumentation Rules + +## Introduction + +This directory contains all the Java files related to VR-specific JUnit4 rules. +For the most part, the rules are identical to the standard activity-specific +rules (e.g. `ChromeTabbedActivityTestRule` for `ChromeTabbedActivity`), but with +additional code to work with JUnit4 test parameterization to support running +a test case multiple times in different activities. + +Usage of this feature is already covered in `../README.md`, so this +documentation concerns implementation details. + +## How It Works + +When a test is set up to use test parameterization (determined by whether the +test class is annotated with `@RunWith(ParameterizedRunner.class)` or not), the +test runner automatically runs each test case in the class once with every +`ParameterSet` in the list of `ParameterSet`s that is annotated with +`@ClassParameter`, passing each `ParameterSet`'s contents to the class constructor +each time. + +In the case of VR tests, the `ParameterSet` list contains `Callable`s that +construct VR test rules for the three supported activity types +(`ChromeTabbedActivity`, `CustomTabActivity`, and `WebappActivity`). The +constructor for parameterized VR tests runs the provided `Callable`, effectively +running every test case once in each activity type. + +However, if the class were to assign the `Callable` return value to its member +variable annotated with `@Rule`, then every test case in the class would always +run in all three activity types, which isn't desirable since some test cases +test scenarios that are only valid in some activities (e.g. tests that involve +the VR browser are currently only supported in ChromeTabbedActivity). To avoid +this, the `Rule` annotated with `@Rule` is actually a `RuleChain` that wraps the +generated VR test rule in a `VrActivityRestrictionRule`. + +`VrActivityRestrictionRule` interacts with the `@VrActivityRestriction` +annotation and the VR test rule for the current test case run. If the activity +type of the current rule is contained in the list provided by +`@VrActivityRestriction` (or there is no restriction annotation and the activity +type is `ChromeTabbedActivity`), then the `VrActivityRestrictionRule` becomes a +no-op and the test case runs normally. Otherwise, `VrActivityRestrictionRule` +causes an assumption failure, which is interpreted by the test runner as a +signal to skip that particular test case/parameter combination. + +Thus, the end result is that the same test case can be run multiple times in +different activities without having to duplicate any code for use in different +activity types, while still retaining the ability to not run every test in every +activity type if necessary. \ No newline at end of file
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/vr_shell/vr_test_framework.md b/chrome/android/javatests/src/org/chromium/chrome/browser/vr_shell/vr_test_framework.md new file mode 100644 index 0000000..8372325 --- /dev/null +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/vr_shell/vr_test_framework.md
@@ -0,0 +1,104 @@ +# VR Test Framework + +## Introduction + +This is an overview of how the VR test framework functions. It is split into two +parts, with Java code located in this directory in `VrTestFramework.java` and +JavaScript code located in `//chrome/test/data/vr/e2e_test_files/`. +It is primarily used for testing WebVR, but can also be useful for testing the +VR Browser. + +A similar approach is used for testing VR on desktop, with the framework +re-implemented in C++ for use in browser tests and many of the same JavaScript +files used on both platforms. See the documentation in +`//chrome/browser/vr/test` for more information on this. + +## Structure + +Tests utilizing this framework are split into separate Java and JavaScript files +since WebVR interaction is done via JavaScript, but instrumentation tests are +Java-based. In general, the JavaScript code handles any interactions with the +WebVR API, and the Java code handles everything else (user gestures, controller +emulation, etc.). + +In general, the flow of a test is: +* In Java, load the HTML test file, which: + * Loads the WebVR boilerplate code and test code + * Sets up any test steps that need to be triggered by Java as separate + functions + * Creates an asynchronous test (denoted t here) +* Repeat: + * Run any necessary Java-side code, e.g. trigger a user action + * Trigger the next JavaScript test step and wait for it to finish +* Finally, call t.done() in JavaScript and endTest in Java + +### JavaScript + +The JavaScript test code mainly makes use of testharness.js, which is also used +for layout tests. This allows the use of asserts in JavaScript code, and any +assert failures will propagate up to Java. There are four main test-specific +functions that you will need to use: + +#### async\_test + +This creates an asynchronous test from testharness.js which you will use +throughout the JavaScript code. It serves two purposes: + +* By being an asynchronous test, it will prevent testharness.js from ending the + test run prematurely once the page is loaded. It will wait until all tests + are done before checking results. +* Enables you to use asserts in JavaScript. Asserts must be within a test to + do anything. + +#### finishJavaScriptStep + +This signals that the current portion of JavaScript code is done and that the +Java side can continue execution. + +#### t.step + +This defines a test step in an asynchronous test t. Any asserts must be within +a test step, so assertions will look along the lines of: +`t.step( () => { + assertTrue(someBool); +});` + +#### t.done + +This signals that the asynchronous test is done. Once all tests in a file are +completed (usually only one), testharness.js will check the results and +automatically call finishJavaScriptStep when done. + +### Java + +There are many Java-side functions that enable VR testing, but only the three +basic ones will be covered here. For specifics about less common functions, see +the JavaDoc comments in `VrTestFramework.java` and the utility classes in +`util/`. + +#### loadUrlAndAwaitInitialization + +This is similar to the standard loadUrl method in Chrome, but also waits until +all initialization steps are complete and the page is ready for testing. By +default, this only includes the page being loaded. Additionally, any files +that include the WebVR boilerplate script (generally any test for WebVR) will +wait until the promise returned by `navigator.getVRDisplays` has resolved or +rejected. Tests can add their own initialization steps by adding an entry to +the `initializationSteps` dictionary defined in +`//chrome/test/data/android/webvr_instrumentation/resources/webvr_e2e.js` with +the value set to `false`. Once the step is done, simply set the value to +`true`. + +#### executeStepAndWait + +This executes the given JavaScript and waits until finishJavaScriptStep is +called on the JavaScript side. + +#### endTest + +Performs any post-test checks after the JavaScript test code has finished +running. Since test failures are caught after each step, all this really does +is ensure that the the JavaScript code has actually finished running, throwing +an error if this is not the case. +Typically called at the very end of the test after everything else is +completed. \ No newline at end of file
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/incognito/IncognitoTabSnapshotControllerTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/incognito/IncognitoTabSnapshotControllerTest.java new file mode 100644 index 0000000..cf44ab6 --- /dev/null +++ b/chrome/android/junit/src/org/chromium/chrome/browser/incognito/IncognitoTabSnapshotControllerTest.java
@@ -0,0 +1,164 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package org.chromium.chrome.browser.incognito; + +import static org.mockito.Mockito.atLeastOnce; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.verify; + +import android.view.Window; +import android.view.WindowManager; +import android.view.WindowManager.LayoutParams; + +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.robolectric.annotation.Config; + +import org.chromium.chrome.browser.compositor.layouts.LayoutManagerChrome; +import org.chromium.chrome.browser.tabmodel.TabModel; +import org.chromium.chrome.browser.tabmodel.TabModelSelector; +import org.chromium.testing.local.LocalRobolectricTestRunner; + +/** + * Unit tests for IncognitoTabSnapshotController.java. + */ +@RunWith(LocalRobolectricTestRunner.class) +@Config(manifest = Config.NONE) +public class IncognitoTabSnapshotControllerTest { + private IncognitoTabSnapshotController mController; + private WindowManager.LayoutParams mParams; + + @Mock + Window mWindow; + + @Mock + TabModelSelector mSelector; + + @Mock + TabModel mTabModel; + + @Mock + LayoutManagerChrome mLayoutManager; + + @Before + public void before() { + MockitoAnnotations.initMocks(this); + + mParams = new LayoutParams(); + } + + @Test + public void testUpdateIncognitoStateIncognitoAndEarlyReturn() { + mParams.flags = WindowManager.LayoutParams.FLAG_SECURE; + doReturn(mParams).when(mWindow).getAttributes(); + + mController = new TestIncognitoTabSnapshotController(true); + mController.updateIncognitoState(); + verify(mWindow, never()).addFlags(WindowManager.LayoutParams.FLAG_SECURE); + verify(mWindow, never()).clearFlags(WindowManager.LayoutParams.FLAG_SECURE); + Assert.assertEquals( + "Flag should be secure", WindowManager.LayoutParams.FLAG_SECURE, mParams.flags); + } + + @Test + public void testUpdateIncognitoStateNotIncognitoAndEarlyReturn() { + mParams.flags = 0; + doReturn(mParams).when(mWindow).getAttributes(); + + mController = new TestIncognitoTabSnapshotController(false); + mController.updateIncognitoState(); + verify(mWindow, never()).addFlags(WindowManager.LayoutParams.FLAG_SECURE); + Assert.assertEquals("Flag should be zero", 0, mParams.flags); + } + + @Test + public void testUpdateIncognitoStateSwitchingToIncognito() { + mParams.flags = 0; + doReturn(mParams).when(mWindow).getAttributes(); + + mController = new TestIncognitoTabSnapshotController(true); + mController.updateIncognitoState(); + verify(mWindow, atLeastOnce()).addFlags(WindowManager.LayoutParams.FLAG_SECURE); + } + + @Test + public void testUpdateIncognitoStateSwitchingToNonIncognito() { + mParams.flags = WindowManager.LayoutParams.FLAG_SECURE; + doReturn(mParams).when(mWindow).getAttributes(); + + mController = new TestIncognitoTabSnapshotController(false); + mController.updateIncognitoState(); + verify(mWindow, atLeastOnce()).clearFlags(WindowManager.LayoutParams.FLAG_SECURE); + } + + @Test + public void testIsShowingIncognitoNotInOverviewMode() { + mController = new IncognitoTabSnapshotController(mWindow, mLayoutManager, mSelector); + mController.setInOverViewMode(false); + doReturn(mTabModel).when(mSelector).getCurrentModel(); + doReturn(true).when(mTabModel).isIncognito(); + Assert.assertTrue("isShowingIncognito should be true", mController.isShowingIncognito()); + + verify(mSelector, never()).getModel(true); + } + + @Test + public void testIsShowingIncognitoInOverviewMode() { + mController = new IncognitoTabSnapshotController(mWindow, mLayoutManager, mSelector); + mController.setInOverViewMode(false); + doReturn(mTabModel).when(mSelector).getCurrentModel(); + doReturn(true).when(mTabModel).isIncognito(); + Assert.assertTrue("isShowingIncognito should be true", mController.isShowingIncognito()); + + verify(mSelector, never()).getModel(true); + } + + @Test + public void testInOverviewModeWithIncognitoTab() { + mController = new IncognitoTabSnapshotController(mWindow, mLayoutManager, mSelector); + mController.setInOverViewMode(true); + + doReturn(mTabModel).when(mSelector).getCurrentModel(); + doReturn(false).when(mTabModel).isIncognito(); + doReturn(mTabModel).when(mSelector).getModel(true); + doReturn(1).when(mTabModel).getCount(); + Assert.assertTrue("isShowingIncognito should be true", mController.isShowingIncognito()); + + verify(mTabModel, atLeastOnce()).getCount(); + } + + @Test + public void testInOverviewModeWithNoIncognitoTab() { + mController = new IncognitoTabSnapshotController(mWindow, mLayoutManager, mSelector); + mController.setInOverViewMode(true); + + doReturn(mTabModel).when(mSelector).getCurrentModel(); + doReturn(false).when(mTabModel).isIncognito(); + doReturn(mTabModel).when(mSelector).getModel(true); + doReturn(0).when(mTabModel).getCount(); + Assert.assertFalse("isShowingIncognito should be false", mController.isShowingIncognito()); + + verify(mTabModel, atLeastOnce()).getCount(); + } + + class TestIncognitoTabSnapshotController extends IncognitoTabSnapshotController { + private boolean mIsShowingIncognito; + + public TestIncognitoTabSnapshotController(boolean isShowingIncognito) { + super(mWindow, mLayoutManager, mSelector); + mIsShowingIncognito = isShowingIncognito; + } + + @Override + boolean isShowingIncognito() { + return mIsShowingIncognito; + } + } +} \ No newline at end of file
diff --git a/chrome/android/profiles/cipd.yaml b/chrome/android/profiles/cipd.yaml new file mode 100644 index 0000000..1e68d45 --- /dev/null +++ b/chrome/android/profiles/cipd.yaml
@@ -0,0 +1,13 @@ +# Copyright 2018 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +# To create a CIPD package, run the following command. +# cipd create --pkg-def cipd.yaml -tag version:version-of-afdo-profile +package: chromium/afdo/profiles/android +description: AFDO profiles collected for Chromium on Android + +# FIXME(gbiv): When we can specify dependencies on the profile in the build +# system, settle on a profile name that doesn't include the version. +data: + - file: chrome-profile-3309-text.prof
diff --git a/chrome/android/third_party/widget_bottomsheet_base/java/src/org/chromium/chrome/browser/widget/bottomsheet/base/BottomNavigationMenuView.java b/chrome/android/third_party/widget_bottomsheet_base/java/src/org/chromium/chrome/browser/widget/bottomsheet/base/BottomNavigationMenuView.java index d746e344..2e1c9ea 100644 --- a/chrome/android/third_party/widget_bottomsheet_base/java/src/org/chromium/chrome/browser/widget/bottomsheet/base/BottomNavigationMenuView.java +++ b/chrome/android/third_party/widget_bottomsheet_base/java/src/org/chromium/chrome/browser/widget/bottomsheet/base/BottomNavigationMenuView.java
@@ -225,7 +225,7 @@ * @param layoutHeight Height of the navigation menu's container. */ public void updateMenuItemSpacingForMinWidth(int layoutWidth, int layoutHeight) { - if (mButtons.length == 0) return; + if (mButtons == null || mButtons.length == 0) return; int menuWidth = Math.min(layoutWidth, layoutHeight); if (menuWidth != mMenuWidth) {
diff --git a/chrome/app/chromium_strings.grd b/chrome/app/chromium_strings.grd index c62ffd9..07aa5cca 100644 --- a/chrome/app/chromium_strings.grd +++ b/chrome/app/chromium_strings.grd
@@ -762,9 +762,6 @@ <message name="IDS_OPTIONS_PASSWORDS_MAC_WARNING" desc="The warning for OS X that passwords are shared across profiles in the keychain."> On Mac, passwords may be saved to your Keychain and accessed or synced by other Chromium users sharing this OS X account. </message> - <message name="IDS_AUTOFILL_ADDRESS_BOOK_PROMPT_DESCRIPTION" desc="Text to show in dialog requesting permission to access the user's Address Book contents."> - Details from your contacts can help you fill out forms more quickly in Chromium. - </message> </if> <message name="IDS_AUTOFILL_DIALOG_SAVE_LOCALLY_CHECKBOX" desc="Checkbox that controls whether info the user types into the autofill dialog is saved by chrome.">
diff --git a/chrome/app/google_chrome_strings.grd b/chrome/app/google_chrome_strings.grd index 84f1845..b4c8ee2 100644 --- a/chrome/app/google_chrome_strings.grd +++ b/chrome/app/google_chrome_strings.grd
@@ -770,9 +770,6 @@ <message name="IDS_OPTIONS_PASSWORDS_MAC_WARNING" desc="The warning for OS X that passwords are shared across profiles in the keychain."> On Mac, passwords may be saved to your Keychain and accessed or synced by other Chrome users sharing this OS X account. </message> - <message name="IDS_AUTOFILL_ADDRESS_BOOK_PROMPT_DESCRIPTION" desc="Text to show in dialog requesting permission to access the user's Address Book contents."> - Details from your contacts can help you fill out forms more quickly in Chrome. - </message> </if> <message name="IDS_AUTOFILL_DIALOG_SAVE_LOCALLY_CHECKBOX" desc="Checkbox that controls whether info the user types into the autofill dialog is saved by chrome.">
diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn index f10dbacff..2b7c879 100644 --- a/chrome/browser/BUILD.gn +++ b/chrome/browser/BUILD.gn
@@ -2952,7 +2952,6 @@ ] libs += [ "Accelerate.framework", - "AddressBook.framework", "AudioUnit.framework", "DiskArbitration.framework", "IOKit.framework",
diff --git a/chrome/browser/chrome_content_browser_client.cc b/chrome/browser/chrome_content_browser_client.cc index 490133c3..64ef941 100644 --- a/chrome/browser/chrome_content_browser_client.cc +++ b/chrome/browser/chrome_content_browser_client.cc
@@ -458,7 +458,6 @@ using extensions::APIPermission; using extensions::ChromeContentBrowserClientExtensionsPart; using extensions::Extension; -using extensions::InfoMap; using extensions::Manifest; #endif
diff --git a/chrome/browser/chromeos/arc/arc_util_unittest.cc b/chrome/browser/chromeos/arc/arc_util_unittest.cc index 4f087d0..3167337 100644 --- a/chrome/browser/chromeos/arc/arc_util_unittest.cc +++ b/chrome/browser/chromeos/arc/arc_util_unittest.cc
@@ -18,6 +18,7 @@ #include "chrome/browser/chromeos/login/users/wallpaper/wallpaper_manager.h" #include "chrome/browser/chromeos/policy/browser_policy_connector_chromeos.h" #include "chrome/browser/chromeos/profiles/profile_helper.h" +#include "chrome/browser/chromeos/settings/cros_settings.h" #include "chrome/browser/chromeos/settings/device_settings_service.h" #include "chrome/browser/chromeos/settings/install_attributes.h" #include "chrome/browser/policy/profile_policy_connector.h" @@ -155,6 +156,8 @@ std::make_unique<FakeUserManagerWithLocalState>()); // Used by FakeChromeUserManager. chromeos::WallpaperManager::Initialize(); + chromeos::DeviceSettingsService::Initialize(); + chromeos::CrosSettings::Initialize(); wallpaper_controller_client_ = std::make_unique<WallpaperControllerClient>(); wallpaper_controller_client_->InitForTesting(
diff --git a/chrome/browser/chromeos/extensions/wallpaper_private_api_unittest.cc b/chrome/browser/chromeos/extensions/wallpaper_private_api_unittest.cc index 91db9dc..b1811b0 100644 --- a/chrome/browser/chromeos/extensions/wallpaper_private_api_unittest.cc +++ b/chrome/browser/chromeos/extensions/wallpaper_private_api_unittest.cc
@@ -13,6 +13,8 @@ #include "base/memory/ptr_util.h" #include "chrome/browser/chromeos/login/users/fake_chrome_user_manager.h" #include "chrome/browser/chromeos/login/users/wallpaper/wallpaper_manager.h" +#include "chrome/browser/chromeos/settings/cros_settings.h" +#include "chrome/browser/chromeos/settings/device_settings_service.h" #include "chrome/browser/ui/ash/multi_user/multi_user_window_manager.h" #include "chrome/browser/ui/ash/multi_user/multi_user_window_manager_chromeos.h" #include "chrome/browser/ui/ash/test_wallpaper_controller.h" @@ -194,6 +196,8 @@ void WallpaperPrivateApiMultiUserUnittest::SetUp() { AshTestBase::SetUp(); + DeviceSettingsService::Initialize(); + CrosSettings::Initialize(); WallpaperManager::Initialize(); wallpaper_controller_client_ = std::make_unique<WallpaperControllerClient>(); wallpaper_controller_client_->InitForTesting( @@ -207,6 +211,8 @@ AshTestBase::TearDown(); WallpaperManager::Shutdown(); wallpaper_controller_client_.reset(); + CrosSettings::Shutdown(); + DeviceSettingsService::Shutdown(); } void WallpaperPrivateApiMultiUserUnittest::SetUpMultiUserWindowManager(
diff --git a/chrome/browser/chromeos/login/existing_user_controller.cc b/chrome/browser/chromeos/login/existing_user_controller.cc index 26b8c1d..905dd65 100644 --- a/chrome/browser/chromeos/login/existing_user_controller.cc +++ b/chrome/browser/chromeos/login/existing_user_controller.cc
@@ -435,6 +435,7 @@ // just after the UI is closed but before the new credentials were stored // in the profile. Therefore we have to give it some time to make sure it // has been updated before we copy it. + // TODO(pmarko): Find a better way to do this, see https://crbug.com/796512. VLOG(1) << "Authentication was entered manually, possibly for proxyauth."; scoped_refptr<net::URLRequestContextGetter> browser_process_context_getter = g_browser_process->system_request_context();
diff --git a/chrome/browser/chromeos/login/signin_partition_manager.cc b/chrome/browser/chromeos/login/signin_partition_manager.cc index 17652f4..a1e0f85 100644 --- a/chrome/browser/chromeos/login/signin_partition_manager.cc +++ b/chrome/browser/chromeos/login/signin_partition_manager.cc
@@ -6,17 +6,26 @@ #include "base/guid.h" #include "base/strings/stringprintf.h" +#include "chrome/browser/browser_process.h" #include "chrome/browser/profiles/incognito_helpers.h" #include "chromeos/chromeos_switches.h" #include "components/keyed_service/content/browser_context_dependency_manager.h" #include "content/public/browser/browser_context.h" +#include "content/public/browser/browser_thread.h" #include "content/public/browser/storage_partition.h" #include "content/public/browser/web_contents.h" #include "content/public/common/url_constants.h" #include "extensions/browser/guest_view/web_view/web_view_guest.h" #include "net/base/escape.h" +#include "net/http/http_auth_cache.h" +#include "net/http/http_network_session.h" +#include "net/http/http_transaction_factory.h" +#include "net/url_request/url_request_context.h" +#include "net/url_request/url_request_context_getter.h" #include "url/gurl.h" +using content::BrowserThread; + namespace chromeos { namespace login { @@ -46,18 +55,50 @@ base::Time::Max(), std::move(partition_data_cleared)); } +net::URLRequestContextGetter* GetSystemURLRequestContextGetter() { + return g_browser_process->system_request_context(); +} + +// Transfers HttpAuthCache content from |main_url_request_context_getter| into +// |signin_url_request_context_getter|. +void PrepareSigninURLRequestContextOnIOThread( + net::URLRequestContextGetter* main_url_request_context_getter, + net::URLRequestContextGetter* signin_url_request_context_getter) { + // Transfer proxy auth data from the main URLRequestContext. + net::HttpAuthCache* main_http_auth_cache = + main_url_request_context_getter->GetURLRequestContext() + ->http_transaction_factory() + ->GetSession() + ->http_auth_cache(); + net::HttpAuthCache* signin_http_auth_cache = + signin_url_request_context_getter->GetURLRequestContext() + ->http_transaction_factory() + ->GetSession() + ->http_auth_cache(); + signin_http_auth_cache->UpdateAllFrom(*main_http_auth_cache); +} + +void InvokeStartSigninSessionDoneCallback( + SigninPartitionManager::StartSigninSessionDoneCallback callback, + const std::string& partition_name) { + std::move(callback).Run(partition_name); +} + } // namespace SigninPartitionManager::SigninPartitionManager( content::BrowserContext* browser_context) : browser_context_(browser_context), clear_storage_partition_task_( - base::BindRepeating(&ClearStoragePartition)) {} + base::BindRepeating(&ClearStoragePartition)), + get_system_url_request_context_getter_task_( + base::BindRepeating(&GetSystemURLRequestContextGetter)) {} SigninPartitionManager::~SigninPartitionManager() {} void SigninPartitionManager::StartSigninSession( - const content::WebContents* embedder_web_contents) { + const content::WebContents* embedder_web_contents, + StartSigninSessionDoneCallback signin_session_started) { // If we already were in a sign-in session, close it first. // This clears stale data from the last-used StorageParittion. CloseCurrentSigninSession(base::BindOnce(&base::DoNothing)); @@ -74,6 +115,19 @@ current_storage_partition_ = content::BrowserContext::GetStoragePartitionForSite(browser_context_, guest_site, true); + + base::OnceClosure invoke_callback = base::BindOnce( + &InvokeStartSigninSessionDoneCallback, std::move(signin_session_started), + current_storage_partition_name_); + + BrowserThread::PostTaskAndReply( + BrowserThread::IO, FROM_HERE, + base::BindOnce( + &PrepareSigninURLRequestContextOnIOThread, + base::RetainedRef(get_system_url_request_context_getter_task_.Run()), + base::RetainedRef( + current_storage_partition_->GetURLRequestContext())), + std::move(invoke_callback)); } void SigninPartitionManager::CloseCurrentSigninSession( @@ -97,6 +151,13 @@ clear_storage_partition_task_ = clear_storage_partition_task; } +void SigninPartitionManager::SetGetSystemURLRequestContextGetterTaskForTesting( + GetSystemURLRequestContextGetterTask + get_system_url_request_context_getter_task) { + get_system_url_request_context_getter_task_ = + get_system_url_request_context_getter_task; +} + const std::string& SigninPartitionManager::GetCurrentStoragePartitionName() const { DCHECK(IsInSigninSession());
diff --git a/chrome/browser/chromeos/login/signin_partition_manager.h b/chrome/browser/chromeos/login/signin_partition_manager.h index 66e790e..1a5478e 100644 --- a/chrome/browser/chromeos/login/signin_partition_manager.h +++ b/chrome/browser/chromeos/login/signin_partition_manager.h
@@ -9,6 +9,7 @@ #include "base/callback.h" #include "base/macros.h" +#include "base/memory/ref_counted.h" #include "base/memory/singleton.h" #include "components/keyed_service/content/browser_context_keyed_service_factory.h" #include "components/keyed_service/core/keyed_service.h" @@ -19,6 +20,10 @@ class WebContents; } // namespace content +namespace net { +class URLRequestContextGetter; +} + namespace chromeos { namespace login { @@ -30,6 +35,12 @@ base::RepeatingCallback<void(content::StoragePartition* storage_partition, base::OnceClosure data_cleared)>; + using GetSystemURLRequestContextGetterTask = + base::RepeatingCallback<net::URLRequestContextGetter*()>; + + using StartSigninSessionDoneCallback = + base::OnceCallback<void(const std::string& partition_name)>; + explicit SigninPartitionManager(content::BrowserContext* browser_context); ~SigninPartitionManager() override; @@ -38,7 +49,11 @@ // closed (and cleared). // |embedder_web_contents| is the WebContents instance embedding the webview // which will display the sign-in pages. - void StartSigninSession(const content::WebContents* embedder_web_contents); + // |signin_session_started| will be invoked with the partition name of the + // started signin session on completition. + void StartSigninSession( + const content::WebContents* embedder_web_contents, + StartSigninSessionDoneCallback signin_session_started); // Closes the current StoragePartition. All cached data in the // StoragePartition is cleared. |partition_data_cleared| will be called when @@ -66,6 +81,9 @@ void SetClearStoragePartitionTaskForTesting( ClearStoragePartitionTask clear_storage_partition_task); + void SetGetSystemURLRequestContextGetterTaskForTesting( + GetSystemURLRequestContextGetterTask + get_system_url_request_context_getter_task); class Factory : public BrowserContextKeyedServiceFactory { public: @@ -93,6 +111,8 @@ content::BrowserContext* const browser_context_; ClearStoragePartitionTask clear_storage_partition_task_; + GetSystemURLRequestContextGetterTask + get_system_url_request_context_getter_task_; // GuestView StoragePartitions use the host of the embedder site's URL as the // domain of their StoragePartition.
diff --git a/chrome/browser/chromeos/login/signin_partition_manager_unittest.cc b/chrome/browser/chromeos/login/signin_partition_manager_unittest.cc index b5b6721..be492f2 100644 --- a/chrome/browser/chromeos/login/signin_partition_manager_unittest.cc +++ b/chrome/browser/chromeos/login/signin_partition_manager_unittest.cc
@@ -12,13 +12,16 @@ #include "chrome/test/base/chrome_render_view_host_test_harness.h" #include "chrome/test/base/testing_profile.h" #include "content/public/browser/browser_context.h" +#include "content/public/browser/browser_thread.h" #include "content/public/browser/site_instance.h" #include "content/public/browser/storage_partition.h" #include "content/public/browser/web_contents.h" +#include "content/public/test/test_browser_thread_bundle.h" #include "content/public/test/web_contents_tester.h" #include "net/cookies/cookie_store.h" #include "net/url_request/url_request_context.h" #include "net/url_request/url_request_context_getter.h" +#include "net/url_request/url_request_test_util.h" #include "testing/gtest/include/gtest/gtest.h" #include "url/gurl.h" @@ -27,6 +30,39 @@ namespace { constexpr char kEmbedderUrl[] = "http://www.whatever.com/"; + +void StorePartitionNameAndQuitLoop(base::RunLoop* loop, + std::string* out_partition_name, + const std::string& partition_name) { + *out_partition_name = partition_name; + loop->Quit(); +} + +void AddEntryToHttpAuthCache( + net::URLRequestContextGetter* url_request_context_getter) { + net::HttpAuthCache* http_auth_cache = + url_request_context_getter->GetURLRequestContext() + ->http_transaction_factory() + ->GetSession() + ->http_auth_cache(); + http_auth_cache->Add(GURL("http://whatever.com/"), "", + net::HttpAuth::AUTH_SCHEME_BASIC, "", + net::AuthCredentials(), ""); +} + +void IsEntryInHttpAuthCache( + net::URLRequestContextGetter* url_request_context_getter, + bool* out_entry_found) { + net::HttpAuthCache* http_auth_cache = + url_request_context_getter->GetURLRequestContext() + ->http_transaction_factory() + ->GetSession() + ->http_auth_cache(); + *out_entry_found = + http_auth_cache->Lookup(GURL("http://whatever.com/"), "", + net::HttpAuth::AUTH_SCHEME_BASIC) != nullptr; +} + } // namespace class SigninPartitionManagerTest : public ChromeRenderViewHostTestHarness { @@ -37,6 +73,10 @@ void SetUp() override { ChromeRenderViewHostTestHarness::SetUp(); + system_request_context_getter_ = new net::TestURLRequestContextGetter( + content::BrowserThread::GetTaskRunnerForThread( + content::BrowserThread::IO)); + signin_browser_context_ = base::MakeUnique<TestingProfile>(); signin_ui_web_contents_ = base::WrapUnique<content::WebContents>( @@ -51,6 +91,10 @@ GetSigninPartitionManager()->SetClearStoragePartitionTaskForTesting( base::Bind(&SigninPartitionManagerTest::ClearStoragePartitionTask, base::Unretained(this))); + GetSigninPartitionManager() + ->SetGetSystemURLRequestContextGetterTaskForTesting(base::BindRepeating( + &SigninPartitionManagerTest::GetSystemURLRequestContextGetter, + base::Unretained(this))); } void TearDown() override { @@ -89,12 +133,29 @@ pending_clear_tasks_.clear(); } + std::string RunStartSigninSesssion(content::WebContents* webcontents) { + std::string partition_name; + base::RunLoop loop; + GetSigninPartitionManager()->StartSigninSession( + webcontents, + base::BindOnce(&StorePartitionNameAndQuitLoop, &loop, &partition_name)); + loop.Run(); + return partition_name; + } + + net::URLRequestContextGetter* GetSystemURLRequestContextGetter() { + return system_request_context_getter_.get(); + } + private: void ClearStoragePartitionTask(content::StoragePartition* partition, base::OnceClosure clear_done_closure) { pending_clear_tasks_.push_back({partition, std::move(clear_done_closure)}); } + scoped_refptr<net::TestURLRequestContextGetter> + system_request_context_getter_; + std::unique_ptr<TestingProfile> signin_browser_context_; // Web contents of the sign-in UI, embedder of the signin-frame webview. @@ -108,20 +169,22 @@ TEST_F(SigninPartitionManagerTest, TestSubsequentAttempts) { // First sign-in attempt - GetSigninPartitionManager()->StartSigninSession(signin_ui_web_contents()); std::string signin_partition_name_1 = - GetSigninPartitionManager()->GetCurrentStoragePartitionName(); + RunStartSigninSesssion(signin_ui_web_contents()); auto* signin_partition_1 = GetSigninPartitionManager()->GetCurrentStoragePartition(); EXPECT_FALSE(signin_partition_name_1.empty()); + EXPECT_EQ(signin_partition_name_1, + GetSigninPartitionManager()->GetCurrentStoragePartitionName()); // Second sign-in attempt - GetSigninPartitionManager()->StartSigninSession(signin_ui_web_contents()); std::string signin_partition_name_2 = - GetSigninPartitionManager()->GetCurrentStoragePartitionName(); + RunStartSigninSesssion(signin_ui_web_contents()); auto* signin_partition_2 = GetSigninPartitionManager()->GetCurrentStoragePartition(); EXPECT_FALSE(signin_partition_name_2.empty()); + EXPECT_EQ(signin_partition_name_2, + GetSigninPartitionManager()->GetCurrentStoragePartitionName()); // Make sure that the StoragePartition has not been re-used. EXPECT_NE(signin_partition_name_1, signin_partition_name_2); @@ -148,5 +211,32 @@ EXPECT_TRUE(closure_called); } +TEST_F(SigninPartitionManagerTest, HttpAuthCacheTransferred) { + base::RunLoop loop_prepare; + content::BrowserThread::PostTaskAndReply( + content::BrowserThread::IO, FROM_HERE, + base::BindOnce(AddEntryToHttpAuthCache, + base::RetainedRef(GetSystemURLRequestContextGetter())), + loop_prepare.QuitClosure()); + loop_prepare.Run(); + + RunStartSigninSesssion(signin_ui_web_contents()); + net::URLRequestContextGetter* signin_url_request_context_getter = + GetSigninPartitionManager() + ->GetCurrentStoragePartition() + ->GetURLRequestContext(); + + bool entry_found = false; + base::RunLoop loop_check; + content::BrowserThread::PostTaskAndReply( + content::BrowserThread::IO, FROM_HERE, + base::BindOnce(IsEntryInHttpAuthCache, + base::RetainedRef(signin_url_request_context_getter), + &entry_found), + loop_check.QuitClosure()); + loop_check.Run(); + EXPECT_TRUE(entry_found); +} + } // namespace login } // namespace chromeos
diff --git a/chrome/browser/chromeos/login/users/wallpaper/wallpaper_manager.cc b/chrome/browser/chromeos/login/users/wallpaper/wallpaper_manager.cc index 8e9c9a60..6cbf63ad 100644 --- a/chrome/browser/chromeos/login/users/wallpaper/wallpaper_manager.cc +++ b/chrome/browser/chromeos/login/users/wallpaper/wallpaper_manager.cc
@@ -17,14 +17,11 @@ #include "base/bind.h" #include "base/bind_helpers.h" #include "base/command_line.h" -#include "base/files/file_util.h" #include "base/lazy_instance.h" #include "base/logging.h" #include "base/memory/ptr_util.h" #include "base/metrics/histogram_macros.h" #include "base/sequenced_task_runner.h" -#include "base/strings/string_number_conversions.h" -#include "base/strings/string_util.h" #include "base/strings/stringprintf.h" #include "base/sys_info.h" #include "base/task_scheduler/post_task.h" @@ -61,14 +58,12 @@ #include "content/public/browser/notification_service.h" #include "content/public/common/content_switches.h" #include "content/public/common/service_manager_connection.h" -#include "crypto/sha2.h" #include "services/service_manager/public/cpp/connector.h" #include "third_party/skia/include/core/SkColor.h" #include "ui/gfx/codec/jpeg_codec.h" #include "ui/gfx/geometry/safe_integer_conversions.h" #include "ui/gfx/image/image_skia_operations.h" #include "ui/gfx/skia_util.h" -#include "url/gurl.h" using content::BrowserThread; using wallpaper::WallpaperInfo; @@ -165,21 +160,6 @@ } } -// A helper function to check the existing/downloaded device wallpaper file's -// hash value matches with the hash value provided in the policy settings. -bool CheckDeviceWallpaperMatchHash(const base::FilePath& device_wallpaper_file, - const std::string& hash) { - std::string image_data; - if (base::ReadFileToString(device_wallpaper_file, &image_data)) { - std::string sha_hash = crypto::SHA256HashString(image_data); - if (base::ToLowerASCII(base::HexEncode( - sha_hash.c_str(), sha_hash.size())) == base::ToLowerASCII(hash)) { - return true; - } - } - return false; -} - } // namespace void AssertCalledOnWallpaperSequence(base::SequencedTaskRunner* task_runner) { @@ -281,7 +261,6 @@ WallpaperManager::~WallpaperManager() { show_user_name_on_signin_subscription_.reset(); - device_wallpaper_image_subscription_.reset(); weak_factory_.InvalidateWeakPtrs(); } @@ -358,9 +337,14 @@ // For a enterprise managed user, set the device wallpaper if we're at the // login screen. - if (!user_manager::UserManager::Get()->IsUserLoggedIn() && - SetDeviceWallpaperIfApplicable(account_id)) + // TODO(xdai): Replace these two functions ShouldSetDeviceWallpaper() and + // OnDeviceWallpaperChanged() with functions in WallpaperController. + std::string url; + std::string hash; + if (ShouldSetDeviceWallpaper(account_id, &url, &hash)) { + WallpaperControllerClient::Get()->OnDeviceWallpaperChanged(); return; + } // TODO(crbug.com/776464): Move the above to // |WallpaperController::ShowUserWallpaper| after @@ -369,8 +353,6 @@ } void WallpaperManager::ShowSigninWallpaper() { - if (SetDeviceWallpaperIfApplicable(user_manager::SignInAccountId())) - return; WallpaperControllerClient::Get()->ShowSigninWallpaper(); } @@ -470,11 +452,6 @@ kAccountsPrefShowUserNamesOnSignIn, base::Bind(&WallpaperManager::InitializeRegisteredDeviceWallpaper, weak_factory_.GetWeakPtr())); - device_wallpaper_image_subscription_ = - CrosSettings::Get()->AddSettingsObserver( - kDeviceWallpaperImage, - base::Bind(&WallpaperManager::OnDeviceWallpaperPolicyChanged, - weak_factory_.GetWeakPtr())); } void WallpaperManager::EnsureLoggedInUserWallpaperLoaded() { @@ -643,24 +620,6 @@ account_id, is_persistent); } -bool WallpaperManager::SetDeviceWallpaperIfApplicable( - const AccountId& account_id) { - std::string url; - std::string hash; - if (ShouldSetDeviceWallpaper(account_id, &url, &hash)) { - // Check if the device wallpaper exists and matches the hash. If so, use it - // directly. Otherwise download it first. - base::PostTaskWithTraitsAndReplyWithResult( - FROM_HERE, {base::MayBlock()}, - base::Bind(&base::PathExists, - ash::WallpaperController::GetDeviceWallpaperFilePath()), - base::Bind(&WallpaperManager::OnDeviceWallpaperExists, - weak_factory_.GetWeakPtr(), account_id, url, hash)); - return true; - } - return false; -} - bool WallpaperManager::GetWallpaperFromCache(const AccountId& account_id, gfx::ImageSkia* image) { DCHECK(thread_checker_.CalledOnValidThread()); @@ -941,119 +900,6 @@ ->IsUserLoggedIn() /* update wallpaper */); } -void WallpaperManager::OnDeviceWallpaperPolicyChanged() { - SetDeviceWallpaperIfApplicable( - user_manager::UserManager::Get()->IsUserLoggedIn() - ? user_manager::UserManager::Get()->GetActiveUser()->GetAccountId() - : user_manager::SignInAccountId()); -} - -void WallpaperManager::OnDeviceWallpaperExists(const AccountId& account_id, - const std::string& url, - const std::string& hash, - bool exist) { - if (exist) { - base::PostTaskWithTraitsAndReplyWithResult( - FROM_HERE, {base::MayBlock()}, - base::Bind(&CheckDeviceWallpaperMatchHash, - ash::WallpaperController::GetDeviceWallpaperFilePath(), - hash), - base::Bind(&WallpaperManager::OnCheckDeviceWallpaperMatchHash, - weak_factory_.GetWeakPtr(), account_id, url, hash)); - } else { - GURL device_wallpaper_url(url); - device_wallpaper_downloader_.reset(new CustomizationWallpaperDownloader( - g_browser_process->system_request_context(), device_wallpaper_url, - ash::WallpaperController::GetDeviceWallpaperDir(), - ash::WallpaperController::GetDeviceWallpaperFilePath(), - base::Bind(&WallpaperManager::OnDeviceWallpaperDownloaded, - weak_factory_.GetWeakPtr(), account_id, hash))); - device_wallpaper_downloader_->Start(); - } -} - -void WallpaperManager::OnDeviceWallpaperDownloaded(const AccountId& account_id, - const std::string& hash, - bool success, - const GURL& url) { - if (!success) { - LOG(ERROR) << "Failed to download the device wallpaper. Fallback to " - "default wallpaper."; - SetDefaultWallpaperImpl(account_id, true /*show_wallpaper=*/); - return; - } - - base::PostTaskWithTraitsAndReplyWithResult( - FROM_HERE, {base::MayBlock()}, - base::Bind(&CheckDeviceWallpaperMatchHash, - ash::WallpaperController::GetDeviceWallpaperFilePath(), hash), - base::Bind(&WallpaperManager::OnCheckDeviceWallpaperMatchHash, - weak_factory_.GetWeakPtr(), account_id, url.spec(), hash)); -} - -void WallpaperManager::OnCheckDeviceWallpaperMatchHash( - const AccountId& account_id, - const std::string& url, - const std::string& hash, - bool match) { - if (!match) { - if (retry_download_if_failed_) { - // We only retry to download the device wallpaper one more time if the - // hash doesn't match. - retry_download_if_failed_ = false; - GURL device_wallpaper_url(url); - device_wallpaper_downloader_.reset(new CustomizationWallpaperDownloader( - g_browser_process->system_request_context(), device_wallpaper_url, - ash::WallpaperController::GetDeviceWallpaperDir(), - ash::WallpaperController::GetDeviceWallpaperFilePath(), - base::Bind(&WallpaperManager::OnDeviceWallpaperDownloaded, - weak_factory_.GetWeakPtr(), account_id, hash))); - device_wallpaper_downloader_->Start(); - } else { - LOG(ERROR) << "The device wallpaper hash doesn't match with provided " - "hash value. Fallback to default wallpaper! "; - SetDefaultWallpaperImpl(account_id, true /*show_wallpaper=*/); - - // Reset the boolean variable so that it can retry to download when the - // next device wallpaper request comes in. - retry_download_if_failed_ = true; - } - return; - } - - const base::FilePath file_path = - ash::WallpaperController::GetDeviceWallpaperFilePath(); - if (!ash::Shell::HasInstance() || ash_util::IsRunningInMash()) { - user_image_loader::StartWithFilePath( - task_runner_, ash::WallpaperController::GetDeviceWallpaperFilePath(), - ImageDecoder::ROBUST_JPEG_CODEC, - 0, // Do not crop. - base::Bind(&WallpaperManager::OnDeviceWallpaperDecoded, - weak_factory_.GetWeakPtr(), account_id)); - } else { - ash::Shell::Get()->wallpaper_controller()->ReadAndDecodeWallpaper( - base::Bind(&WallpaperManager::OnDeviceWallpaperDecoded, - weak_factory_.GetWeakPtr(), account_id), - task_runner_, file_path); - } -} - -void WallpaperManager::OnDeviceWallpaperDecoded( - const AccountId& account_id, - std::unique_ptr<user_manager::UserImage> user_image) { - // It might be possible that the device policy controlled wallpaper finishes - // decoding after the user logs in. In this case do nothing. - if (!user_manager::UserManager::Get()->IsUserLoggedIn()) { - WallpaperInfo wallpaper_info = { - ash::WallpaperController::GetDeviceWallpaperFilePath().value(), - wallpaper::WALLPAPER_LAYOUT_CENTER_CROPPED, wallpaper::DEVICE, - base::Time::Now().LocalMidnight()}; - // TODO(crbug.com/776464): This should go through PendingWallpaper after - // moving to WallpaperController. - SetWallpaper(user_image->image(), wallpaper_info); - } -} - void WallpaperManager::SetCustomizedDefaultWallpaperImpl( const base::FilePath& default_small_wallpaper_file, std::unique_ptr<gfx::ImageSkia> small_wallpaper_image,
diff --git a/chrome/browser/chromeos/login/users/wallpaper/wallpaper_manager.h b/chrome/browser/chromeos/login/users/wallpaper/wallpaper_manager.h index fb1252e3..790a134 100644 --- a/chrome/browser/chromeos/login/users/wallpaper/wallpaper_manager.h +++ b/chrome/browser/chromeos/login/users/wallpaper/wallpaper_manager.h
@@ -24,7 +24,6 @@ #include "base/threading/thread_checker.h" #include "base/threading/thread_task_runner_handle.h" #include "base/timer/timer.h" -#include "chrome/browser/chromeos/customization/customization_wallpaper_downloader.h" #include "chrome/browser/chromeos/settings/cros_settings.h" #include "components/signin/core/account_id/account_id.h" #include "components/user_manager/user_image/user_image.h" @@ -236,10 +235,6 @@ // A wrapper of |WallpaperController::InitializeUserWallpaperInfo|. void InitializeUserWallpaperInfo(const AccountId& account_id); - // If the device is enterprise managed and the device wallpaper policy exists, - // set the device wallpaper as the login screen wallpaper. - bool SetDeviceWallpaperIfApplicable(const AccountId& account_id); - // A wrapper of |WallpaperController::GetWallpaperFromCache|. bool GetWallpaperFromCache(const AccountId& account_id, gfx::ImageSkia* image); @@ -262,6 +257,7 @@ wallpaper::WallpaperInfo* info) const; // Returns true if the device wallpaper should be set for the account. + // TODO(xdai): Remove this function after migrating ShowUserWallpaper(). bool ShouldSetDeviceWallpaper(const AccountId& account_id, std::string* url, std::string* hash); @@ -306,30 +302,6 @@ const AccountId& account_id, std::unique_ptr<user_manager::UserImage> user_image); - // This is called when the device wallpaper policy changes. - void OnDeviceWallpaperPolicyChanged(); - // This is call after checking if the device wallpaper exists. - void OnDeviceWallpaperExists(const AccountId& account_id, - const std::string& url, - const std::string& hash, - bool exist); - // This is called after the device wallpaper is download (either successful or - // failed). - void OnDeviceWallpaperDownloaded(const AccountId& account_id, - const std::string& hash, - bool success, - const GURL& url); - // Check if the device wallpaper matches the hash that's provided in the - // device wallpaper policy setting. - void OnCheckDeviceWallpaperMatchHash(const AccountId& account_id, - const std::string& url, - const std::string& hash, - bool match); - // This is called when the device wallpaper is decoded successfully. - void OnDeviceWallpaperDecoded( - const AccountId& account_id, - std::unique_ptr<user_manager::UserImage> user_image); - // A wrapper of |WallpaperController::SetCustomizedDefaultWallpaperImpl|. void SetCustomizedDefaultWallpaperImpl( const base::FilePath& customized_default_wallpaper_file_small, @@ -350,11 +322,6 @@ std::unique_ptr<CrosSettings::ObserverSubscription> show_user_name_on_signin_subscription_; - std::unique_ptr<CrosSettings::ObserverSubscription> - device_wallpaper_image_subscription_; - std::unique_ptr<CustomizationWallpaperDownloader> - device_wallpaper_downloader_; - // The number of loaded wallpapers. int loaded_wallpapers_for_test_ = 0;
diff --git a/chrome/browser/chromeos/login/webview_login_browsertest.cc b/chrome/browser/chromeos/login/webview_login_browsertest.cc index 48bce5d..2dde52f 100644 --- a/chrome/browser/chromeos/login/webview_login_browsertest.cc +++ b/chrome/browser/chromeos/login/webview_login_browsertest.cc
@@ -9,6 +9,7 @@ #include "base/macros.h" #include "base/memory/ptr_util.h" #include "base/run_loop.h" +#include "base/strings/utf_string_conversions.h" #include "base/values.h" #include "chrome/browser/browser_process.h" #include "chrome/browser/chrome_notification_types.h" @@ -17,8 +18,13 @@ #include "chrome/browser/chromeos/login/test/oobe_base_test.h" #include "chrome/browser/chromeos/login/test/oobe_screen_waiter.h" #include "chrome/browser/chromeos/login/ui/login_display_webui.h" +#include "chrome/browser/chromeos/policy/browser_policy_connector_chromeos.h" +#include "chrome/browser/chromeos/policy/device_policy_builder.h" #include "chrome/browser/chromeos/policy/device_policy_cros_browser_test.h" #include "chrome/browser/chromeos/profiles/profile_helper.h" +#include "chrome/browser/policy/test/local_policy_test_server.h" +#include "chrome/browser/ui/login/login_handler.h" +#include "chrome/browser/ui/login/login_handler_test_utils.h" #include "chrome/browser/ui/webui/signin/signin_utils.h" #include "chromeos/chromeos_switches.h" #include "chromeos/dbus/dbus_thread_manager.h" @@ -27,9 +33,15 @@ #include "components/guest_view/browser/guest_view_manager.h" #include "components/onc/onc_constants.h" #include "components/onc/onc_pref_names.h" +#include "components/policy/core/common/cloud/device_management_service.h" +#include "components/policy/core/common/policy_service.h" +#include "components/policy/core/common/policy_switches.h" +#include "components/policy/policy_constants.h" #include "components/policy/proto/chrome_device_policy.pb.h" #include "components/prefs/pref_change_registrar.h" +#include "content/public/browser/browser_thread.h" #include "content/public/browser/storage_partition.h" +#include "content/public/common/content_switches.h" #include "content/public/test/browser_test_utils.h" #include "content/public/test/test_navigation_observer.h" #include "content/public/test/test_utils.h" @@ -98,6 +110,12 @@ return cookies; } +void PolicyChangedCallback(base::RepeatingClosure callback, + const base::Value* old_value, + const base::Value* new_value) { + callback.Run(); +} + // Spins the loop until a notification is received from |prefs| that the value // of |pref_name| has changed. If the notification is received before Wait() // has been called, Wait() returns immediately and no loop is spun. @@ -397,6 +415,9 @@ device_policy_test_helper_.InstallOwnerKey(); device_policy_test_helper_.MarkAsEnterpriseOwned(); + fake_session_manager_client_->set_device_policy( + device_policy_test_helper_.device_policy()->GetBlob()); + WebviewLoginTest::SetUpInProcessBrowserTestFixture(); } @@ -721,4 +742,141 @@ EXPECT_EQ("got no client cert", https_reply_content); } +class WebviewProxyAuthLoginTest : public WebviewLoginTest { + public: + WebviewProxyAuthLoginTest() + : auth_proxy_server_(std::make_unique<net::SpawnedTestServer>( + net::SpawnedTestServer::TYPE_BASIC_AUTH_PROXY, + base::FilePath())) {} + + void SetUp() override { + // Start proxy server + auth_proxy_server_->set_redirect_connect_to_localhost(true); + ASSERT_TRUE(auth_proxy_server_->Start()); + + // Prepare device policy which will be used for two purposes: + // - given to |fake_session_manager_client_|, so the device appears to have + // registered for policy. + // - the payload is given to |policy_test_server_|, so we can download fresh + // policy. + device_policy_test_helper_.device_policy() + ->policy_data() + .set_public_key_version(1); + device_policy_test_helper_.device_policy()->Build(); + + // Start policy server. Use the DMToken and DeviceId from PolicyBuilder. + // These also used in |device_policy_test_helper_| and was passed to + // |fake_session_manager_client_| above, so the device will request policy + // with these identifiers. + policy_test_server_.RegisterClient(policy::PolicyBuilder::kFakeToken, + policy::PolicyBuilder::kFakeDeviceId); + UpdateServedPolicyFromDevicePolicyTestHelper(); + ASSERT_TRUE(policy_test_server_.Start()); + + WebviewLoginTest::SetUp(); + } + + void SetUpCommandLine(base::CommandLine* command_line) override { + command_line->AppendSwitchASCII( + ::switches::kProxyServer, + auth_proxy_server_->host_port_pair().ToString()); + command_line->AppendSwitchASCII(policy::switches::kDeviceManagementUrl, + policy_test_server_.GetServiceURL().spec()); + WebviewLoginTest::SetUpCommandLine(command_line); + } + + void SetUpInProcessBrowserTestFixture() override { + WebviewLoginTest::SetUpInProcessBrowserTestFixture(); + + // Use a fake SessionManagerClient to be able to pretend that the device has + // been enrolled and registered for policy (and has a device DMToken). + auto fake_session_manager_client = + std::make_unique<FakeSessionManagerClient>(); + fake_session_manager_client_ = fake_session_manager_client.get(); + DBusThreadManager::GetSetterForTesting()->SetSessionManagerClient( + std::move(fake_session_manager_client)); + device_policy_test_helper_.InstallOwnerKey(); + device_policy_test_helper_.MarkAsEnterpriseOwned(); + + fake_session_manager_client_->set_device_policy( + device_policy_test_helper_.device_policy()->GetBlob()); + + // Set some fake state keys to make sure they are not empty. + std::vector<std::string> state_keys; + state_keys.push_back("1"); + fake_session_manager_client_->set_server_backed_state_keys(state_keys); + } + + void UpdateServedPolicyFromDevicePolicyTestHelper() { + policy_test_server_.UpdatePolicy( + policy::dm_protocol::kChromeDevicePolicyType, + std::string() /* entity_id */, + device_policy_test_helper_.device_policy() + ->payload() + .SerializeAsString()); + } + + // A proxy server which requires authentication using the 'Basic' + // authentication method. + std::unique_ptr<net::SpawnedTestServer> auth_proxy_server_; + policy::LocalPolicyTestServer policy_test_server_; + policy::DevicePolicyCrosTestHelper device_policy_test_helper_; + + // FakeDBusThreadManager uses FakeSessionManagerClient. + std::unique_ptr<chromeos::DBusThreadManagerSetter> dbus_setter_; + // Unowned pointer - owned by DBusThreadManager. + chromeos::FakeSessionManagerClient* fake_session_manager_client_; + + DISALLOW_COPY_AND_ASSIGN(WebviewProxyAuthLoginTest); +}; + +IN_PROC_BROWSER_TEST_F(WebviewProxyAuthLoginTest, ProxyAuthTransfer) { + WaitForSigninScreen(); + + LoginPromptBrowserTestObserver observer; + observer.Register(content::NotificationService::AllSources()); + + content::WindowedNotificationObserver auth_needed_waiter( + chrome::NOTIFICATION_AUTH_NEEDED, + content::NotificationService::AllSources()); + + auth_needed_waiter.Wait(); + ASSERT_FALSE(observer.handlers().empty()); + LoginHandler* login_handler = *observer.handlers().begin(); + + // Before entering auth data, make |policy_test_server_| serve a policy that + // we can use to detect if policies have been fetched. + em::ChromeDeviceSettingsProto& device_policy = + device_policy_test_helper_.device_policy()->payload(); + device_policy.mutable_device_login_screen_auto_select_certificate_for_urls() + ->add_login_screen_auto_select_certificate_rules("test_pattern"); + UpdateServedPolicyFromDevicePolicyTestHelper(); + + policy::PolicyChangeRegistrar policy_change_registrar( + g_browser_process->platform_part() + ->browser_policy_connector_chromeos() + ->GetPolicyService(), + policy::PolicyNamespace(policy::POLICY_DOMAIN_CHROME, + std::string() /* component_id */)); + + // Now enter auth data + login_handler->SetAuth(base::ASCIIToUTF16("foo"), base::ASCIIToUTF16("bar")); + WaitForGaiaPageLoad(); + + base::RunLoop run_loop; + policy_change_registrar.Observe( + policy::key::kDeviceLoginScreenAutoSelectCertificateForUrls, + base::BindRepeating(&PolicyChangedCallback, run_loop.QuitClosure())); + run_loop.Run(); + + // Press the back button at a sign-in screen without pre-existing users to + // start a new sign-in attempt. + // This will re-load gaia, rotating the StoragePartition. The new + // StoragePartition must also have the proxy auth details. + JS().Evaluate("$('signin-back-button').fire('tap')"); + WaitForGaiaPageReload(); + // Expect that we got back to the identifier page, as there are no known users + // so the sign-in screen will not display user pods. + ExpectIdentifierPage(); +} } // namespace chromeos
diff --git a/chrome/browser/devtools/devtools_sanity_browsertest.cc b/chrome/browser/devtools/devtools_sanity_browsertest.cc index ef4ecbf..a47a3d0 100644 --- a/chrome/browser/devtools/devtools_sanity_browsertest.cc +++ b/chrome/browser/devtools/devtools_sanity_browsertest.cc
@@ -2027,9 +2027,8 @@ // This tests checks that window is correctly initialized when DevTools is // opened while navigation through history with forward and back actions. // (crbug.com/627407) -// Flaky on Windows and ChromeOS. http://crbug.com/628174#c4 IN_PROC_BROWSER_TEST_F(DevToolsSanityTest, - DISABLED_TestWindowInitializedOnNavigateBack) { + TestWindowInitializedOnNavigateBack) { TestChromeWebUIControllerFactory test_factory; MockWebUIProvider mock_provider("dummyurl", "<script>\n"
diff --git a/chrome/browser/mash_service_registry.cc b/chrome/browser/mash_service_registry.cc index 149d2578..858aee8d 100644 --- a/chrome/browser/mash_service_registry.cc +++ b/chrome/browser/mash_service_registry.cc
@@ -12,30 +12,40 @@ #include "mash/quick_launch/quick_launch.h" #include "services/ui/public/interfaces/constants.mojom.h" +using content::ContentBrowserClient; + namespace mash_service_registry { namespace { struct Service { const char* name; - const char* description; + const char* display_name; + const char* process_group; // If null, uses a separate process. }; constexpr Service kServices[] = { - {mash::quick_launch::mojom::kServiceName, "Quick Launch"}, - {ui::mojom::kServiceName, "UI Service"}, - {ash::mojom::kServiceName, "Ash Window Manager and Shell"}, - {"accessibility_autoclick", "Ash Accessibility Autoclick"}, - {"touch_hud", "Ash Touch Hud"}, - {font_service::mojom::kServiceName, "Font Service"}, + {mash::quick_launch::mojom::kServiceName, "Quick Launch", nullptr}, + {ui::mojom::kServiceName, "UI Service", kAshAndUiProcessGroup}, + {ash::mojom::kServiceName, "Ash Window Manager and Shell", + kAshAndUiProcessGroup}, + {"accessibility_autoclick", "Ash Accessibility Autoclick", nullptr}, + {"touch_hud", "Ash Touch Hud", nullptr}, + {font_service::mojom::kServiceName, "Font Service", nullptr}, }; } // namespace void RegisterOutOfProcessServices( - content::ContentBrowserClient::OutOfProcessServiceMap* services) { - for (size_t i = 0; i < arraysize(kServices); ++i) { - (*services)[kServices[i].name] = - base::ASCIIToUTF16(kServices[i].description); + ContentBrowserClient::OutOfProcessServiceMap* services) { + for (const auto& service : kServices) { + base::string16 display_name = base::ASCIIToUTF16(service.display_name); + if (service.process_group) { + (*services)[service.name] = ContentBrowserClient::OutOfProcessServiceInfo( + display_name, service.process_group); + } else { + (*services)[service.name] = + ContentBrowserClient::OutOfProcessServiceInfo(display_name); + } } }
diff --git a/chrome/browser/mash_service_registry.h b/chrome/browser/mash_service_registry.h index 76e72f1..a4848c25 100644 --- a/chrome/browser/mash_service_registry.h +++ b/chrome/browser/mash_service_registry.h
@@ -11,6 +11,9 @@ namespace mash_service_registry { +// Process group used for the ash service and the ui service. Visible for test. +constexpr char kAshAndUiProcessGroup[] = "ash_and_ui"; + // Starts one of Mash's embedded services. void RegisterOutOfProcessServices( content::ContentBrowserClient::OutOfProcessServiceMap* services);
diff --git a/chrome/browser/mash_service_registry_browsertest.cc b/chrome/browser/mash_service_registry_browsertest.cc new file mode 100644 index 0000000..2629f4a --- /dev/null +++ b/chrome/browser/mash_service_registry_browsertest.cc
@@ -0,0 +1,51 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/mash_service_registry.h" + +#include "base/bind.h" +#include "base/run_loop.h" +#include "base/stl_util.h" +#include "chrome/browser/chromeos/ash_config.h" +#include "chrome/test/base/in_process_browser_test.h" +#include "content/public/browser/browser_thread.h" +#include "content/public/browser/child_process_data.h" +#include "content/public/browser/utility_process_host.h" +#include "content/public/test/browser_test_utils.h" + +namespace { + +void VerifyProcessGroupOnIOThread() { + // Ash and ui are in the same process group. + std::map<std::string, base::WeakPtr<content::UtilityProcessHost>>* groups = + content::GetServiceManagerProcessGroups(); + ASSERT_TRUE(groups); + ASSERT_TRUE( + base::ContainsKey(*groups, mash_service_registry::kAshAndUiProcessGroup)); + + // The process group has a process host. + base::WeakPtr<content::UtilityProcessHost> host = + groups->at(mash_service_registry::kAshAndUiProcessGroup); + ASSERT_TRUE(host); + + // The host is associated with a real process. + EXPECT_NE(base::kNullProcessHandle, host->GetData().handle); +} + +} // namespace + +using MashServiceRegistryTest = InProcessBrowserTest; + +IN_PROC_BROWSER_TEST_F(MashServiceRegistryTest, AshAndUiInSameProcess) { + // Test only applies to --mash (out-of-process ash). + if (chromeos::GetAshConfig() != ash::Config::MASH) + return; + + // Process group information is owned by the IO thread. + base::RunLoop run_loop; + content::BrowserThread::PostTaskAndReply( + content::BrowserThread::IO, FROM_HERE, + base::BindOnce(&VerifyProcessGroupOnIOThread), run_loop.QuitClosure()); + run_loop.Run(); +}
diff --git a/chrome/browser/mash_service_registry_unittest.cc b/chrome/browser/mash_service_registry_unittest.cc new file mode 100644 index 0000000..e8f75bd --- /dev/null +++ b/chrome/browser/mash_service_registry_unittest.cc
@@ -0,0 +1,27 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/mash_service_registry.h" + +#include "ash/public/interfaces/constants.mojom.h" +#include "base/stl_util.h" +#include "content/public/browser/content_browser_client.h" +#include "services/ui/public/interfaces/constants.mojom.h" +#include "testing/gtest/include/gtest/gtest.h" + +TEST(MashServiceRegistryTest, AshAndUiInSameProcess) { + content::ContentBrowserClient::OutOfProcessServiceMap services; + mash_service_registry::RegisterOutOfProcessServices(&services); + + // The ash service and ui service should be in the same process group. + ASSERT_TRUE(base::ContainsKey(services, ash::mojom::kServiceName)); + ASSERT_TRUE(base::ContainsKey(services, ui::mojom::kServiceName)); + std::string ash_process_group = + *services[ash::mojom::kServiceName].process_group; + std::string ui_process_group = + *services[ui::mojom::kServiceName].process_group; + EXPECT_FALSE(ash_process_group.empty()); + EXPECT_FALSE(ui_process_group.empty()); + EXPECT_EQ(ash_process_group, ui_process_group); +}
diff --git a/chrome/browser/memory_details.cc b/chrome/browser/memory_details.cc index 15a9106..5ef6e729 100644 --- a/chrome/browser/memory_details.cc +++ b/chrome/browser/memory_details.cc
@@ -96,8 +96,7 @@ num_open_fds(-1), open_fds_soft_limit(-1), renderer_type(RENDERER_UNKNOWN), - phys_footprint(0), - private_memory_footprint(0) {} + phys_footprint(0) {} ProcessMemoryInformation::ProcessMemoryInformation( const ProcessMemoryInformation& other) = default;
diff --git a/chrome/browser/memory_details.h b/chrome/browser/memory_details.h index b0f84af9..5f6b259 100644 --- a/chrome/browser/memory_details.h +++ b/chrome/browser/memory_details.h
@@ -72,9 +72,6 @@ // The physical footprint is a macOS concept that tracks anonymous, // non-discardable memory. size_t phys_footprint; - // TODO(erikchen): Remove this temporary estimate for private memory once the - // memory infra service emits the same metric. https://crbug.com/720541. - size_t private_memory_footprint; }; typedef std::vector<ProcessMemoryInformation> ProcessMemoryInformationList;
diff --git a/chrome/browser/memory_details_mac.cc b/chrome/browser/memory_details_mac.cc index ffd655d..312cb98 100644 --- a/chrome/browser/memory_details_mac.cc +++ b/chrome/browser/memory_details_mac.cc
@@ -14,7 +14,6 @@ #include "base/file_version_info.h" #include "base/files/file_path.h" #include "base/mac/foundation_util.h" -#include "base/mac/mac_util.h" #include "base/process/process_iterator.h" #include "base/strings/string_util.h" #include "base/strings/utf_string_conversions.h" @@ -66,14 +65,6 @@ base::ProcessMetrics::TaskVMInfo vm_info = metrics->GetTaskVMInfo(); info.phys_footprint = vm_info.phys_footprint; - // TODO(erikchen): Remove this temporary estimate for private memory once the - // memory infra service emits the same metric. https://crbug.com/720541. - if (base::mac::IsAtLeastOS10_12()) { - info.private_memory_footprint = vm_info.phys_footprint; - } else { - info.private_memory_footprint = vm_info.internal + vm_info.compressed; - } - processes->push_back(info); }
diff --git a/chrome/browser/metrics/metrics_memory_details.cc b/chrome/browser/metrics/metrics_memory_details.cc index a7bedac..b87c127 100644 --- a/chrome/browser/metrics/metrics_memory_details.cc +++ b/chrome/browser/metrics/metrics_memory_details.cc
@@ -21,10 +21,6 @@ #include "ppapi/features/features.h" #include "third_party/leveldatabase/leveldb_chrome.h" -#if defined(OS_MACOSX) -#include "base/mac/mac_util.h" -#endif - MemoryGrowthTracker::MemoryGrowthTracker() { } @@ -105,11 +101,6 @@ UMA_HISTOGRAM_COUNTS_10000("Memory.Browser.OpenFDsSoftLimit", open_fds_soft_limit); } -#if defined(OS_MACOSX) - UMA_HISTOGRAM_MEMORY_LARGE_MB( - "Memory.Experimental.Browser.PrivateMemoryFootprint.MacOS", - browser.processes[index].private_memory_footprint / 1024 / 1024); -#endif continue; case content::PROCESS_TYPE_RENDERER: { UMA_HISTOGRAM_MEMORY_LARGE_MB("Memory.RendererAll.Committed", @@ -129,12 +120,6 @@ num_open_fds); } extension_count++; -#if defined(OS_MACOSX) - UMA_HISTOGRAM_MEMORY_LARGE_MB( - "Memory.Experimental.Extension.PrivateMemoryFootprint.MacOS", - browser.processes[index].private_memory_footprint / 1024 / - 1024); -#endif continue; case ProcessMemoryInformation::RENDERER_CHROME: if (num_open_fds != -1) @@ -146,12 +131,6 @@ continue; case ProcessMemoryInformation::RENDERER_NORMAL: default: -#if defined(OS_MACOSX) - UMA_HISTOGRAM_MEMORY_LARGE_MB( - "Memory.Experimental.Renderer.PrivateMemoryFootprint.MacOS", - browser.processes[index].private_memory_footprint / 1024 / - 1024); -#endif // TODO(erikkay): Should we bother splitting out the other subtypes? UMA_HISTOGRAM_MEMORY_LARGE_MB("Memory.Renderer.Committed", committed / 1024); @@ -181,17 +160,6 @@ other_count++; continue; case content::PROCESS_TYPE_GPU: -#if defined(OS_MACOSX) - // Physical footprint was introduced in macOS 10.12. - if (base::mac::IsAtLeastOS10_12()) { - UMA_HISTOGRAM_MEMORY_LARGE_MB( - "Memory.Experimental.Gpu.PhysicalFootprint.MacOS", - browser.processes[index].phys_footprint / 1024 / 1024); - } - UMA_HISTOGRAM_MEMORY_LARGE_MB( - "Memory.Experimental.Gpu.PrivateMemoryFootprint.MacOS", - browser.processes[index].private_memory_footprint / 1024 / 1024); -#endif if (num_open_fds != -1 && open_fds_soft_limit != -1) { UMA_HISTOGRAM_COUNTS_10000("Memory.Gpu.OpenFDs", num_open_fds); UMA_HISTOGRAM_COUNTS_10000("Memory.Gpu.OpenFDsSoftLimit",
diff --git a/chrome/browser/metrics/thread_watcher.cc b/chrome/browser/metrics/thread_watcher.cc index fce991e..904266f6 100644 --- a/chrome/browser/metrics/thread_watcher.cc +++ b/chrome/browser/metrics/thread_watcher.cc
@@ -466,13 +466,11 @@ crash_on_hang_thread_names = command_line.GetSwitchValueASCII(switches::kCrashOnHangThreads); } else if (channel != version_info::Channel::STABLE) { - // Default to crashing the browser if UI or IO or FILE threads are not - // responsive except in stable channel. - crash_on_hang_thread_names = base::StringPrintf( - "UI:%d:%d,IO:%d:%d,FILE:%d:%d", - kLiveThreadsThreshold, crash_seconds, - kLiveThreadsThreshold, crash_seconds, - kLiveThreadsThreshold, crash_seconds * 5); + // Default to crashing the browser if UI or IO threads are not responsive + // except in stable channel. + crash_on_hang_thread_names = + base::StringPrintf("UI:%d:%d,IO:%d:%d", kLiveThreadsThreshold, + crash_seconds, kLiveThreadsThreshold, crash_seconds); } ParseCommandLineCrashOnHangThreads(crash_on_hang_thread_names, @@ -552,6 +550,7 @@ unresponsive_threshold, crash_on_hang_threads); StartWatching(BrowserThread::IO, "IO", kSleepTime, kUnresponsiveTime, unresponsive_threshold, crash_on_hang_threads); + // TODO(gab): Stop watching deprecated BrowserThreads, crbug.com/768886. StartWatching(BrowserThread::DB, "DB", kSleepTime, kUnresponsiveTime, unresponsive_threshold, crash_on_hang_threads); StartWatching(BrowserThread::FILE, "FILE", kSleepTime, kUnresponsiveTime,
diff --git a/chrome/browser/metrics/thread_watcher_report_hang.cc b/chrome/browser/metrics/thread_watcher_report_hang.cc index 93fd6c6..7bae67a 100644 --- a/chrome/browser/metrics/thread_watcher_report_hang.cc +++ b/chrome/browser/metrics/thread_watcher_report_hang.cc
@@ -50,36 +50,12 @@ ReportThreadHang(); } -NOINLINE void ThreadUnresponsive_DB() { - volatile int inhibit_comdat = __LINE__; - ALLOW_UNUSED_LOCAL(inhibit_comdat); - ReportThreadHang(); -} - -NOINLINE void ThreadUnresponsive_FILE() { - volatile int inhibit_comdat = __LINE__; - ALLOW_UNUSED_LOCAL(inhibit_comdat); - ReportThreadHang(); -} - -NOINLINE void ThreadUnresponsive_FILE_USER_BLOCKING() { - volatile int inhibit_comdat = __LINE__; - ALLOW_UNUSED_LOCAL(inhibit_comdat); - ReportThreadHang(); -} - NOINLINE void ThreadUnresponsive_PROCESS_LAUNCHER() { volatile int inhibit_comdat = __LINE__; ALLOW_UNUSED_LOCAL(inhibit_comdat); ReportThreadHang(); } -NOINLINE void ThreadUnresponsive_CACHE() { - volatile int inhibit_comdat = __LINE__; - ALLOW_UNUSED_LOCAL(inhibit_comdat); - ReportThreadHang(); -} - NOINLINE void ThreadUnresponsive_IO() { volatile int inhibit_comdat = __LINE__; ALLOW_UNUSED_LOCAL(inhibit_comdat); @@ -91,19 +67,16 @@ switch (thread_id) { case content::BrowserThread::UI: return ThreadUnresponsive_UI(); - case content::BrowserThread::DB: - return ThreadUnresponsive_DB(); - case content::BrowserThread::FILE: - return ThreadUnresponsive_FILE(); - case content::BrowserThread::FILE_USER_BLOCKING: - return ThreadUnresponsive_FILE_USER_BLOCKING(); case content::BrowserThread::PROCESS_LAUNCHER: return ThreadUnresponsive_PROCESS_LAUNCHER(); - case content::BrowserThread::CACHE: - return ThreadUnresponsive_CACHE(); case content::BrowserThread::IO: return ThreadUnresponsive_IO(); case content::BrowserThread::ID_COUNT: + // TODO(gab): Get rid of deprecated BrowserThread IDs. + case content::BrowserThread::DB: + case content::BrowserThread::FILE: + case content::BrowserThread::FILE_USER_BLOCKING: + case content::BrowserThread::CACHE: NOTREACHED(); break; }
diff --git a/chrome/browser/net/errorpage_browsertest.cc b/chrome/browser/net/errorpage_browsertest.cc index 7b29449..e577d73 100644 --- a/chrome/browser/net/errorpage_browsertest.cc +++ b/chrome/browser/net/errorpage_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 <algorithm> #include <memory> #include <utility> @@ -63,12 +64,14 @@ #include "mojo/public/cpp/bindings/strong_binding.h" #include "net/base/filename_util.h" #include "net/base/net_errors.h" +#include "net/dns/mock_host_resolver.h" #include "net/http/failing_http_transaction_factory.h" #include "net/http/http_cache.h" #include "net/test/embedded_test_server/embedded_test_server.h" #include "net/test/embedded_test_server/http_request.h" #include "net/test/embedded_test_server/http_response.h" #include "net/test/url_request/url_request_failed_job.h" +#include "net/test/url_request/url_request_mock_data_job.h" #include "net/test/url_request/url_request_mock_http_job.h" #include "net/url_request/url_request_context.h" #include "net/url_request/url_request_context_getter.h" @@ -144,12 +147,13 @@ // Checks that the local error page is being displayed, without remotely // retrieved navigation corrections, and with the specified error string. -void ExpectDisplayingLocalErrorPage(Browser* browser, +void ExpectDisplayingLocalErrorPage(const std::string& url, + Browser* browser, const std::string& error_string) { EXPECT_TRUE(IsDisplayingText(browser, error_string)); // Locally generated error pages should not have navigation corrections. - EXPECT_FALSE(IsDisplayingText(browser, "http://mock.http/title2.html")); + EXPECT_FALSE(IsDisplayingText(browser, url)); // Locally generated error pages should not have a link with search terms. EXPECT_FALSE(IsDisplayingText(browser, "search query")); @@ -157,19 +161,23 @@ // Checks that the local error page is being displayed, without remotely // retrieved navigation corrections, and with the specified error code. -void ExpectDisplayingLocalErrorPage(Browser* browser, net::Error error_code) { - ExpectDisplayingLocalErrorPage(browser, net::ErrorToShortString(error_code)); +void ExpectDisplayingLocalErrorPage(const std::string& url, + Browser* browser, + net::Error error_code) { + ExpectDisplayingLocalErrorPage(url, browser, + net::ErrorToShortString(error_code)); } // Checks that an error page with information retrieved from the navigation // correction service is being displayed, with the specified specified error // string. -void ExpectDisplayingNavigationCorrections(Browser* browser, +void ExpectDisplayingNavigationCorrections(const std::string& url, + Browser* browser, const std::string& error_string) { EXPECT_TRUE(IsDisplayingText(browser, error_string)); // Check that the mock navigation corrections are displayed. - EXPECT_TRUE(IsDisplayingText(browser, "http://mock.http/title2.html")); + EXPECT_TRUE(IsDisplayingText(browser, url)); // Check that the search terms are displayed as a link. EXPECT_TRUE(IsDisplayingText(browser, "search query")); @@ -182,9 +190,10 @@ // Checks that an error page with information retrieved from the navigation // correction service is being displayed, with the specified specified error // code. -void ExpectDisplayingNavigationCorrections(Browser* browser, +void ExpectDisplayingNavigationCorrections(const std::string& url, + Browser* browser, net::Error error_code) { - ExpectDisplayingNavigationCorrections(browser, + ExpectDisplayingNavigationCorrections(url, browser, net::ErrorToShortString(error_code)); } @@ -428,8 +437,7 @@ // provided owner every time there is a new request. class LinkDoctorInterceptor : public net::URLRequestInterceptor { public: - explicit LinkDoctorInterceptor(class DNSErrorPageTest* owner) - : owner_(owner) {} + explicit LinkDoctorInterceptor(class DNSErrorPageTest* owner); ~LinkDoctorInterceptor() override = default; // net::URLRequestInterceptor implementation @@ -439,12 +447,15 @@ private: DNSErrorPageTest* owner_; + GURL link_doctor_url; DISALLOW_COPY_AND_ASSIGN(LinkDoctorInterceptor); }; class DNSErrorPageTest : public ErrorPageTest { public: + friend LinkDoctorInterceptor; + DNSErrorPageTest() { if (!base::FeatureList::IsEnabled(features::kNetworkService)) return; @@ -479,15 +490,15 @@ BrowserThread::UI, FROM_HERE, base::BindOnce(&DNSErrorPageTest::RequestCreated, base::Unretained(owner))); - - return WriteFileToURLLoader(params, "mock-link-doctor.json"); + return WriteFileToURLLoader(owner, params, + "mock-link-doctor.json"); } // Add an interceptor for the search engine the error page will // use. if (params->url_request.url.host() == owner->search_term_url_.host()) { - return WriteFileToURLLoader(params, "title3.html"); + return WriteFileToURLLoader(owner, params, "title3.html"); } return false; @@ -530,6 +541,7 @@ void TearDownOnMainThread() override { url_loader_interceptor_.reset(); } static bool WriteFileToURLLoader( + DNSErrorPageTest* owner, content::URLLoaderInterceptor::RequestParams* params, std::string path) { base::ScopedAllowBlockingForTesting allow_blocking; @@ -548,12 +560,26 @@ const bool result = base::ReadFileToString(file_path, &contents); EXPECT_TRUE(result); + if (path == "mock-link-doctor.json") { + GURL url = + owner->embedded_test_server()->GetURL("mock.http", "/title2.html"); + + std::string placeholder = "http://mock.http/title2.html"; + contents.replace(contents.find(placeholder), placeholder.length(), + url.spec()); + } + content::URLLoaderInterceptor::WriteResponse( net::URLRequestTestJob::test_headers(), contents, params->client.get()); return true; } void SetUpOnMainThread() override { + // All mock.http requests get served by the embedded test server. + host_resolver()->AddRule("mock.http", "127.0.0.1"); + + ASSERT_TRUE(embedded_test_server()->Start()); + UIThreadSearchTermsData search_terms_data(browser()->profile()); search_term_url_ = GURL(search_terms_data.GoogleBaseURLValue()); @@ -624,7 +650,9 @@ ui_test_utils::NavigateToURLBlockUntilNavigationsComplete( browser(), non_existent_file_url, 1); - ExpectDisplayingLocalErrorPage(browser(), net::ERR_FILE_NOT_FOUND); + ExpectDisplayingLocalErrorPage( + embedded_test_server()->GetURL("mock.http", "/title2.html").spec(), + browser(), net::ERR_FILE_NOT_FOUND); // Should not request Link Doctor corrections for local errors. EXPECT_EQ(0, num_requests()); // Only errors on HTTP/HTTPS pages should display a diagnostics button. @@ -637,7 +665,9 @@ ui_test_utils::NavigateToURLBlockUntilNavigationsComplete( browser(), URLRequestFailedJob::GetMockHttpUrl(net::ERR_FAILED), 1); - ExpectDisplayingLocalErrorPage(browser(), net::ERR_FAILED); + ExpectDisplayingLocalErrorPage( + embedded_test_server()->GetURL("mock.http", "/title2.html").spec(), + browser(), net::ERR_FAILED); // Should not request Link Doctor corrections for this error. EXPECT_EQ(0, num_requests()); } @@ -648,19 +678,21 @@ // the Link Doctor response. The second navigation is the Link Doctor. ui_test_utils::NavigateToURLBlockUntilNavigationsComplete( browser(), GetDnsErrorURL(), 2); - ExpectDisplayingNavigationCorrections(browser(), net::ERR_NAME_NOT_RESOLVED); + ExpectDisplayingNavigationCorrections( + embedded_test_server()->GetURL("mock.http", "/title2.html").spec(), + browser(), net::ERR_NAME_NOT_RESOLVED); EXPECT_EQ(1, num_requests()); } // Test that a DNS error occuring in the main frame does not result in an // additional session history entry. IN_PROC_BROWSER_TEST_F(DNSErrorPageTest, DNSError_GoBack1) { - ASSERT_TRUE(embedded_test_server()->Start()); - NavigateToFileURL("/title2.html"); ui_test_utils::NavigateToURLBlockUntilNavigationsComplete( browser(), GetDnsErrorURL(), 2); - ExpectDisplayingNavigationCorrections(browser(), net::ERR_NAME_NOT_RESOLVED); + ExpectDisplayingNavigationCorrections( + embedded_test_server()->GetURL("mock.http", "/title2.html").spec(), + browser(), net::ERR_NAME_NOT_RESOLVED); GoBackAndWaitForTitle("Title Of Awesomeness", 1); EXPECT_EQ(1, num_requests()); } @@ -668,19 +700,21 @@ // Test that a DNS error occuring in the main frame does not result in an // additional session history entry. IN_PROC_BROWSER_TEST_F(DNSErrorPageTest, DNSError_GoBack2) { - ASSERT_TRUE(embedded_test_server()->Start()); - NavigateToFileURL("/title2.html"); ui_test_utils::NavigateToURLBlockUntilNavigationsComplete( browser(), GetDnsErrorURL(), 2); - ExpectDisplayingNavigationCorrections(browser(), net::ERR_NAME_NOT_RESOLVED); + ExpectDisplayingNavigationCorrections( + embedded_test_server()->GetURL("mock.http", "/title2.html").spec(), + browser(), net::ERR_NAME_NOT_RESOLVED); EXPECT_EQ(1, num_requests()); NavigateToFileURL("/title3.html"); GoBackAndWaitForNavigations(2); - ExpectDisplayingNavigationCorrections(browser(), net::ERR_NAME_NOT_RESOLVED); + ExpectDisplayingNavigationCorrections( + embedded_test_server()->GetURL("mock.http", "/title2.html").spec(), + browser(), net::ERR_NAME_NOT_RESOLVED); EXPECT_EQ(2, num_requests()); GoBackAndWaitForTitle("Title Of Awesomeness", 1); @@ -690,50 +724,57 @@ // Test that a DNS error occuring in the main frame does not result in an // additional session history entry. IN_PROC_BROWSER_TEST_F(DNSErrorPageTest, DNSError_GoBack2AndForward) { - ASSERT_TRUE(embedded_test_server()->Start()); - NavigateToFileURL("/title2.html"); ui_test_utils::NavigateToURLBlockUntilNavigationsComplete( browser(), GetDnsErrorURL(), 2); - ExpectDisplayingNavigationCorrections(browser(), net::ERR_NAME_NOT_RESOLVED); + + std::string url = + embedded_test_server()->GetURL("mock.http", "/title2.html").spec(); + ExpectDisplayingNavigationCorrections(url, browser(), + net::ERR_NAME_NOT_RESOLVED); EXPECT_EQ(1, num_requests()); NavigateToFileURL("/title3.html"); GoBackAndWaitForNavigations(2); - ExpectDisplayingNavigationCorrections(browser(), net::ERR_NAME_NOT_RESOLVED); + ExpectDisplayingNavigationCorrections(url, browser(), + net::ERR_NAME_NOT_RESOLVED); EXPECT_EQ(2, num_requests()); GoBackAndWaitForTitle("Title Of Awesomeness", 1); GoForwardAndWaitForNavigations(2); - ExpectDisplayingNavigationCorrections(browser(), net::ERR_NAME_NOT_RESOLVED); + ExpectDisplayingNavigationCorrections(url, browser(), + net::ERR_NAME_NOT_RESOLVED); EXPECT_EQ(3, num_requests()); } // Test that a DNS error occuring in the main frame does not result in an // additional session history entry. IN_PROC_BROWSER_TEST_F(DNSErrorPageTest, DNSError_GoBack2Forward2) { - ASSERT_TRUE(embedded_test_server()->Start()); - NavigateToFileURL("/title3.html"); + std::string url = + embedded_test_server()->GetURL("mock.http", "/title2.html").spec(); ui_test_utils::NavigateToURLBlockUntilNavigationsComplete( browser(), GetDnsErrorURL(), 2); - ExpectDisplayingNavigationCorrections(browser(), net::ERR_NAME_NOT_RESOLVED); + ExpectDisplayingNavigationCorrections(url, browser(), + net::ERR_NAME_NOT_RESOLVED); EXPECT_EQ(1, num_requests()); NavigateToFileURL("/title2.html"); GoBackAndWaitForNavigations(2); - ExpectDisplayingNavigationCorrections(browser(), net::ERR_NAME_NOT_RESOLVED); + ExpectDisplayingNavigationCorrections(url, browser(), + net::ERR_NAME_NOT_RESOLVED); EXPECT_EQ(2, num_requests()); GoBackAndWaitForTitle("Title Of More Awesomeness", 1); GoForwardAndWaitForNavigations(2); - ExpectDisplayingNavigationCorrections(browser(), net::ERR_NAME_NOT_RESOLVED); + ExpectDisplayingNavigationCorrections(url, browser(), + net::ERR_NAME_NOT_RESOLVED); EXPECT_EQ(3, num_requests()); GoForwardAndWaitForTitle("Title Of Awesomeness", 1); @@ -746,7 +787,9 @@ // page. ui_test_utils::NavigateToURLBlockUntilNavigationsComplete( browser(), GetDnsErrorURL(), 2); - ExpectDisplayingNavigationCorrections(browser(), net::ERR_NAME_NOT_RESOLVED); + ExpectDisplayingNavigationCorrections( + embedded_test_server()->GetURL("mock.http", "/title2.html").spec(), + browser(), net::ERR_NAME_NOT_RESOLVED); EXPECT_EQ(1, num_requests()); content::WebContents* web_contents = @@ -782,7 +825,9 @@ // Go back to the error page, to make sure the history is correct. GoBackAndWaitForNavigations(2); - ExpectDisplayingNavigationCorrections(browser(), net::ERR_NAME_NOT_RESOLVED); + ExpectDisplayingNavigationCorrections( + embedded_test_server()->GetURL("mock.http", "/title2.html").spec(), + browser(), net::ERR_NAME_NOT_RESOLVED); EXPECT_EQ(3, num_requests()); } @@ -790,9 +835,12 @@ IN_PROC_BROWSER_TEST_F(DNSErrorPageTest, DNSError_DoReload) { // The first navigation should fail, and the second one should be the error // page. + std::string url = + embedded_test_server()->GetURL("mock.http", "/title2.html").spec(); ui_test_utils::NavigateToURLBlockUntilNavigationsComplete( browser(), GetDnsErrorURL(), 2); - ExpectDisplayingNavigationCorrections(browser(), net::ERR_NAME_NOT_RESOLVED); + ExpectDisplayingNavigationCorrections(url, browser(), + net::ERR_NAME_NOT_RESOLVED); EXPECT_EQ(1, num_requests()); content::WebContents* web_contents = @@ -807,7 +855,8 @@ web_contents->GetMainFrame()->ExecuteJavaScriptForTests( base::ASCIIToUTF16("document.getElementById('reload-button').click();")); nav_observer.Wait(); - ExpectDisplayingNavigationCorrections(browser(), net::ERR_NAME_NOT_RESOLVED); + ExpectDisplayingNavigationCorrections(url, browser(), + net::ERR_NAME_NOT_RESOLVED); // There should have been two more requests to the correction service: One // for the new error page, and one for tracking purposes. Have to make sure @@ -823,9 +872,12 @@ DNSError_DoReloadAfterSameDocumentNavigation) { // The first navigation should fail, and the second one should be the error // page. + std::string url = + embedded_test_server()->GetURL("mock.http", "/title2.html").spec(); ui_test_utils::NavigateToURLBlockUntilNavigationsComplete( browser(), GetDnsErrorURL(), 2); - ExpectDisplayingNavigationCorrections(browser(), net::ERR_NAME_NOT_RESOLVED); + ExpectDisplayingNavigationCorrections(url, browser(), + net::ERR_NAME_NOT_RESOLVED); EXPECT_EQ(1, num_requests()); content::WebContents* web_contents = @@ -837,7 +889,8 @@ base::ASCIIToUTF16("document.location='#';")); content::WaitForLoadStop(web_contents); // Page being displayed should not change. - ExpectDisplayingNavigationCorrections(browser(), net::ERR_NAME_NOT_RESOLVED); + ExpectDisplayingNavigationCorrections(url, browser(), + net::ERR_NAME_NOT_RESOLVED); // No new requests should have been issued. EXPECT_EQ(1, num_requests()); @@ -850,7 +903,8 @@ web_contents->GetMainFrame()->ExecuteJavaScriptForTests( base::ASCIIToUTF16("document.getElementById('reload-button').click();")); nav_observer2.Wait(); - ExpectDisplayingNavigationCorrections(browser(), net::ERR_NAME_NOT_RESOLVED); + ExpectDisplayingNavigationCorrections(url, browser(), + net::ERR_NAME_NOT_RESOLVED); // There should have been two more requests to the correction service: One // for the new error page, and one for tracking purposes. Have to make sure @@ -863,10 +917,12 @@ IN_PROC_BROWSER_TEST_F(DNSErrorPageTest, DNSError_DoClickLink) { // The first navigation should fail, and the second one should be the error // page. - + GURL url = embedded_test_server()->GetURL("mock.http", "/title2.html"); ui_test_utils::NavigateToURLBlockUntilNavigationsComplete( browser(), GetDnsErrorURL(), 2); - ExpectDisplayingNavigationCorrections(browser(), net::ERR_NAME_NOT_RESOLVED); + ExpectDisplayingNavigationCorrections( + embedded_test_server()->GetURL("mock.http", "/title2.html").spec(), + browser(), net::ERR_NAME_NOT_RESOLVED); EXPECT_EQ(1, num_requests()); content::WebContents* web_contents = @@ -878,7 +934,7 @@ web_contents, base::ASCIIToUTF16("Title Of Awesomeness")); std::string link_selector = - "document.querySelector('a[href=\"http://mock.http/title2.html\"]')"; + "document.querySelector('a[href=\"" + url.spec() + "\"]')"; // The tracking request is triggered by onmousedown, so it catches middle // mouse button clicks, as well as left clicks. web_contents->GetMainFrame()->ExecuteJavaScriptForTests( @@ -900,7 +956,6 @@ // Test that a DNS error occuring in an iframe does not result in showing // navigation corrections. IN_PROC_BROWSER_TEST_F(DNSErrorPageTest, IFrameDNSError_Basic) { - ASSERT_TRUE(embedded_test_server()->Start()); NavigateToURLAndWaitForTitle( embedded_test_server()->GetURL("/iframe_dns_error.html"), "Blah", 1); // We expect to have two history entries, since we started off with navigation @@ -920,8 +975,6 @@ // Test that a DNS error occuring in an iframe does not result in an // additional session history entry. IN_PROC_BROWSER_TEST_F(DNSErrorPageTest, MAYBE_IFrameDNSError_GoBack) { - ASSERT_TRUE(embedded_test_server()->Start()); - ui_test_utils::NavigateToURL(browser(), embedded_test_server()->GetURL("/title2.html")); ui_test_utils::NavigateToURL( @@ -942,8 +995,6 @@ // additional session history entry. IN_PROC_BROWSER_TEST_F(DNSErrorPageTest, MAYBE_IFrameDNSError_GoBackAndForward) { - ASSERT_TRUE(embedded_test_server()->Start()); - NavigateToFileURL("/title2.html"); NavigateToFileURL("/iframe_dns_error.html"); GoBackAndWaitForTitle("Title Of Awesomeness", 1); @@ -956,8 +1007,6 @@ // To ensure that the main document has completed loading, JavaScript is used to // inject an iframe after loading is done. IN_PROC_BROWSER_TEST_F(DNSErrorPageTest, IFrameDNSError_JavaScript) { - ASSERT_TRUE(embedded_test_server()->Start()); - content::WebContents* wc = browser()->tab_strip_model()->GetActiveWebContents(); GURL fail_url = @@ -1022,7 +1071,6 @@ // Checks that navigation corrections are not loaded when we receive an actual // 404 page. IN_PROC_BROWSER_TEST_F(DNSErrorPageTest, Page404) { - ASSERT_TRUE(embedded_test_server()->Start()); NavigateToURLAndWaitForTitle(embedded_test_server()->GetURL("/page404.html"), "SUCCESS", 1); EXPECT_EQ(0, num_requests()); @@ -1033,26 +1081,26 @@ IN_PROC_BROWSER_TEST_F(DNSErrorPageTest, Empty404) { // The first navigation should fail and load a blank page, while it fetches // the Link Doctor response. The second navigation is the Link Doctor. - ASSERT_TRUE(embedded_test_server()->Start()); - GURL url = embedded_test_server()->GetURL("/errorpage/empty404.html"); ui_test_utils::NavigateToURLBlockUntilNavigationsComplete(browser(), url, 2); // This depends on the non-internationalized error ID string in // localized_error.cc. - ExpectDisplayingNavigationCorrections(browser(), "HTTP ERROR 404"); + ExpectDisplayingNavigationCorrections( + embedded_test_server()->GetURL("mock.http", "/title2.html").spec(), + browser(), "HTTP ERROR 404"); EXPECT_EQ(1, num_requests()); } // Checks that a local error page is shown in response to a 500 error page // without a body. IN_PROC_BROWSER_TEST_F(DNSErrorPageTest, Empty500) { - ASSERT_TRUE(embedded_test_server()->Start()); - ui_test_utils::NavigateToURL( browser(), embedded_test_server()->GetURL("/errorpage/empty500.html")); // This depends on the non-internationalized error ID string in // localized_error.cc. - ExpectDisplayingLocalErrorPage(browser(), "HTTP ERROR 500"); + ExpectDisplayingLocalErrorPage( + embedded_test_server()->GetURL("mock.http", "/title2.html").spec(), + browser(), "HTTP ERROR 500"); EXPECT_EQ(0, num_requests()); } @@ -1060,7 +1108,6 @@ // is correctly transferred, and that stale cached copied can be loaded // from the javascript. IN_PROC_BROWSER_TEST_F(DNSErrorPageTest, StaleCacheStatus) { - ASSERT_TRUE(embedded_test_server()->Start()); // Load cache with entry with "nocache" set, to create stale // cache. Currently it needs to at least have an etag for the cache to // not give up on it entirely, however. See https://crbug.com/784520 @@ -1138,20 +1185,36 @@ EXPECT_EQ(1, result); } +LinkDoctorInterceptor::LinkDoctorInterceptor(DNSErrorPageTest* owner) + : owner_(owner) { + link_doctor_url = + owner->embedded_test_server()->GetURL("mock.http", "/title2.html"); +} + net::URLRequestJob* LinkDoctorInterceptor::MaybeInterceptRequest( net::URLRequest* request, net::NetworkDelegate* network_delegate) const { DCHECK_CURRENTLY_ON(BrowserThread::IO); + base::ScopedAllowBlockingForTesting allow_blocking; BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, base::BindOnce(&DNSErrorPageTest::RequestCreated, base::Unretained(owner_))); - base::FilePath root_http; - PathService::Get(chrome::DIR_TEST_DATA, &root_http); - return new net::URLRequestMockHTTPJob( - request, network_delegate, - root_http.AppendASCII("mock-link-doctor.json")); + base::FilePath file_path; + PathService::Get(chrome::DIR_TEST_DATA, &file_path); + file_path = file_path.AppendASCII("mock-link-doctor.json"); + + std::string contents; + const bool result = base::ReadFileToString(file_path, &contents); + EXPECT_TRUE(result); + + std::string placeholder = "http://mock.http/title2.html"; + contents.replace(contents.find(placeholder), placeholder.length(), + link_doctor_url.spec()); + + return new net::URLRequestMockDataJob(request, network_delegate, contents, 1, + false); } class ErrorPageAutoReloadTest : public InProcessBrowserTest { @@ -1402,13 +1465,16 @@ // successfully loaded. IN_PROC_BROWSER_TEST_F(ErrorPageNavigationCorrectionsFailTest, FetchCorrectionsFails) { + ASSERT_TRUE(embedded_test_server()->Start()); ui_test_utils::NavigateToURLBlockUntilNavigationsComplete( browser(), URLRequestFailedJob::GetMockHttpUrl(net::ERR_NAME_NOT_RESOLVED), 2); // Verify that the expected error page is being displayed. - ExpectDisplayingLocalErrorPage(browser(), net::ERR_NAME_NOT_RESOLVED); + ExpectDisplayingLocalErrorPage( + embedded_test_server()->GetURL("mock.http", "/title2.html").spec(), + browser(), net::ERR_NAME_NOT_RESOLVED); // Diagnostics button should be displayed, if available on this platform. EXPECT_EQ(PlatformSupportsDiagnosticsTool(), @@ -1677,19 +1743,21 @@ // Make sure HTTP/0.9 is disabled on non-default ports by default. IN_PROC_BROWSER_TEST_F(DNSErrorPageTest, Http09WeirdPort) { - ASSERT_TRUE(embedded_test_server()->Start()); ui_test_utils::NavigateToURL( browser(), embedded_test_server()->GetURL("/echo-raw?spam")); - ExpectDisplayingLocalErrorPage(browser(), net::ERR_INVALID_HTTP_RESPONSE); + ExpectDisplayingLocalErrorPage( + embedded_test_server()->GetURL("mock.http", "/title2.html").spec(), + browser(), net::ERR_INVALID_HTTP_RESPONSE); } // Test that redirects to invalid URLs show an error. See // https://crbug.com/462272. IN_PROC_BROWSER_TEST_F(DNSErrorPageTest, RedirectToInvalidURL) { - ASSERT_TRUE(embedded_test_server()->Start()); GURL url = embedded_test_server()->GetURL("/server-redirect?https://:"); ui_test_utils::NavigateToURL(browser(), url); - ExpectDisplayingLocalErrorPage(browser(), net::ERR_INVALID_REDIRECT); + ExpectDisplayingLocalErrorPage( + embedded_test_server()->GetURL("mock.http", "/title2.html").spec(), + browser(), net::ERR_INVALID_REDIRECT); // The error page should commit before the redirect, not after. EXPECT_EQ(url, browser() ->tab_strip_model() @@ -1734,7 +1802,9 @@ // is displayed. This tests the particular case in which the response body // is small enough that the entire response must be read before its MIME type // can be determined. -IN_PROC_BROWSER_TEST_F(DNSErrorPageTest, +class ErrorPageSniffTest : public InProcessBrowserTest {}; + +IN_PROC_BROWSER_TEST_F(ErrorPageSniffTest, SniffSmallHttpErrorResponseAsDownload) { const char kErrorPath[] = "/foo"; embedded_test_server()->RegisterRequestHandler(base::BindRepeating( @@ -1744,7 +1814,9 @@ ui_test_utils::NavigateToURL(browser(), embedded_test_server()->GetURL(kErrorPath)); - ExpectDisplayingLocalErrorPage(browser(), net::ERR_INVALID_RESPONSE); + ExpectDisplayingLocalErrorPage( + embedded_test_server()->GetURL("mock.http", "/title2.html").spec(), + browser(), net::ERR_INVALID_RESPONSE); } } // namespace
diff --git a/chrome/browser/notifications/notification_platform_bridge_win.cc b/chrome/browser/notifications/notification_platform_bridge_win.cc index 99dcef6..65e90c8 100644 --- a/chrome/browser/notifications/notification_platform_bridge_win.cc +++ b/chrome/browser/notifications/notification_platform_bridge_win.cc
@@ -52,6 +52,10 @@ winui::Notifications::ToastNotification*, winui::Notifications::ToastDismissedEventArgs*> ToastDismissedHandler; +typedef winfoundtn::ITypedEventHandler< + winui::Notifications::ToastNotification*, + winui::Notifications::ToastFailedEventArgs*> + ToastFailedHandler; // Templated wrapper for winfoundtn::GetActivationFactory(). template <unsigned int size, typename T> @@ -272,6 +276,15 @@ return; } + auto failed_handler = mswr::Callback<ToastFailedHandler>( + this, &NotificationPlatformBridgeWinImpl::OnFailed); + EventRegistrationToken failed_token; + hr = toast->add_Failed(failed_handler.Get(), &failed_token); + if (FAILED(hr)) { + LOG(ERROR) << "Unable to add toast failed event handler"; + return; + } + hr = notifier_->Show(toast.Get()); if (FAILED(hr)) LOG(ERROR) << "Unable to display the notification"; @@ -430,6 +443,14 @@ return S_OK; } + HRESULT OnFailed( + winui::Notifications::IToastNotification* notification, + winui::Notifications::IToastFailedEventArgs* /* arguments */) { + // TODO(chengx): Investigate what the correct behavior should be here and + // implement it. + return S_OK; + } + HRESULT InitializeToastNotifier() { mswr::ComPtr<winui::Notifications::IToastNotificationManagerStatics> toast_manager;
diff --git a/chrome/browser/resources/pdf/pdf.js b/chrome/browser/resources/pdf/pdf.js index 5544dec..80ec971 100644 --- a/chrome/browser/resources/pdf/pdf.js +++ b/chrome/browser/resources/pdf/pdf.js
@@ -227,7 +227,7 @@ document.body.addEventListener('change-page', e => { this.viewport_.goToPage(e.detail.page); if (e.detail.origin == 'bookmark') - this.metrics.onBookmarkFollowed(); + this.metrics.onFollowBookmark(); else if (e.detail.origin == 'pageselector') this.metrics.onPageSelectorNavigation(); });
diff --git a/chrome/browser/sync/sessions/browser_list_router_helper.cc b/chrome/browser/sync/sessions/browser_list_router_helper.cc index 472ef4e..1f42b27 100644 --- a/chrome/browser/sync/sessions/browser_list_router_helper.cc +++ b/chrome/browser/sync/sessions/browser_list_router_helper.cc
@@ -53,8 +53,19 @@ int index, bool foreground) { if (web_contents && Profile::FromBrowserContext( - web_contents->GetBrowserContext()) == profile_) + web_contents->GetBrowserContext()) == profile_) { router_->NotifyTabModified(web_contents, false); + } +} + +void BrowserListRouterHelper::TabReplacedAt(TabStripModel* tab_strip_model, + content::WebContents* old_contents, + content::WebContents* new_contents, + int index) { + if (new_contents && Profile::FromBrowserContext( + new_contents->GetBrowserContext()) == profile_) { + router_->NotifyTabModified(new_contents, false); + } } } // namespace sync_sessions
diff --git a/chrome/browser/sync/sessions/browser_list_router_helper.h b/chrome/browser/sync/sessions/browser_list_router_helper.h index 9f528ef..93de5b3 100644 --- a/chrome/browser/sync/sessions/browser_list_router_helper.h +++ b/chrome/browser/sync/sessions/browser_list_router_helper.h
@@ -5,6 +5,8 @@ #ifndef CHROME_BROWSER_SYNC_SESSIONS_BROWSER_LIST_ROUTER_HELPER_H_ #define CHROME_BROWSER_SYNC_SESSIONS_BROWSER_LIST_ROUTER_HELPER_H_ +#include <set> + #include "chrome/browser/sync/sessions/sync_sessions_web_contents_router.h" #include "chrome/browser/ui/browser_list_observer.h" #include "chrome/browser/ui/tabs/tab_strip_model_observer.h" @@ -31,6 +33,10 @@ content::WebContents* web_contents, int index, bool foreground) override; + void TabReplacedAt(TabStripModel* tab_strip_model, + content::WebContents* old_contents, + content::WebContents* new_contents, + int index) override; // |router_| owns |this|. SyncSessionsWebContentsRouter* router_;
diff --git a/chrome/browser/sync/sessions/browser_list_router_helper_unittest.cc b/chrome/browser/sync/sessions/browser_list_router_helper_unittest.cc index f142765..f366640 100644 --- a/chrome/browser/sync/sessions/browser_list_router_helper_unittest.cc +++ b/chrome/browser/sync/sessions/browser_list_router_helper_unittest.cc
@@ -4,9 +4,15 @@ #include "chrome/browser/sync/sessions/browser_list_router_helper.h" +#include <memory> +#include <vector> + #include "base/stl_util.h" +#include "chrome/browser/browser_process.h" +#include "chrome/browser/resource_coordinator/tab_manager.h" #include "chrome/browser/sync/sessions/sync_sessions_web_contents_router.h" #include "chrome/browser/sync/sessions/sync_sessions_web_contents_router_factory.h" +#include "chrome/browser/ui/browser_list.h" #include "chrome/browser/ui/tabs/tab_strip_model.h" #include "chrome/test/base/browser_with_test_window_test.h" #include "chrome/test/base/testing_profile.h" @@ -20,15 +26,18 @@ void OnLocalTabModified(SyncedTabDelegate* modified_tab) override { seen_urls_.push_back(modified_tab->GetVirtualURLAtIndex( modified_tab->GetCurrentEntryIndex())); + seen_ids_.push_back(modified_tab->GetSessionId()); } void OnFaviconsChanged(const std::set<GURL>& page_urls, const GURL& icon_url) override {} std::vector<GURL>* seen_urls() { return &seen_urls_; } + std::vector<SessionID::id_type>* seen_ids() { return &seen_ids_; } private: std::vector<GURL> seen_urls_; + std::vector<SessionID::id_type> seen_ids_; }; class BrowserListRouterHelperTest : public BrowserWithTestWindowTest { @@ -48,15 +57,12 @@ std::unique_ptr<Browser> browser_2( CreateBrowser(profile_2, browser()->type(), false, window_2.get())); - SyncSessionsWebContentsRouter* router_1 = - SyncSessionsWebContentsRouterFactory::GetInstance()->GetForProfile( - profile_1); - SyncSessionsWebContentsRouter* router_2 = - SyncSessionsWebContentsRouterFactory::GetInstance()->GetForProfile( - profile_2); - - router_1->StartRoutingTo(&handler_1); - router_2->StartRoutingTo(&handler_2); + SyncSessionsWebContentsRouterFactory::GetInstance() + ->GetForProfile(profile_1) + ->StartRoutingTo(&handler_1); + SyncSessionsWebContentsRouterFactory::GetInstance() + ->GetForProfile(profile_2) + ->StartRoutingTo(&handler_2); GURL gurl_1("http://foo1.com"); GURL gurl_2("http://foo2.com"); @@ -100,4 +106,61 @@ new_browser_in_second_profile->tab_strip_model()->CloseAllTabs(); } +// Added when fixing https://crbug.com/777745, ensure tab discards are observed. +TEST_F(BrowserListRouterHelperTest, NotifyOnDiscardTab) { + TestingProfile* profile_1 = profile(); + TestingProfile* profile_2 = + profile_manager()->CreateTestingProfile("testing_profile2"); + + std::unique_ptr<BrowserWindow> window_2(CreateBrowserWindow()); + std::unique_ptr<Browser> browser_2( + CreateBrowser(profile_2, browser()->type(), false, window_2.get())); + + SyncSessionsWebContentsRouterFactory::GetInstance() + ->GetForProfile(profile_1) + ->StartRoutingTo(&handler_1); + SyncSessionsWebContentsRouterFactory::GetInstance() + ->GetForProfile(profile_2) + ->StartRoutingTo(&handler_2); + + GURL gurl_1("http://foo1.com"); + AddTab(browser(), gurl_1); + + // Tab needs to have been active to be found when discarding. + BrowserList::GetInstance()->SetLastActive(browser()); + + EXPECT_EQ(gurl_1, *handler_1.seen_urls()->rbegin()); + SessionID::id_type old_id = *handler_1.seen_ids()->rbegin(); + + // Remove previous any observations from setup to make checking expectations + // easier below. + handler_1.seen_urls()->clear(); + handler_1.seen_ids()->clear(); + + g_browser_process->GetTabManager()->DiscardTabByExtension( + browser()->tab_strip_model()->GetWebContentsAt(0)); + + // We're typically notified twice while discarding tabs. Once for the + // destruction of the old web contents, and once for the new. This test case + // is really trying to make sure the TabReplacedAt() method is called, which + // is going to be invoked for the new web contents. We can tell it is the new + // one by finding |gurl_1| for an id that is not |old_id|. + bool found_new_id = false; + for (size_t i = 0; i < handler_1.seen_ids()->size(); ++i) { + if (handler_1.seen_ids()->at(i) != old_id && + handler_1.seen_urls()->at(i) == gurl_1) { + found_new_id = true; + break; + } + } + EXPECT_TRUE(found_new_id); + + // And of course |profile_2| shouldn't have seen anything. + EXPECT_EQ(0U, handler_2.seen_urls()->size()); + + // Cleanup needed for manually created browsers so they don't complain about + // having open tabs when destructing. + browser_2->tab_strip_model()->CloseAllTabs(); +} + } // namespace sync_sessions
diff --git a/chrome/browser/ui/ash/multi_user/multi_user_window_manager_chromeos_unittest.cc b/chrome/browser/ui/ash/multi_user/multi_user_window_manager_chromeos_unittest.cc index 983bf56..2452ef3 100644 --- a/chrome/browser/ui/ash/multi_user/multi_user_window_manager_chromeos_unittest.cc +++ b/chrome/browser/ui/ash/multi_user/multi_user_window_manager_chromeos_unittest.cc
@@ -31,6 +31,8 @@ #include "chrome/browser/chromeos/login/users/fake_chrome_user_manager.h" #include "chrome/browser/chromeos/login/users/wallpaper/wallpaper_manager.h" #include "chrome/browser/chromeos/profiles/profile_helper.h" +#include "chrome/browser/chromeos/settings/cros_settings.h" +#include "chrome/browser/chromeos/settings/device_settings_service.h" #include "chrome/browser/ui/ash/chrome_new_window_client.h" #include "chrome/browser/ui/ash/multi_user/multi_user_util.h" #include "chrome/browser/ui/ash/multi_user/multi_user_window_manager.h" @@ -308,6 +310,8 @@ }; void MultiUserWindowManagerChromeOSTest::SetUp() { + chromeos::DeviceSettingsService::Initialize(); + chromeos::CrosSettings::Initialize(); ash_test_helper()->set_test_shell_delegate(new TestShellDelegateChromeOS); ash::AshTestEnvironmentContent* test_environment = static_cast<ash::AshTestEnvironmentContent*>( @@ -354,6 +358,8 @@ chromeos::WallpaperManager::Shutdown(); wallpaper_controller_client_.reset(); profile_manager_.reset(); + chromeos::CrosSettings::Shutdown(); + chromeos::DeviceSettingsService::Shutdown(); } std::string MultiUserWindowManagerChromeOSTest::GetStatus() {
diff --git a/chrome/browser/ui/ash/test_wallpaper_controller.cc b/chrome/browser/ui/ash/test_wallpaper_controller.cc index 50a901c..018123a 100644 --- a/chrome/browser/ui/ash/test_wallpaper_controller.cc +++ b/chrome/browser/ui/ash/test_wallpaper_controller.cc
@@ -19,11 +19,12 @@ return ptr; } -void TestWallpaperController::SetClientAndPaths( +void TestWallpaperController::Init( ash::mojom::WallpaperControllerClientPtr client, const base::FilePath& user_data_path, const base::FilePath& chromeos_wallpapers_path, - const base::FilePath& chromeos_custom_wallpapers_path) { + const base::FilePath& chromeos_custom_wallpapers_path, + bool is_device_wallpaper_policy_enforced) { was_client_set_ = true; }
diff --git a/chrome/browser/ui/ash/test_wallpaper_controller.h b/chrome/browser/ui/ash/test_wallpaper_controller.h index 77bb6d2..5297f698 100644 --- a/chrome/browser/ui/ash/test_wallpaper_controller.h +++ b/chrome/browser/ui/ash/test_wallpaper_controller.h
@@ -32,11 +32,11 @@ ash::mojom::WallpaperControllerPtr CreateInterfacePtr(); // ash::mojom::WallpaperController: - void SetClientAndPaths( - ash::mojom::WallpaperControllerClientPtr client, - const base::FilePath& user_data_path, - const base::FilePath& chromeos_wallpapers_path, - const base::FilePath& chromeos_custom_wallpapers_path) override; + void Init(ash::mojom::WallpaperControllerClientPtr client, + const base::FilePath& user_data_path, + const base::FilePath& chromeos_wallpapers_path, + const base::FilePath& chromeos_custom_wallpapers_path, + bool is_device_wallpaper_policy_enforced) override; void SetCustomWallpaper(ash::mojom::WallpaperUserInfoPtr user_info, const std::string& wallpaper_files_id, const std::string& file_name,
diff --git a/chrome/browser/ui/ash/wallpaper_controller_client.cc b/chrome/browser/ui/ash/wallpaper_controller_client.cc index 713b68fe..34bf1ce 100644 --- a/chrome/browser/ui/ash/wallpaper_controller_client.cc +++ b/chrome/browser/ui/ash/wallpaper_controller_client.cc
@@ -86,7 +86,8 @@ } // namespace -WallpaperControllerClient::WallpaperControllerClient() : binding_(this) { +WallpaperControllerClient::WallpaperControllerClient() + : policy_handler_(this), binding_(this) { DCHECK(!g_instance); g_instance = this; } @@ -101,8 +102,6 @@ ->GetConnector() ->BindInterface(ash::mojom::kServiceName, &wallpaper_controller_); BindAndSetClient(); - // TODO(xdai): Get current device policy enforced flag from - // WallpaperPolicyHandler::IsDeviceWallpaperPolicyEnforced() and set here. } void WallpaperControllerClient::InitForTesting( @@ -257,7 +256,8 @@ ash::WallpaperController::dir_chrome_os_custom_wallpapers_path_ = chromeos_custom_wallpapers_path; - wallpaper_controller_->SetClientAndPaths(std::move(client), user_data_path, - chromeos_wallpapers_path, - chromeos_custom_wallpapers_path); + wallpaper_controller_->Init( + std::move(client), user_data_path, chromeos_wallpapers_path, + chromeos_custom_wallpapers_path, + policy_handler_.IsDeviceWallpaperPolicyEnforced()); }
diff --git a/chrome/browser/ui/ash/wallpaper_controller_client.h b/chrome/browser/ui/ash/wallpaper_controller_client.h index da17c0c..9c72ec48 100644 --- a/chrome/browser/ui/ash/wallpaper_controller_client.h +++ b/chrome/browser/ui/ash/wallpaper_controller_client.h
@@ -77,6 +77,8 @@ // WallpaperController interface in ash. ash::mojom::WallpaperControllerPtr wallpaper_controller_; + WallpaperPolicyHandler policy_handler_; + // Binds to the client interface. mojo::Binding<ash::mojom::WallpaperControllerClient> binding_;
diff --git a/chrome/browser/ui/ash/wallpaper_controller_client_unittest.cc b/chrome/browser/ui/ash/wallpaper_controller_client_unittest.cc index 4c990ae3..3145497 100644 --- a/chrome/browser/ui/ash/wallpaper_controller_client_unittest.cc +++ b/chrome/browser/ui/ash/wallpaper_controller_client_unittest.cc
@@ -5,6 +5,8 @@ #include "chrome/browser/ui/ash/wallpaper_controller_client.h" #include "base/test/scoped_task_environment.h" +#include "chrome/browser/chromeos/settings/cros_settings.h" +#include "chrome/browser/chromeos/settings/device_settings_service.h" #include "chrome/browser/ui/ash/test_wallpaper_controller.h" #include "testing/gtest/include/gtest/gtest.h" @@ -15,6 +17,12 @@ WallpaperControllerClientTest() = default; ~WallpaperControllerClientTest() override = default; + void SetUp() override { + testing::Test::SetUp(); + chromeos::DeviceSettingsService::Initialize(); + chromeos::CrosSettings::Initialize(); + } + private: base::test::ScopedTaskEnvironment scoped_task_environment_; @@ -34,4 +42,4 @@ EXPECT_TRUE(controller.was_client_set()); } -} // namespace \ No newline at end of file +} // namespace
diff --git a/chrome/browser/ui/cocoa/bookmarks/bookmark_button_cell.mm b/chrome/browser/ui/cocoa/bookmarks/bookmark_button_cell.mm index b91622f..d4e75f9 100644 --- a/chrome/browser/ui/cocoa/bookmarks/bookmark_button_cell.mm +++ b/chrome/browser/ui/cocoa/bookmarks/bookmark_button_cell.mm
@@ -88,6 +88,11 @@ @synthesize startingChildIndex = startingChildIndex_; @synthesize drawFolderArrow = drawFolderArrow_; +// Overridden from GradientButtonCell. ++ (CGFloat)insetInView:(NSView*)view { + return 0; +} + + (id)buttonCellForNode:(const BookmarkNode*)node text:(NSString*)text image:(NSImage*)image
diff --git a/chrome/browser/ui/cocoa/framed_browser_window.mm b/chrome/browser/ui/cocoa/framed_browser_window.mm index 7b18d090..ac46eae5 100644 --- a/chrome/browser/ui/cocoa/framed_browser_window.mm +++ b/chrome/browser/ui/cocoa/framed_browser_window.mm
@@ -34,8 +34,7 @@ @implementation FramedBrowserWindow + (CGFloat)browserFrameViewPaintHeight { - return chrome::ShouldUseFullSizeContentView() ? chrome::kTabStripHeight - : 60.0; + return chrome::kTabStripHeight; } + (NSUInteger)defaultStyleMask {
diff --git a/chrome/browser/ui/cocoa/tabs/tab_window_controller.mm b/chrome/browser/ui/cocoa/tabs/tab_window_controller.mm index 0d8474f3..8be82134 100644 --- a/chrome/browser/ui/cocoa/tabs/tab_window_controller.mm +++ b/chrome/browser/ui/cocoa/tabs/tab_window_controller.mm
@@ -134,24 +134,21 @@ if (hasTabStrip) [windowView addSubview:tabStripView_]; - if (chrome::ShouldUseFullSizeContentView()) { - // |windowWillEnterFullScreen:| and |windowWillExitFullScreen:| are - // already called because self is a delegate for the window. However this - // class is designed for subclassing and can not implement - // NSWindowDelegate methods (because subclasses can do so as well and they - // should be able to). TODO(crbug.com/654656): Move |visualEffectView_| to - // subclass. - [[NSNotificationCenter defaultCenter] - addObserver:self - selector:@selector(windowWillEnterFullScreenNotification:) - name:NSWindowWillEnterFullScreenNotification - object:window]; - [[NSNotificationCenter defaultCenter] - addObserver:self - selector:@selector(windowWillExitFullScreenNotification:) - name:NSWindowWillExitFullScreenNotification - object:window]; - } + // |windowWillEnterFullScreen:| and |windowWillExitFullScreen:| are already + // called because self is a delegate for the window. However this class is + // designed for subclassing and can not implement NSWindowDelegate methods + // (because subclasses can do so as well and they should be able to). + // TODO(crbug.com/654656): Move |visualEffectView_| to subclass. + [[NSNotificationCenter defaultCenter] + addObserver:self + selector:@selector(windowWillEnterFullScreenNotification:) + name:NSWindowWillEnterFullScreenNotification + object:window]; + [[NSNotificationCenter defaultCenter] + addObserver:self + selector:@selector(windowWillExitFullScreenNotification:) + name:NSWindowWillExitFullScreenNotification + object:window]; } return self; } @@ -460,18 +457,14 @@ [visualEffectWrapperView addSubview:visualEffectView_]; - [[window contentView] addSubview:visualEffectWrapperView - positioned:NSWindowBelow - relativeTo:nil]; + [[window contentView] addSubview:visualEffectWrapperView]; // Make the |tabStripBackgroundView_| a child of the NSVisualEffectView. [tabStripBackgroundView_ setFrame:[visualEffectView_ bounds]]; [visualEffectView_ addSubview:tabStripBackgroundView_]; } else { DCHECK(!chrome::ShouldUseFullSizeContentView()); - [[window contentView] addSubview:tabStripBackgroundView_ - positioned:NSWindowBelow - relativeTo:nil]; + [[window contentView] addSubview:tabStripBackgroundView_]; } } @@ -482,11 +475,13 @@ } - (void)windowWillEnterFullScreenNotification:(NSNotification*)notification { - [[visualEffectView_ animator] setAlphaValue:0.0]; + [(visualEffectView_ ? visualEffectView_.get() + : tabStripBackgroundView_.get()) setHidden:YES]; } - (void)windowWillExitFullScreenNotification:(NSNotification*)notification { - [[visualEffectView_ animator] setAlphaValue:1.0]; + [(visualEffectView_ ? visualEffectView_.get() + : tabStripBackgroundView_.get()) setHidden:NO]; } @end
diff --git a/chrome/browser/ui/tabs/tab_utils.cc b/chrome/browser/ui/tabs/tab_utils.cc index b0bd2e8..616f0324 100644 --- a/chrome/browser/ui/tabs/tab_utils.cc +++ b/chrome/browser/ui/tabs/tab_utils.cc
@@ -452,6 +452,13 @@ bool IsSiteMuted(const TabStripModel& tab_strip, const int index) { content::WebContents* web_contents = tab_strip.GetWebContentsAt(index); + + // TODO(steimel): Why was this not a problem for AreAllTabsMuted? Is this + // going to be a problem for SetSitesMuted? + // Prevent crashes with null WebContents (https://crbug.com/797647). + if (!web_contents) + return false; + GURL url = web_contents->GetLastCommittedURL(); // chrome:// URLs don't have content settings but can be muted, so just check
diff --git a/chrome/browser/ui/views/omnibox/omnibox_result_view.cc b/chrome/browser/ui/views/omnibox/omnibox_result_view.cc index a1314ec..fee3a45 100644 --- a/chrome/browser/ui/views/omnibox/omnibox_result_view.cc +++ b/chrome/browser/ui/views/omnibox/omnibox_result_view.cc
@@ -455,7 +455,7 @@ // Regular results. if (base::FeatureList::IsEnabled(omnibox::kUIExperimentVerticalLayout)) { - // For no description, shift down halfways to draw contents in middle. + // For no description, shift down halfway to draw contents in middle. if (description_max_width == 0) y += GetTextHeight() / 2;
diff --git a/chrome/browser/ui/views/omnibox/omnibox_view_views_browsertest.cc b/chrome/browser/ui/views/omnibox/omnibox_view_views_browsertest.cc index 24f1056..3f1b10c 100644 --- a/chrome/browser/ui/views/omnibox/omnibox_view_views_browsertest.cc +++ b/chrome/browser/ui/views/omnibox/omnibox_view_views_browsertest.cc
@@ -432,7 +432,7 @@ // Execute a command and check if it deactivate touch editing. Paste & Go is // chosen since it is specific to Omnibox and its execution wouldn't be - // delgated to the base Textfield class. + // delegated to the base Textfield class. omnibox_view_views->ExecuteCommand(IDS_PASTE_AND_GO, ui::EF_NONE); EXPECT_FALSE(textfield_test_api.touch_selection_controller()); }
diff --git a/chrome/browser/ui/views/payments/cvc_unmask_view_controller.cc b/chrome/browser/ui/views/payments/cvc_unmask_view_controller.cc index 148f3d0..60feffe 100644 --- a/chrome/browser/ui/views/payments/cvc_unmask_view_controller.cc +++ b/chrome/browser/ui/views/payments/cvc_unmask_view_controller.cc
@@ -286,6 +286,9 @@ void CvcUnmaskViewController::ButtonPressed(views::Button* sender, const ui::Event& event) { + if (!dialog()->IsInteractive()) + return; + switch (sender->tag()) { case static_cast<int>(Tags::CONFIRM_TAG): CvcConfirmed(); @@ -396,6 +399,9 @@ } void CvcUnmaskViewController::OnPerformAction(views::Combobox* combobox) { + if (!dialog()->IsInteractive()) + return; + UpdatePayButtonState(); }
diff --git a/chrome/browser/ui/views/payments/payment_method_view_controller.cc b/chrome/browser/ui/views/payments/payment_method_view_controller.cc index d8aa1c7..c5cc5ae 100644 --- a/chrome/browser/ui/views/payments/payment_method_view_controller.cc +++ b/chrome/browser/ui/views/payments/payment_method_view_controller.cc
@@ -229,6 +229,9 @@ std::unique_ptr<views::View> PaymentMethodViewController::CreateExtraFooterView() { + if (!spec()->supports_basic_card()) + return nullptr; + auto extra_view = base::MakeUnique<views::View>(); extra_view->SetLayoutManager(std::make_unique<views::BoxLayout>(
diff --git a/chrome/browser/ui/views/payments/payment_request_dialog_view.cc b/chrome/browser/ui/views/payments/payment_request_dialog_view.cc index a68b20e..58d79e0 100644 --- a/chrome/browser/ui/views/payments/payment_request_dialog_view.cc +++ b/chrome/browser/ui/views/payments/payment_request_dialog_view.cc
@@ -166,6 +166,10 @@ observer_for_testing_->OnProcessingSpinnerShown(); } +bool PaymentRequestDialogView::IsInteractive() const { + return !throbber_overlay_.visible(); +} + void PaymentRequestDialogView::OnStartUpdating( PaymentRequestSpec::UpdateReason reason) { ShowProcessingSpinner();
diff --git a/chrome/browser/ui/views/payments/payment_request_dialog_view.h b/chrome/browser/ui/views/payments/payment_request_dialog_view.h index 74983c7..2c1d074 100644 --- a/chrome/browser/ui/views/payments/payment_request_dialog_view.h +++ b/chrome/browser/ui/views/payments/payment_request_dialog_view.h
@@ -109,6 +109,7 @@ void CloseDialog() override; void ShowErrorMessage() override; void ShowProcessingSpinner() override; + bool IsInteractive() const override; // PaymentRequestSpec::Observer: void OnStartUpdating(PaymentRequestSpec::UpdateReason reason) override;
diff --git a/chrome/browser/ui/views/payments/payment_request_sheet_controller.cc b/chrome/browser/ui/views/payments/payment_request_sheet_controller.cc index a609b34..af826ced 100644 --- a/chrome/browser/ui/views/payments/payment_request_sheet_controller.cc +++ b/chrome/browser/ui/views/payments/payment_request_sheet_controller.cc
@@ -321,6 +321,9 @@ void PaymentRequestSheetController::ButtonPressed(views::Button* sender, const ui::Event& event) { + if (!dialog()->IsInteractive()) + return; + switch (static_cast<PaymentRequestCommonTags>(sender->tag())) { case PaymentRequestCommonTags::CLOSE_BUTTON_TAG: dialog()->CloseDialog(); @@ -349,11 +352,11 @@ std::make_unique<views::GridLayout>(container.get())); views::ColumnSet* columns = layout->AddColumnSet(0); - columns->AddColumn(views::GridLayout::LEADING, views::GridLayout::CENTER, - 0, views::GridLayout::USE_PREF, 0, 0); + columns->AddColumn(views::GridLayout::LEADING, views::GridLayout::CENTER, 0, + views::GridLayout::USE_PREF, 0, 0); columns->AddPaddingColumn(1, 0); - columns->AddColumn(views::GridLayout::TRAILING, views::GridLayout::CENTER, - 0, views::GridLayout::USE_PREF, 0, 0); + columns->AddColumn(views::GridLayout::TRAILING, views::GridLayout::CENTER, 0, + views::GridLayout::USE_PREF, 0, 0); layout->StartRow(0, 0); std::unique_ptr<views::View> extra_view = CreateExtraFooterView(); @@ -397,6 +400,10 @@ } bool PaymentRequestSheetController::PerformPrimaryButtonAction() { + // Return "true" to prevent other views from handling the event. + if (!dialog()->IsInteractive()) + return true; + if (primary_button_ && primary_button_->enabled()) ButtonPressed(primary_button_.get(), DummyEvent()); return true;
diff --git a/chrome/browser/ui/views/payments/payment_sheet_view_controller.cc b/chrome/browser/ui/views/payments/payment_sheet_view_controller.cc index 89d198c..51a23fe 100644 --- a/chrome/browser/ui/views/payments/payment_sheet_view_controller.cc +++ b/chrome/browser/ui/views/payments/payment_sheet_view_controller.cc
@@ -474,6 +474,9 @@ void PaymentSheetViewController::ButtonPressed(views::Button* sender, const ui::Event& event) { + if (!dialog()->IsInteractive()) + return; + switch (sender->tag()) { case static_cast<int>( PaymentSheetViewControllerTags::SHOW_ORDER_SUMMARY_BUTTON): @@ -542,6 +545,9 @@ views::StyledLabel* label, const gfx::Range& range, int event_flags) { + if (!dialog()->IsInteractive()) + return; + // The only thing that can trigger this is the user clicking on the "settings" // link in the data attribution text. chrome::ShowSettingsSubPageForProfile(dialog()->GetProfile(),
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 492913c..aaca6cae 100644 --- a/chrome/browser/ui/webui/chromeos/login/enrollment_screen_handler.cc +++ b/chrome/browser/ui/webui/chromeos/login/enrollment_screen_handler.cc
@@ -707,13 +707,16 @@ login::SigninPartitionManager* signin_partition_manager = login::SigninPartitionManager::Factory::GetForBrowserContext( Profile::FromWebUI(web_ui())); - signin_partition_manager->StartSigninSession(web_ui()->GetWebContents()); + signin_partition_manager->StartSigninSession( + web_ui()->GetWebContents(), + base::BindOnce(&EnrollmentScreenHandler::DoShowWithPartition, + weak_ptr_factory_.GetWeakPtr())); +} - // Then leave it running forever. +void EnrollmentScreenHandler::DoShowWithPartition( + const std::string& partition_name) { base::DictionaryValue screen_data; - screen_data.SetString( - "webviewPartitionName", - signin_partition_manager->GetCurrentStoragePartitionName()); + screen_data.SetString("webviewPartitionName", partition_name); screen_data.SetString("gaiaUrl", GaiaUrls::GetInstance()->gaia_url().spec()); screen_data.SetString("clientId", GaiaUrls::GetInstance()->oauth2_chrome_client_id());
diff --git a/chrome/browser/ui/webui/chromeos/login/enrollment_screen_handler.h b/chrome/browser/ui/webui/chromeos/login/enrollment_screen_handler.h index 23b7d798..e97c73e 100644 --- a/chrome/browser/ui/webui/chromeos/login/enrollment_screen_handler.h +++ b/chrome/browser/ui/webui/chromeos/login/enrollment_screen_handler.h
@@ -118,6 +118,9 @@ // Shows the screen. void DoShow(); + // Shows the screen. + void DoShowWithPartition(const std::string& partition_name); + // Returns true if current visible screen is the enrollment sign-in page. bool IsOnEnrollmentScreen() const;
diff --git a/chrome/browser/ui/webui/chromeos/login/gaia_screen_handler.cc b/chrome/browser/ui/webui/chromeos/login/gaia_screen_handler.cc index a27ea28..f9d8266 100644 --- a/chrome/browser/ui/webui/chromeos/login/gaia_screen_handler.cc +++ b/chrome/browser/ui/webui/chromeos/login/gaia_screen_handler.cc
@@ -300,31 +300,39 @@ } void GaiaScreenHandler::LoadGaia(const GaiaContext& context) { + // Start a new session with SigninPartitionManager, generating a unique + // StoragePartition. + login::SigninPartitionManager* signin_partition_manager = + login::SigninPartitionManager::Factory::GetForBrowserContext( + Profile::FromWebUI(web_ui())); + signin_partition_manager->StartSigninSession( + web_ui()->GetWebContents(), + base::BindOnce(&GaiaScreenHandler::LoadGaiaWithPartition, + weak_factory_.GetWeakPtr(), context)); +} + +void GaiaScreenHandler::LoadGaiaWithPartition( + const GaiaContext& context, + const std::string& partition_name) { std::unique_ptr<std::string> version = std::make_unique<std::string>(); std::unique_ptr<bool> consent = std::make_unique<bool>(); base::OnceClosure get_version_and_consent = base::BindOnce(&GetVersionAndConsent, base::Unretained(version.get()), base::Unretained(consent.get())); base::OnceClosure load_gaia = base::BindOnce( - &GaiaScreenHandler::LoadGaiaWithVersionAndConsent, - weak_factory_.GetWeakPtr(), context, base::Owned(version.release()), - base::Owned(consent.release())); + &GaiaScreenHandler::LoadGaiaWithPartitionAndVersionAndConsent, + weak_factory_.GetWeakPtr(), context, partition_name, + base::Owned(version.release()), base::Owned(consent.release())); base::PostTaskWithTraitsAndReply( FROM_HERE, {base::MayBlock(), base::TaskPriority::USER_VISIBLE}, std::move(get_version_and_consent), std::move(load_gaia)); } -void GaiaScreenHandler::LoadGaiaWithVersionAndConsent( +void GaiaScreenHandler::LoadGaiaWithPartitionAndVersionAndConsent( const GaiaContext& context, + const std::string& partition_name, const std::string* platform_version, const bool* collect_stats_consent) { - // Start a new session with SigninPartitionManager, generating a a unique - // StoragePartition. - login::SigninPartitionManager* signin_partition_manager = - login::SigninPartitionManager::Factory::GetForBrowserContext( - Profile::FromWebUI(web_ui())); - signin_partition_manager->StartSigninSession(web_ui()->GetWebContents()); - base::DictionaryValue params; params.SetBoolean("forceReload", context.force_reload); @@ -400,8 +408,8 @@ // sending device statistics. if (*collect_stats_consent) params.SetString("lsbReleaseBoard", base::SysInfo::GetLsbReleaseBoard()); - params.SetString("webviewPartitionName", - signin_partition_manager->GetCurrentStoragePartitionName()); + + params.SetString("webviewPartitionName", partition_name); frame_state_ = FRAME_STATE_LOADING; CallJS("loadAuthExtension", params);
diff --git a/chrome/browser/ui/webui/chromeos/login/gaia_screen_handler.h b/chrome/browser/ui/webui/chromeos/login/gaia_screen_handler.h index 7e91022e..749c2de03 100644 --- a/chrome/browser/ui/webui/chromeos/login/gaia_screen_handler.h +++ b/chrome/browser/ui/webui/chromeos/login/gaia_screen_handler.h
@@ -64,9 +64,16 @@ // Callback that loads GAIA after version and stat consent information has // been retrieved. - void LoadGaiaWithVersionAndConsent(const GaiaContext& context, - const std::string* platform_version, - const bool* collect_stats_consent); + void LoadGaiaWithPartition(const GaiaContext& context, + const std::string& partition_name); + + // Callback that loads GAIA after version and stat consent information has + // been retrieved. + void LoadGaiaWithPartitionAndVersionAndConsent( + const GaiaContext& context, + const std::string& partition_name, + const std::string* platform_version, + const bool* collect_stats_consent); // Sends request to reload Gaia. If |force_reload| is true, request // will be sent in any case, otherwise it will be sent only when Gaia is
diff --git a/chrome/browser/ui/webui/chromeos/login/signin_screen_handler.cc b/chrome/browser/ui/webui/chromeos/login/signin_screen_handler.cc index af4dfdc..4f2118f 100644 --- a/chrome/browser/ui/webui/chromeos/login/signin_screen_handler.cc +++ b/chrome/browser/ui/webui/chromeos/login/signin_screen_handler.cc
@@ -685,7 +685,8 @@ // Skip "update" notification about OFFLINE state from // NetworkStateInformer if previous notification already was // delayed. - if ((state == NetworkStateInformer::OFFLINE || has_pending_auth_ui_) && + if ((state == NetworkStateInformer::OFFLINE || + network_state_ignored_until_proxy_auth_) && !force_update && !update_state_closure_.IsCancelled()) { return; } @@ -693,7 +694,7 @@ update_state_closure_.Cancel(); if ((state == NetworkStateInformer::OFFLINE && !force_update) || - has_pending_auth_ui_) { + network_state_ignored_until_proxy_auth_) { update_state_closure_.Reset( base::Bind(&SigninScreenHandler::UpdateStateInternal, weak_factory_.GetWeakPtr(), @@ -789,7 +790,6 @@ if (is_gaia_loading_timeout) { LOG(WARNING) << "Retry frame load due to loading timeout."; - LOG(ERROR) << "UpdateStateInternal reload 4"; reload_gaia.ScheduleCall(); } @@ -1082,20 +1082,33 @@ const content::NotificationDetails& details) { switch (type) { case chrome::NOTIFICATION_AUTH_NEEDED: { - has_pending_auth_ui_ = true; + network_state_ignored_until_proxy_auth_ = true; break; } - case chrome::NOTIFICATION_AUTH_SUPPLIED: - has_pending_auth_ui_ = false; - // Reload auth extension as proxy credentials are supplied. - if (!IsSigninScreenHiddenByError() && ui_state_ == UI_STATE_GAIA_SIGNIN) - ReloadGaia(true); - update_state_closure_.Cancel(); + case chrome::NOTIFICATION_AUTH_SUPPLIED: { + if (IsGaiaHiddenByError()) { + // Start listening to network state notifications immediately, hoping + // that the network will switch to ONLINE soon. + update_state_closure_.Cancel(); + ReenableNetworkStateUpdatesAfterProxyAuth(); + } else { + // Gaia is not hidden behind an error yet. Discard last cached network + // state notification and wait for |kOfflineTimeoutSec| before + // considering network update notifications again (hoping the network + // will become ONLINE by then). + update_state_closure_.Cancel(); + base::ThreadTaskRunnerHandle::Get()->PostDelayedTask( + FROM_HERE, + base::BindOnce( + &SigninScreenHandler::ReenableNetworkStateUpdatesAfterProxyAuth, + weak_factory_.GetWeakPtr()), + base::TimeDelta::FromSeconds(kOfflineTimeoutSec)); + } break; + } case chrome::NOTIFICATION_AUTH_CANCELLED: { - // Don't reload auth extension if proxy auth dialog was cancelled. - has_pending_auth_ui_ = false; update_state_closure_.Cancel(); + ReenableNetworkStateUpdatesAfterProxyAuth(); break; } default: @@ -1103,6 +1116,10 @@ } } +void SigninScreenHandler::ReenableNetworkStateUpdatesAfterProxyAuth() { + network_state_ignored_until_proxy_auth_ = false; +} + void SigninScreenHandler::SuspendDone(const base::TimeDelta& sleep_duration) { for (user_manager::User* user : user_manager::UserManager::Get()->GetUnlockUsers()) {
diff --git a/chrome/browser/ui/webui/chromeos/login/signin_screen_handler.h b/chrome/browser/ui/webui/chromeos/login/signin_screen_handler.h index 680ab51..d63b0652f 100644 --- a/chrome/browser/ui/webui/chromeos/login/signin_screen_handler.h +++ b/chrome/browser/ui/webui/chromeos/login/signin_screen_handler.h
@@ -483,6 +483,10 @@ // Called when the cros property controlling allowed input methods changes. void OnAllowedInputMethodsChanged(); + // After proxy auth information has been supplied, this function re-enables + // responding to network state notifications. + void ReenableNetworkStateUpdatesAfterProxyAuth(); + // Current UI state of the signin screen. UIState ui_state_ = UI_STATE_UNKNOWN; @@ -522,10 +526,10 @@ std::unique_ptr<CrosSettings::ObserverSubscription> allowed_input_methods_subscription_; - // Whether there is an auth UI pending. This flag is set on receiving - // NOTIFICATION_AUTH_NEEDED and reset on either NOTIFICATION_AUTH_SUPPLIED or - // NOTIFICATION_AUTH_CANCELLED. - bool has_pending_auth_ui_ = false; + // Whether we're currently ignoring network state updates because a proxy auth + // UI pending (or we're waiting for a grace period after the proxy auth UI is + // finished for the network to switch into the ONLINE state). + bool network_state_ignored_until_proxy_auth_ = false; // Used for pending GAIA reloads. NetworkError::ErrorReason gaia_reload_reason_ =
diff --git a/chrome/browser/ui/webui/chromeos/login/signin_userlist_unittest.cc b/chrome/browser/ui/webui/chromeos/login/signin_userlist_unittest.cc index 7a3af9af..f80653a 100644 --- a/chrome/browser/ui/webui/chromeos/login/signin_userlist_unittest.cc +++ b/chrome/browser/ui/webui/chromeos/login/signin_userlist_unittest.cc
@@ -13,6 +13,8 @@ #include "chrome/browser/chromeos/login/users/multi_profile_user_controller.h" #include "chrome/browser/chromeos/login/users/multi_profile_user_controller_delegate.h" #include "chrome/browser/chromeos/login/users/wallpaper/wallpaper_manager.h" +#include "chrome/browser/chromeos/settings/cros_settings.h" +#include "chrome/browser/chromeos/settings/device_settings_service.h" #include "chrome/browser/ui/ash/test_wallpaper_controller.h" #include "chrome/browser/ui/ash/wallpaper_controller_client.h" #include "chrome/test/base/testing_browser_process.h" @@ -67,6 +69,8 @@ fake_user_manager_->set_owner_id(AccountId::FromUserEmail(kOwner)); chromeos::WallpaperManager::Initialize(); + chromeos::DeviceSettingsService::Initialize(); + chromeos::CrosSettings::Initialize(); wallpaper_controller_client_ = std::make_unique<WallpaperControllerClient>(); wallpaper_controller_client_->InitForTesting(
diff --git a/chrome/browser/vr/test/vr_browser_tests.md b/chrome/browser/vr/test/vr_browser_tests.md new file mode 100644 index 0000000..9f4d1d7 --- /dev/null +++ b/chrome/browser/vr/test/vr_browser_tests.md
@@ -0,0 +1,42 @@ +# VR Browser Tests + +## Introduction + +This documentation concerns `vr_browser_test.h`, `vr_browser_test.cc`, and files +that use them. + +These files port the framework used by VR instrumentation tests (located in +`//chrome/android/javatests/src/org/chromium/chrome/browser/vr_shell/` and +documented in +`//chrome/android/javatests/src/org/chromium/chrome/browser/vr_shell/*.md`) for +use in browser tests in order to test VR features on desktop platforms. + +This is pretty much a direct port, with the same JavaScript/HTML files being +used for both and the Java/C++ code being functionally equivalent to each other, +so the instrumentation test's documentation on writing tests using the framework +is applicable here, too. As such, this documentation covers any notable +differences between the two implementations. + +## Restrictions + +Both the instrumentation tests and browser tests have hardware/software +restrictions - in the case of browser tests, VR is only supported on Windows 8 +and later (or Windows 7 with a non-standard patch applied) with a GPU that +supports DirectX 11.1. + +Instrumentation tests handle restrictions with the `@Restriction` annotation, +but browser tests don't have any equivalent functionality. Instead, test names +should be wrapped in the REQUIRES_GPU macro defined in `vr_browser_test.h`, +which simply disables the test by default. We then explicitly run tests that +inherit from `VrBrowserTest` and enable the running of disabled tests on bots +that meet the requirements. + +## Command Line Switches + +Instrumentation tests are able to add and remove command line switches on a +per-test-case basis using `@CommandLine` annotations, but equivalent +functionality does not exist in browser tests. + +Instead, if different command line flags are needed, a new class will need to +be created that extends `VrBrowserTest` and overrides the flags that are set +in its `SetUp` function. \ No newline at end of file
diff --git a/chrome/browser/vr/testapp/vr_test_context.cc b/chrome/browser/vr/testapp/vr_test_context.cc index f4a7006..aa720a71 100644 --- a/chrome/browser/vr/testapp/vr_test_context.cc +++ b/chrome/browser/vr/testapp/vr_test_context.cc
@@ -87,10 +87,7 @@ model_ = ui_->model_for_test(); - ToolbarState state(GURL("https://dangerous.com/dir/file.html"), - security_state::SecurityLevel::HTTP_SHOW_WARNING, - &toolbar::kHttpIcon, base::string16(), true, false); - ui_->SetToolbarState(state); + CycleOrigin(); ui_->SetHistoryButtonsEnabled(true, true); ui_->SetLoading(true); ui_->SetLoadProgress(0.4); @@ -180,6 +177,9 @@ case ui::DomCode::US_E: model_->exiting_vr = !model_->exiting_vr; break; + case ui::DomCode::US_O: + CycleOrigin(); + break; default: break; } @@ -471,4 +471,28 @@ ui_->SetOmniboxSuggestions(base::MakeUnique<OmniboxSuggestions>()); } +void VrTestContext::CycleOrigin() { + const std::vector<ToolbarState> states = { + {GURL("http://www.domain.com/path/segment/directory/file.html"), + security_state::SecurityLevel::HTTP_SHOW_WARNING, &toolbar::kHttpIcon, + base::string16(), true, false}, + {GURL("http://www.domain.com/"), + security_state::SecurityLevel::HTTP_SHOW_WARNING, &toolbar::kHttpIcon, + base::string16(), true, false}, + {GURL("https://www.domain.com/path/segment/directory/file.html"), + security_state::SecurityLevel::SECURE, &toolbar::kHttpsValidIcon, + base::UTF8ToUTF16("Secure"), true, false}, + {GURL("https://www.domain.com/path/segment/directory/file.html"), + security_state::SecurityLevel::DANGEROUS, &toolbar::kHttpsValidIcon, + base::UTF8ToUTF16("Dangerous"), true, false}, + {GURL("https://www.domain.com/path/segment/directory/file.html"), + security_state::SecurityLevel::HTTP_SHOW_WARNING, + &toolbar::kOfflinePinIcon, base::UTF8ToUTF16("Offline"), true, true}, + }; + + static int state = 0; + ui_->SetToolbarState(states[state]); + state = (state + 1) % states.size(); +} + } // namespace vr
diff --git a/chrome/browser/vr/testapp/vr_test_context.h b/chrome/browser/vr/testapp/vr_test_context.h index daf3040..b6fd1d11 100644 --- a/chrome/browser/vr/testapp/vr_test_context.h +++ b/chrome/browser/vr/testapp/vr_test_context.h
@@ -61,6 +61,7 @@ void CreateFakeTextInputOrCommit(bool commit); void CycleWebVrModes(); void ToggleSplashScreen(); + void CycleOrigin(); gfx::Transform ProjectionMatrix() const; gfx::Transform ViewProjectionMatrix() const; ControllerModel UpdateController();
diff --git a/chrome/common/chrome_utility_printing_messages.h b/chrome/common/chrome_utility_printing_messages.h index cb60927..33e3a1b 100644 --- a/chrome/common/chrome_utility_printing_messages.h +++ b/chrome/common/chrome_utility_printing_messages.h
@@ -9,7 +9,6 @@ #include <vector> #include "base/strings/string16.h" -#include "build/build_config.h" #include "components/printing/common/printing_param_traits_macros.h" #include "ipc/ipc_message_macros.h" #include "ipc/ipc_param_traits.h" @@ -17,28 +16,11 @@ #include "printing/backend/print_backend.h" #include "printing/features/features.h" #include "printing/page_range.h" -#include "printing/pdf_render_settings.h" -#include "printing/pwg_raster_settings.h" - -#if defined(OS_WIN) -#include <windows.h> -#endif #define IPC_MESSAGE_START ChromeUtilityPrintingMsgStart -// Preview and Cloud Print messages. #if BUILDFLAG(ENABLE_PRINT_PREVIEW) -IPC_ENUM_TRAITS_MAX_VALUE(printing::PdfRenderSettings::Mode, - printing::PdfRenderSettings::Mode::LAST) - -IPC_STRUCT_TRAITS_BEGIN(printing::PdfRenderSettings) - IPC_STRUCT_TRAITS_MEMBER(area) - IPC_STRUCT_TRAITS_MEMBER(offsets) - IPC_STRUCT_TRAITS_MEMBER(dpi) - IPC_STRUCT_TRAITS_MEMBER(autorotate) - IPC_STRUCT_TRAITS_MEMBER(mode) -IPC_STRUCT_TRAITS_END() - +// Preview and Cloud Print messages. IPC_STRUCT_TRAITS_BEGIN(printing::PrinterCapsAndDefaults) IPC_STRUCT_TRAITS_MEMBER(printer_capabilities) IPC_STRUCT_TRAITS_MEMBER(caps_mime_type) @@ -87,32 +69,11 @@ // sandbox. Returns result as printing::PrinterSemanticCapsAndDefaults. IPC_MESSAGE_CONTROL1(ChromeUtilityMsg_GetPrinterSemanticCapsAndDefaults, std::string /* printer name */) -#endif // ENABLE_PRINT_PREVIEW - -// Windows uses messages for printing even without preview. crbug.com/170859 -// Primary user of Windows without preview is CEF. crbug.com/417967 -#if BUILDFLAG(ENABLE_PRINTING) && defined(OS_WIN) -// Tell the utility process to start rendering the given PDF into a metafile. -// Utility process would be alive until -// ChromeUtilityMsg_RenderPDFPagesToMetafiles_Stop message. -IPC_MESSAGE_CONTROL2(ChromeUtilityMsg_RenderPDFPagesToMetafiles, - IPC::PlatformFileForTransit /* input_file */, - printing::PdfRenderSettings /* settings */) - -// Requests conversion of the next page. -IPC_MESSAGE_CONTROL2(ChromeUtilityMsg_RenderPDFPagesToMetafiles_GetPage, - int /* page_number */, - IPC::PlatformFileForTransit /* output_file */) - -// Requests utility process to stop conversion and exit. -IPC_MESSAGE_CONTROL0(ChromeUtilityMsg_RenderPDFPagesToMetafiles_Stop) -#endif // BUILDFLAG(ENABLE_PRINTING) && defined(OS_WIN) //------------------------------------------------------------------------------ // Utility process host messages: // These are messages from the utility process to the browser. -#if BUILDFLAG(ENABLE_PRINT_PREVIEW) // Reply when the utility process has succeeded in obtaining the printer // capabilities and defaults. IPC_MESSAGE_CONTROL2(ChromeUtilityHostMsg_GetPrinterCapsAndDefaults_Succeeded, @@ -136,26 +97,6 @@ IPC_MESSAGE_CONTROL1( ChromeUtilityHostMsg_GetPrinterSemanticCapsAndDefaults_Failed, std::string /* printer name */) -#endif // ENABLE_PRINT_PREVIEW - -#if BUILDFLAG(ENABLE_PRINTING) && defined(OS_WIN) -// Reply when the utility process loaded PDF. |page_count| is 0, if loading -// failed. -IPC_MESSAGE_CONTROL1(ChromeUtilityHostMsg_RenderPDFPagesToMetafiles_PageCount, - int /* page_count */) - -// Reply when the utility process rendered the PDF page. -IPC_MESSAGE_CONTROL2(ChromeUtilityHostMsg_RenderPDFPagesToMetafiles_PageDone, - bool /* success */, - float /* scale_factor */) - -// Request that the given font characters be loaded by the browser so it's -// cached by the OS. Please see -// PdfToEmfUtilityProcessHostClient::OnPreCacheFontCharacters for details. -IPC_SYNC_MESSAGE_CONTROL2_0(ChromeUtilityHostMsg_PreCacheFontCharacters, - LOGFONT /* font_data */, - base::string16 /* characters */) - -#endif // ENABLE_PRINTING && OS_WIN +#endif // BUILDFLAG(ENABLE_PRINT_PREVIEW) #endif // CHROME_COMMON_CHROME_UTILITY_PRINTING_MESSAGES_H_
diff --git a/chrome/service/BUILD.gn b/chrome/service/BUILD.gn index 386f4e2..f4dcb26 100644 --- a/chrome/service/BUILD.gn +++ b/chrome/service/BUILD.gn
@@ -57,6 +57,7 @@ "//base", "//chrome:strings", "//chrome/common", + "//chrome/services/printing/public/interfaces", "//components/cloud_devices/common", "//components/data_use_measurement/core", "//components/network_session_configurator/browser",
diff --git a/chrome/service/DEPS b/chrome/service/DEPS index 8052f77..4618fc5 100644 --- a/chrome/service/DEPS +++ b/chrome/service/DEPS
@@ -1,5 +1,6 @@ include_rules = [ "+chrome/grit", + "+chrome/services/printing/public", "+components/data_use_measurement/core", "+components/network_session_configurator/common", "+components/prefs",
diff --git a/chrome/service/service_utility_process_host.cc b/chrome/service/service_utility_process_host.cc index e991854..4359bb5 100644 --- a/chrome/service/service_utility_process_host.cc +++ b/chrome/service/service_utility_process_host.cc
@@ -27,6 +27,7 @@ #include "base/win/win_util.h" #include "chrome/common/chrome_switches.h" #include "chrome/common/chrome_utility_printing_messages.h" +#include "chrome/services/printing/public/interfaces/pdf_to_emf_converter.mojom.h" #include "content/public/common/child_process_host.h" #include "content/public/common/content_switches.h" #include "content/public/common/mojo_channel_switches.h" @@ -38,6 +39,8 @@ #include "mojo/edk/embedder/named_platform_channel_pair.h" #include "mojo/edk/embedder/platform_channel_pair.h" #include "mojo/edk/embedder/scoped_platform_handle.h" +#include "mojo/public/cpp/bindings/binding.h" +#include "mojo/public/cpp/system/platform_handle.h" #include "printing/emf_win.h" #include "sandbox/win/src/sandbox_policy.h" #include "sandbox/win/src/sandbox_types.h" @@ -91,20 +94,72 @@ DISALLOW_COPY_AND_ASSIGN(ServiceSandboxedProcessLauncherDelegate); }; +// This implementation does not do any font pre-caching. +// TODO(thestig): Can this be deleted and the PdfToEmfConverterClient be made +// optional? +class ServicePdfToEmfConverterClientImpl + : public printing::mojom::PdfToEmfConverterClient { + public: + explicit ServicePdfToEmfConverterClientImpl( + printing::mojom::PdfToEmfConverterClientRequest request) + : binding_(this, std::move(request)) {} + + private: + // mojom::PdfToEmfConverterClient: + void PreCacheFontCharacters( + const std::vector<uint8_t>& logfont_data, + const base::string16& characters, + PreCacheFontCharactersCallback callback) override { + std::move(callback).Run(); + } + + mojo::Binding<printing::mojom::PdfToEmfConverterClient> binding_; +}; + } // namespace class ServiceUtilityProcessHost::PdfToEmfState { public: - explicit PdfToEmfState(ServiceUtilityProcessHost* host) : host_(host) {} + explicit PdfToEmfState(base::WeakPtr<ServiceUtilityProcessHost> host) + : weak_host_(host) {} + ~PdfToEmfState() { Stop(); } bool Start(base::File pdf_file, const printing::PdfRenderSettings& conversion_settings) { if (!temp_dir_.CreateUniqueTempDir()) return false; - return host_->Send(new ChromeUtilityMsg_RenderPDFPagesToMetafiles( - IPC::TakePlatformFileForTransit(std::move(pdf_file)), - conversion_settings)); + + weak_host_->BindInterface( + printing::mojom::PdfToEmfConverterFactory::Name_, + mojo::MakeRequest(&pdf_to_emf_converter_factory_).PassMessagePipe()); + + pdf_to_emf_converter_factory_.set_connection_error_handler(base::BindOnce( + &PdfToEmfState::OnFailed, weak_host_, + std::string("Connection to PdfToEmfConverterFactory error."))); + + printing::mojom::PdfToEmfConverterClientPtr pdf_to_emf_converter_client_ptr; + pdf_to_emf_converter_client_impl_ = + std::make_unique<ServicePdfToEmfConverterClientImpl>( + mojo::MakeRequest(&pdf_to_emf_converter_client_ptr)); + + pdf_to_emf_converter_factory_->CreateConverter( + mojo::WrapPlatformFile(pdf_file.TakePlatformFile()), + conversion_settings, std::move(pdf_to_emf_converter_client_ptr), + base::BindOnce( + &ServiceUtilityProcessHost::OnRenderPDFPagesToMetafilesPageCount, + weak_host_)); + return true; + } + + void GotPageCount(printing::mojom::PdfToEmfConverterPtr converter, + uint32_t page_count) { + DCHECK(!pdf_to_emf_converter_.is_bound()); + pdf_to_emf_converter_ = std::move(converter); + pdf_to_emf_converter_.set_connection_error_handler( + base::BindOnce(&PdfToEmfState::OnFailed, weak_host_, + std::string("Connection to PdfToEmfConverter error."))); + page_count_ = page_count; } void GetMorePages() { @@ -113,10 +168,16 @@ current_page_ < page_count_) { ++pages_in_progress_; emf_files_.push(CreateTempFile()); - host_->Send(new ChromeUtilityMsg_RenderPDFPagesToMetafiles_GetPage( + + // We need to dup the file as mojo::WrapPlatformFile takes ownership of + // the passed file. + base::File temp_file_copy = emf_files_.back().Duplicate(); + pdf_to_emf_converter_->ConvertPage( current_page_++, - IPC::GetPlatformFileForTransit( - emf_files_.back().GetPlatformFile(), false))); + mojo::WrapPlatformFile(temp_file_copy.TakePlatformFile()), + base::BindOnce( + &ServiceUtilityProcessHost::OnRenderPDFPagesToMetafilesPageDone, + weak_host_)); } } @@ -140,12 +201,19 @@ return file; } - void set_page_count(int page_count) { page_count_ = page_count; } - bool has_page_count() { return page_count_ > 0; } + bool has_page_count() const { return page_count_ > 0; } private: + static void OnFailed(const base::WeakPtr<ServiceUtilityProcessHost>& host, + const std::string& error_message) { + LOG(ERROR) << "Failed to convert PDF: " << error_message; + host->OnChildDisconnected(); + } + void Stop() { - host_->Send(new ChromeUtilityMsg_RenderPDFPagesToMetafiles_Stop()); + // Disconnect interface ptrs so that the printing service process stop. + pdf_to_emf_converter_factory_.reset(); + pdf_to_emf_converter_.reset(); } base::File CreateTempFile() { @@ -161,11 +229,18 @@ } base::ScopedTempDir temp_dir_; - ServiceUtilityProcessHost* const host_; + base::WeakPtr<ServiceUtilityProcessHost> weak_host_; base::queue<base::File> emf_files_; int page_count_ = 0; int current_page_ = 0; int pages_in_progress_ = 0; + + std::unique_ptr<ServicePdfToEmfConverterClientImpl> + pdf_to_emf_converter_client_impl_; + + printing::mojom::PdfToEmfConverterPtr pdf_to_emf_converter_; + + printing::mojom::PdfToEmfConverterFactoryPtr pdf_to_emf_converter_factory_; }; ServiceUtilityProcessHost::ServiceUtilityProcessHost( @@ -195,7 +270,8 @@ DCHECK(!waiting_for_reply_); waiting_for_reply_ = true; - pdf_to_emf_state_ = std::make_unique<PdfToEmfState>(this); + pdf_to_emf_state_ = + std::make_unique<PdfToEmfState>(weak_ptr_factory_.GetWeakPtr()); return pdf_to_emf_state_->Start(std::move(pdf_file), render_settings); } @@ -316,11 +392,6 @@ bool handled = true; IPC_BEGIN_MESSAGE_MAP(ServiceUtilityProcessHost, message) IPC_MESSAGE_HANDLER( - ChromeUtilityHostMsg_RenderPDFPagesToMetafiles_PageCount, - OnRenderPDFPagesToMetafilesPageCount) - IPC_MESSAGE_HANDLER(ChromeUtilityHostMsg_RenderPDFPagesToMetafiles_PageDone, - OnRenderPDFPagesToMetafilesPageDone) - IPC_MESSAGE_HANDLER( ChromeUtilityHostMsg_GetPrinterCapsAndDefaults_Succeeded, OnGetPrinterCapsAndDefaultsSucceeded) IPC_MESSAGE_HANDLER(ChromeUtilityHostMsg_GetPrinterCapsAndDefaults_Failed, @@ -359,13 +430,13 @@ } void ServiceUtilityProcessHost::OnRenderPDFPagesToMetafilesPageCount( - int page_count) { + printing::mojom::PdfToEmfConverterPtr converter, + uint32_t page_count) { DCHECK(waiting_for_reply_); - if (!pdf_to_emf_state_ || page_count <= 0 || - pdf_to_emf_state_->has_page_count()) { + if (page_count == 0 || pdf_to_emf_state_->has_page_count()) return OnPDFToEmfFinished(false); - } - pdf_to_emf_state_->set_page_count(page_count); + + pdf_to_emf_state_->GotPageCount(std::move(converter), page_count); pdf_to_emf_state_->GetMorePages(); }
diff --git a/chrome/service/service_utility_process_host.h b/chrome/service/service_utility_process_host.h index cab95542..61bee76f 100644 --- a/chrome/service/service_utility_process_host.h +++ b/chrome/service/service_utility_process_host.h
@@ -11,6 +11,7 @@ #include "base/macros.h" #include "base/memory/ref_counted.h" #include "base/memory/weak_ptr.h" +#include "chrome/services/printing/public/interfaces/pdf_to_emf_converter.mojom.h" #include "content/public/common/child_process_host_delegate.h" #include "ipc/ipc_platform_file.h" #include "mojo/edk/embedder/outgoing_broker_client_invitation.h" @@ -132,9 +133,13 @@ void OnMetafileSpooled(bool success); void OnPDFToEmfFinished(bool success); - // Messages handlers: - void OnRenderPDFPagesToMetafilesPageCount(int page_count); + // PdfToEmfState callbacks: + void OnRenderPDFPagesToMetafilesPageCount( + printing::mojom::PdfToEmfConverterPtr converter, + uint32_t page_count); void OnRenderPDFPagesToMetafilesPageDone(bool success, float scale_factor); + + // IPC Messages handlers: void OnGetPrinterCapsAndDefaultsSucceeded( const std::string& printer_name, const printing::PrinterCapsAndDefaults& caps_and_defaults);
diff --git a/chrome/services/printing/pdf_to_emf_converter_factory.cc b/chrome/services/printing/pdf_to_emf_converter_factory.cc index 5e6c0e95..93689066 100644 --- a/chrome/services/printing/pdf_to_emf_converter_factory.cc +++ b/chrome/services/printing/pdf_to_emf_converter_factory.cc
@@ -14,6 +14,8 @@ std::unique_ptr<service_manager::ServiceContextRef> service_ref) : service_ref_(std::move(service_ref)) {} +PdfToEmfConverterFactory::PdfToEmfConverterFactory() = default; + PdfToEmfConverterFactory::~PdfToEmfConverterFactory() = default; void PdfToEmfConverterFactory::CreateConverter( @@ -31,4 +33,10 @@ std::move(callback).Run(std::move(converter_ptr), page_count); } +// static +void PdfToEmfConverterFactory::Create( + mojom::PdfToEmfConverterFactoryRequest request) { + mojo::MakeStrongBinding(base::MakeUnique<PdfToEmfConverterFactory>(), + std::move(request)); +} } // namespace printing
diff --git a/chrome/services/printing/pdf_to_emf_converter_factory.h b/chrome/services/printing/pdf_to_emf_converter_factory.h index 10a658c..acb9743 100644 --- a/chrome/services/printing/pdf_to_emf_converter_factory.h +++ b/chrome/services/printing/pdf_to_emf_converter_factory.h
@@ -17,6 +17,11 @@ std::unique_ptr<service_manager::ServiceContextRef> service_ref); ~PdfToEmfConverterFactory() override; + // TODO(crbug.com/798782): remove when the Cloud print chrome/service is + // removed. + PdfToEmfConverterFactory(); + static void Create(mojom::PdfToEmfConverterFactoryRequest request); + private: // mojom::PdfToEmfConverterFactory implementation. void CreateConverter(mojo::ScopedHandle pdf_file_in,
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn index ad9d0ce2..c7f72a21 100644 --- a/chrome/test/BUILD.gn +++ b/chrome/test/BUILD.gn
@@ -474,6 +474,7 @@ "../browser/chrome_find_request_manager_browsertest.cc", "../browser/chrome_main_browsertest.cc", "../browser/chrome_navigation_browsertest.cc", + "../browser/chrome_network_service_restart_browsertest.cc", "../browser/chrome_origin_trials_browsertest.cc", "../browser/chrome_plugin_browsertest.cc", "../browser/chrome_security_exploit_browsertest.cc", @@ -587,6 +588,7 @@ "../browser/net/errorpage_browsertest.cc", "../browser/net/ftp_browsertest.cc", "../browser/net/load_timing_browsertest.cc", + "../browser/net/network_connection_tracker_browsertest.cc", "../browser/net/network_context_configuration_browsertest.cc", "../browser/net/nqe/ui_network_quality_estimator_service_browsertest.cc", "../browser/net/nqe/ui_network_quality_estimator_service_test_util.cc", @@ -682,8 +684,6 @@ # If this list is used on Android in the future, these browser/speech/* # files will probably not be applicable. - "../browser/chrome_network_service_restart_browsertest.cc", - "../browser/net/network_connection_tracker_browsertest.cc", "../browser/speech/extension_api/tts_extension_apitest.cc", "../browser/speech/speech_recognition_browsertest.cc", "../browser/spellchecker/spellcheck_mac_view_browsertest.mm", @@ -1604,6 +1604,7 @@ "../browser/extensions/api/networking_private/networking_private_apitest.cc", "../browser/extensions/api/networking_private/networking_private_chromeos_apitest.cc", "../browser/extensions/api/vpn_provider/vpn_provider_apitest.cc", + "../browser/mash_service_registry_browsertest.cc", "../browser/signin/chromeos_mirror_account_consistency_browsertest.cc", "../browser/ui/ash/accelerator_commands_browsertest.cc", "../browser/ui/ash/app_list/app_list_browsertest.cc", @@ -3068,6 +3069,7 @@ ] sources += [ "../browser/component_updater/cros_component_installer_unittest.cc", + "../browser/mash_service_registry_unittest.cc", "../browser/media/webrtc/desktop_media_list_ash_unittest.cc", "../browser/notifications/chrome_ash_message_center_client_unittest.cc", "../browser/renderer_context_menu/mock_render_view_context_menu.cc",
diff --git a/chrome/test/android/javatests/src/org/chromium/chrome/test/ChromeJUnit4ClassRunner.java b/chrome/test/android/javatests/src/org/chromium/chrome/test/ChromeJUnit4ClassRunner.java index 6ab26c8..e21b055 100644 --- a/chrome/test/android/javatests/src/org/chromium/chrome/test/ChromeJUnit4ClassRunner.java +++ b/chrome/test/android/javatests/src/org/chromium/chrome/test/ChromeJUnit4ClassRunner.java
@@ -8,8 +8,8 @@ import org.junit.runners.model.InitializationError; -import org.chromium.base.BaseChromiumApplication; import org.chromium.base.CollectionUtil; +import org.chromium.base.CommandLineInitUtil; import org.chromium.base.test.BaseJUnit4ClassRunner; import org.chromium.base.test.BaseTestResult.PreTestHook; import org.chromium.base.test.util.CommandLineFlags; @@ -49,6 +49,7 @@ @Override protected void initCommandLineForTest() { - BaseChromiumApplication.initCommandLine(InstrumentationRegistry.getTargetContext()); + CommandLineInitUtil.initCommandLine( + InstrumentationRegistry.getTargetContext(), CommandLineFlags.getTestCmdLineFile()); } }
diff --git a/chrome/test/data/extensions/api_test/cast_channel/api/test_open_error_send.html b/chrome/test/data/extensions/api_test/cast_channel/api/test_open_error_send.html new file mode 100644 index 0000000..090ff78 --- /dev/null +++ b/chrome/test/data/extensions/api_test/cast_channel/api/test_open_error_send.html
@@ -0,0 +1,2 @@ +<script src="common.js"></script> +<script src="test_open_error_send.js"></script>
diff --git a/chrome/test/data/extensions/api_test/cast_channel/api/test_open_error_send.js b/chrome/test/data/extensions/api_test/cast_channel/api/test_open_error_send.js new file mode 100644 index 0000000..179ef9882 --- /dev/null +++ b/chrome/test/data/extensions/api_test/cast_channel/api/test_open_error_send.js
@@ -0,0 +1,31 @@ +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +var message = { + 'namespace_': 'foo', + 'sourceId': 'src', + 'destinationId': 'dest', + 'data': 'some-string' +}; + +var onClose = function(channel) { + chrome.test.assertLastError('Channel socket error = 3'); + chrome.test.succeed(); +}; + +var onSend = function(channel) { + chrome.test.assertLastError('Channel error = 1'); + chrome.cast.channel.close(channel, onClose); +}; + +var onOpen = function(channel) { + chrome.test.assertLastError('Channel socket error = 3'); + assertClosedChannelWithError(channel, 'connect_error'); + chrome.cast.channel.send(channel, message, onSend); +}; + +chrome.cast.channel.open({ + ipAddress: '192.168.1.1', + port: 8009, + auth: 'ssl_verified'}, onOpen);
diff --git a/chrome/tools/build/mac/infoplist_strings_util.mm b/chrome/tools/build/mac/infoplist_strings_util.mm index 6558aec..f1d158dc 100644 --- a/chrome/tools/build/mac/infoplist_strings_util.mm +++ b/chrome/tools/build/mac/infoplist_strings_util.mm
@@ -256,10 +256,6 @@ LoadStringFromDataPack(branded_data_pack.get(), cur_lang, IDS_ABOUT_VERSION_COPYRIGHT, "IDS_ABOUT_VERSION_COPYRIGHT"); - NSString* address_book_prompt_description = - LoadStringFromDataPack(branded_data_pack.get(), cur_lang, - IDS_AUTOFILL_ADDRESS_BOOK_PROMPT_DESCRIPTION, - "IDS_AUTOFILL_ADDRESS_BOOK_PROMPT_DESCRIPTION"); NSString* copyright = base::SysUTF16ToNSString( base::i18n::MessageFormatter::FormatWithNumberedArgs( @@ -276,12 +272,10 @@ @"CFBundleDisplayName = \"%@\";\n" @"CFBundleGetInfoString = \"%@\";\n" @"CFBundleName = \"%@\";\n" - @"NSContactsUsageDescription = \"%@\";\n" @"NSHumanReadableCopyright = \"%@\";\n", EscapeForStringsFileValue(name), EscapeForStringsFileValue(get_info), EscapeForStringsFileValue(short_name), - EscapeForStringsFileValue(address_book_prompt_description), EscapeForStringsFileValue(copyright)]; // We set up Xcode projects expecting strings files to be UTF8, so make
diff --git a/chrome/utility/DEPS b/chrome/utility/DEPS index 17bf4ca3..6797a1f 100644 --- a/chrome/utility/DEPS +++ b/chrome/utility/DEPS
@@ -6,6 +6,9 @@ "+chrome/services/file_util/public/interfaces", "+chrome/services/media_gallery_util/media_gallery_util_service.h", "+chrome/services/media_gallery_util/public/interfaces", + # TODO(crbug.com/798782): remove dependency to pdf_to_emf_converter_factory.h + # when Cloud print chrome/service is removed. + "+chrome/services/printing/pdf_to_emf_converter_factory.h", "+chrome/services/printing/printing_service.h", "+chrome/services/printing/public/interfaces", "+chrome/services/removable_storage_writer/removable_storage_writer_service.h",
diff --git a/chrome/utility/chrome_content_utility_client.cc b/chrome/utility/chrome_content_utility_client.cc index b70e6b4..af47855 100644 --- a/chrome/utility/chrome_content_utility_client.cc +++ b/chrome/utility/chrome_content_utility_client.cc
@@ -44,6 +44,7 @@ #endif // !defined(OS_ANDROID) #if defined(OS_WIN) +#include "chrome/services/printing/pdf_to_emf_converter_factory.h" #include "chrome/services/util_win/public/interfaces/constants.mojom.h" #include "chrome/services/util_win/util_win_service.h" #endif @@ -178,6 +179,13 @@ registry->AddInterface(base::Bind(CreateResourceUsageReporter), base::ThreadTaskRunnerHandle::Get()); #endif // !defined(OS_ANDROID) +#if defined(OS_WIN) + // TODO(crbug.com/798782): remove when the Cloud print chrome/service is + // removed. + registry->AddInterface( + base::Bind(printing::PdfToEmfConverterFactory::Create), + base::ThreadTaskRunnerHandle::Get()); +#endif } connection->AddConnectionFilter(
diff --git a/chrome/utility/mash_service_factory.cc b/chrome/utility/mash_service_factory.cc index 244ae60..f566bc98 100644 --- a/chrome/utility/mash_service_factory.cc +++ b/chrome/utility/mash_service_factory.cc
@@ -34,8 +34,24 @@ // NOTE: For --mus the UI service is created at the //chrome/browser layer, // not in //content. See ServiceManagerContext. -std::unique_ptr<service_manager::Service> CreateUiService() { - return std::make_unique<ui::Service>(); +std::unique_ptr<service_manager::Service> CreateUiService( + const scoped_refptr<base::SingleThreadTaskRunner>& task_runner) { + ui::Service::InProcessConfig config; + config.resource_runner = task_runner; + // TODO(jamescook): Fix cursor loading. + config.should_host_viz = true; + return std::make_unique<ui::Service>(&config); +} + +void RegisterUiService( + content::ContentUtilityClient::StaticServiceMap* services) { + service_manager::EmbeddedServiceInfo service_info; + service_info.use_own_thread = true; + service_info.message_loop_type = base::MessageLoop::TYPE_UI; + service_info.thread_priority = base::ThreadPriority::DISPLAY; + service_info.factory = base::BindRepeating( + &CreateUiService, base::ThreadTaskRunnerHandle::Get()); + services->emplace(ui::mojom::kServiceName, service_info); } std::unique_ptr<service_manager::Service> CreateAshService() { @@ -64,7 +80,7 @@ void RegisterOutOfProcessMashServices( content::ContentUtilityClient::StaticServiceMap* services) { - RegisterMashService(services, ui::mojom::kServiceName, &CreateUiService); + RegisterUiService(services); RegisterMashService(services, mash::quick_launch::mojom::kServiceName, &CreateQuickLaunch); RegisterMashService(services, ash::mojom::kServiceName, &CreateAshService);
diff --git a/chrome/utility/printing_handler.cc b/chrome/utility/printing_handler.cc index f12cc09c..1eb8186 100644 --- a/chrome/utility/printing_handler.cc +++ b/chrome/utility/printing_handler.cc
@@ -40,10 +40,6 @@ bool PrintingHandler::OnMessageReceived(const IPC::Message& message) { bool handled = true; IPC_BEGIN_MESSAGE_MAP(PrintingHandler, message) -#if defined(OS_WIN) - IPC_MESSAGE_HANDLER(ChromeUtilityMsg_RenderPDFPagesToMetafiles_Stop, - OnRenderPDFPagesToMetafileStop) -#endif // OS_WIN #if BUILDFLAG(ENABLE_PRINT_PREVIEW) IPC_MESSAGE_HANDLER(ChromeUtilityMsg_GetPrinterCapsAndDefaults, OnGetPrinterCapsAndDefaults) @@ -55,12 +51,6 @@ return handled; } -#if defined(OS_WIN) -void PrintingHandler::OnRenderPDFPagesToMetafileStop() { - ReleaseProcess(); -} -#endif - #if BUILDFLAG(ENABLE_PRINT_PREVIEW) void PrintingHandler::OnGetPrinterCapsAndDefaults( const std::string& printer_name) {
diff --git a/chrome/utility/printing_handler.h b/chrome/utility/printing_handler.h index 8ed7389..a9465916 100644 --- a/chrome/utility/printing_handler.h +++ b/chrome/utility/printing_handler.h
@@ -31,13 +31,10 @@ private: // IPC message handlers. -#if defined(OS_WIN) - void OnRenderPDFPagesToMetafileStop(); -#endif // OS_WIN #if BUILDFLAG(ENABLE_PRINT_PREVIEW) void OnGetPrinterCapsAndDefaults(const std::string& printer_name); void OnGetPrinterSemanticCapsAndDefaults(const std::string& printer_name); -#endif // ENABLE_PRINT_PREVIEW +#endif DISALLOW_COPY_AND_ASSIGN(PrintingHandler); };
diff --git a/chromecast/browser/android/apk/src/org/chromium/chromecast/shell/CastApplication.java b/chromecast/browser/android/apk/src/org/chromium/chromecast/shell/CastApplication.java index 7f072354..fec40f7 100644 --- a/chromecast/browser/android/apk/src/org/chromium/chromecast/shell/CastApplication.java +++ b/chromecast/browser/android/apk/src/org/chromium/chromecast/shell/CastApplication.java
@@ -39,7 +39,6 @@ ApplicationStatus.initialize(this); } - @Override public void initCommandLine() { CommandLineInitUtil.initCommandLine(this, COMMAND_LINE_FILE); }
diff --git a/chromecast/browser/android/apk/src/org/chromium/chromecast/shell/CastBrowserHelper.java b/chromecast/browser/android/apk/src/org/chromium/chromecast/shell/CastBrowserHelper.java index 64f23e2..9cc9595 100644 --- a/chromecast/browser/android/apk/src/org/chromium/chromecast/shell/CastBrowserHelper.java +++ b/chromecast/browser/android/apk/src/org/chromium/chromecast/shell/CastBrowserHelper.java
@@ -14,7 +14,6 @@ import org.chromium.base.library_loader.LibraryProcessType; import org.chromium.base.library_loader.ProcessInitException; import org.chromium.chromecast.base.ChromecastConfigAndroid; -import org.chromium.content.app.ContentApplication; import org.chromium.content.browser.BrowserStartupController; import org.chromium.content.browser.DeviceUtils; import org.chromium.net.NetworkChangeNotifier; @@ -45,7 +44,7 @@ // Initializing the command line must occur before loading the library. if (!CommandLine.isInitialized()) { - ContentApplication.initCommandLine(context); + ((CastApplication) context.getApplicationContext()).initCommandLine(); if (context instanceof Activity) { Intent launchingIntent = ((Activity) context).getIntent();
diff --git a/components/assist_ranker/base_predictor.cc b/components/assist_ranker/base_predictor.cc index bece7fb..8e061a52 100644 --- a/components/assist_ranker/base_predictor.cc +++ b/components/assist_ranker/base_predictor.cc
@@ -57,9 +57,8 @@ void BasePredictor::LogFeatureToUkm(const std::string& feature_name, const Feature& feature, ukm::UkmEntryBuilder* ukm_builder) { - if (!ukm_builder) { + if (!ukm_builder) return; - } if (!base::ContainsKey(*config_.feature_whitelist, feature_name)) { DVLOG(1) << "Feature not whitelisted: " << feature_name;
diff --git a/components/assist_ranker/binary_classifier_predictor.cc b/components/assist_ranker/binary_classifier_predictor.cc index 7898588..cc595bf0 100644 --- a/components/assist_ranker/binary_classifier_predictor.cc +++ b/components/assist_ranker/binary_classifier_predictor.cc
@@ -82,8 +82,8 @@ bool BinaryClassifierPredictor::Initialize() { if (ranker_model_->proto().model_case() == RankerModelProto::kLogisticRegression) { - inference_module_.reset(new GenericLogisticRegressionInference( - ranker_model_->proto().logistic_regression())); + inference_module_ = std::make_unique<GenericLogisticRegressionInference>( + ranker_model_->proto().logistic_regression()); return true; }
diff --git a/components/autofill/content/renderer/password_form_conversion_utils_browsertest.cc b/components/autofill/content/renderer/password_form_conversion_utils_browsertest.cc index c3eb4dc..4cb5beec 100644 --- a/components/autofill/content/renderer/password_form_conversion_utils_browsertest.cc +++ b/components/autofill/content/renderer/password_form_conversion_utils_browsertest.cc
@@ -3,9 +3,9 @@ // found in the LICENSE file. #include <stddef.h> +#include <memory> #include "base/macros.h" -#include "base/memory/ptr_util.h" #include "base/strings/string16.h" #include "base/strings/string_util.h" #include "base/strings/stringprintf.h" @@ -731,10 +731,10 @@ // for "id" field. FieldValueAndPropertiesMaskMap user_input; user_input[control_elements[2]] = std::make_pair( // id - base::MakeUnique<base::string16>(control_elements[2].Value().Utf16()), + std::make_unique<base::string16>(control_elements[2].Value().Utf16()), FieldPropertiesFlags::USER_TYPED); user_input[control_elements[3]] = std::make_pair( // password - base::MakeUnique<base::string16>(control_elements[3].Value().Utf16()), + std::make_unique<base::string16>(control_elements[3].Value().Utf16()), FieldPropertiesFlags::USER_TYPED); std::unique_ptr<PasswordForm> password_form = CreatePasswordFormFromWebForm(
diff --git a/components/autofill/core/browser/BUILD.gn b/components/autofill/core/browser/BUILD.gn index a8402deb..e1f163b 100644 --- a/components/autofill/core/browser/BUILD.gn +++ b/components/autofill/core/browser/BUILD.gn
@@ -266,10 +266,6 @@ } configs += [ "//build/config/compiler:no_size_t_to_int_warning" ] - - if (is_mac) { - libs = [ "AddressBook.framework" ] - } } static_library("test_support") {
diff --git a/components/autofill/core/browser/address_combobox_model.cc b/components/autofill/core/browser/address_combobox_model.cc index 940bcf53..e7e6fdb3 100644 --- a/components/autofill/core/browser/address_combobox_model.cc +++ b/components/autofill/core/browser/address_combobox_model.cc
@@ -127,13 +127,8 @@ AutofillProfile::CreateDifferentiatingLabels(profiles, app_locale_, &labels); DCHECK_EQ(labels.size(), profiles_cache_.size()); - for (size_t i = 0; i < profiles_cache_.size(); ++i) { - // Skip showing auxiliary profiles (e.g. Mac Contacts). - if (profiles_cache_[i]->record_type() == AutofillProfile::AUXILIARY_PROFILE) - continue; - - addresses_.push_back(std::make_pair(profiles_cache_[i]->guid(), labels[i])); - } + for (size_t i = 0; i < profiles_cache_.size(); ++i) + addresses_.emplace_back(profiles_cache_[i]->guid(), labels[i]); for (auto& observer : observers_) { observer.OnComboboxModelChanged(this);
diff --git a/components/autofill/core/browser/autofill_external_delegate.cc b/components/autofill/core/browser/autofill_external_delegate.cc index 15daab1..2c8d17a3 100644 --- a/components/autofill/core/browser/autofill_external_delegate.cc +++ b/components/autofill/core/browser/autofill_external_delegate.cc
@@ -53,7 +53,6 @@ should_show_scan_credit_card_(false), is_credit_card_popup_(false), should_show_cc_signin_promo_(false), - has_shown_address_book_prompt(false), weak_ptr_factory_(this) { DCHECK(manager); } @@ -67,9 +66,6 @@ const FormData& form, const FormFieldData& field, const gfx::RectF& element_bounds) { - if (!query_form_.SameFormAs(form)) - has_shown_address_book_prompt = false; - query_form_ = form; query_field_ = field; query_id_ = query_id;
diff --git a/components/autofill/core/browser/autofill_external_delegate.h b/components/autofill/core/browser/autofill_external_delegate.h index fee1624..4bc3364 100644 --- a/components/autofill/core/browser/autofill_external_delegate.h +++ b/components/autofill/core/browser/autofill_external_delegate.h
@@ -154,10 +154,6 @@ // Whether the credit card signin promo should be shown to the user. bool should_show_cc_signin_promo_; - // Whether the access Address Book prompt has ever been shown for the current - // |query_form_|. This variable is only used on OSX. - bool has_shown_address_book_prompt; - // The current data list values. std::vector<base::string16> data_list_values_; std::vector<base::string16> data_list_labels_;
diff --git a/components/autofill/core/browser/autofill_manager.cc b/components/autofill/core/browser/autofill_manager.cc index 6bbf9180..dfa7585 100644 --- a/components/autofill/core/browser/autofill_manager.cc +++ b/components/autofill/core/browser/autofill_manager.cc
@@ -765,8 +765,7 @@ if (!IsValidFormData(form) || !IsValidFormFieldData(field)) return; - // NOTE: RefreshDataModels may invalidate |data_model| because it causes the - // PersonalDataManager to reload Mac address book entries. Thus it must come + // NOTE: RefreshDataModels may invalidate |data_model|. Thus it must come // before GetProfile or GetCreditCard. if (!RefreshDataModels() || !driver()->RendererIsAvailable()) return; @@ -1331,8 +1330,7 @@ } } - // Note that this may invalidate |data_model|, particularly if it is a Mac - // address book entry. + // Note that this may invalidate |data_model|. if (action == AutofillDriver::FORM_DATA_ACTION_FILL) personal_data_->RecordUseOf(data_model); @@ -1387,8 +1385,7 @@ if (autofilled_form_signatures_.size() > kMaxRecentFormSignaturesToRemember) autofilled_form_signatures_.pop_back(); - // Note that this may invalidate |data_model|, particularly if it is a Mac - // address book entry. + // Note that this may invalidate |data_model|. if (action == AutofillDriver::FORM_DATA_ACTION_FILL) personal_data_->RecordUseOf(data_model);
diff --git a/components/autofill/core/browser/autofill_metrics_unittest.cc b/components/autofill/core/browser/autofill_metrics_unittest.cc index 0481bd01..33defae 100644 --- a/components/autofill/core/browser/autofill_metrics_unittest.cc +++ b/components/autofill/core/browser/autofill_metrics_unittest.cc
@@ -248,9 +248,6 @@ void AutofillMetricsTest::SetUp() { autofill_client_.SetPrefs(test::PrefServiceForTesting()); - // Ensure Mac OS X does not pop up a modal dialog for the Address Book. - test::DisableSystemServices(autofill_client_.GetPrefs()); - // Set up identity services. signin_client_ = std::make_unique<TestSigninClient>(autofill_client_.GetPrefs());
diff --git a/components/autofill/core/browser/autofill_policy_handler_unittest.cc b/components/autofill/core/browser/autofill_policy_handler_unittest.cc index 6969366..09ccd18e 100644 --- a/components/autofill/core/browser/autofill_policy_handler_unittest.cc +++ b/components/autofill/core/browser/autofill_policy_handler_unittest.cc
@@ -2,8 +2,9 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include <memory> + #include "components/autofill/core/browser/autofill_policy_handler.h" -#include "base/memory/ptr_util.h" #include "base/values.h" #include "components/autofill/core/common/autofill_pref_names.h" #include "components/policy/core/common/policy_map.h" @@ -29,7 +30,7 @@ policy::PolicyMap policy; policy.Set(policy::key::kAutoFillEnabled, policy::POLICY_LEVEL_MANDATORY, policy::POLICY_SCOPE_USER, policy::POLICY_SOURCE_CLOUD, - base::MakeUnique<base::Value>(true), nullptr); + std::make_unique<base::Value>(true), nullptr); PrefValueMap prefs; AutofillPolicyHandler handler; handler.ApplyPolicySettings(policy, &prefs); @@ -42,7 +43,7 @@ policy::PolicyMap policy; policy.Set(policy::key::kAutoFillEnabled, policy::POLICY_LEVEL_MANDATORY, policy::POLICY_SCOPE_USER, policy::POLICY_SOURCE_CLOUD, - base::MakeUnique<base::Value>(false), nullptr); + std::make_unique<base::Value>(false), nullptr); PrefValueMap prefs; AutofillPolicyHandler handler; handler.ApplyPolicySettings(policy, &prefs);
diff --git a/components/autofill/core/browser/autofill_profile.h b/components/autofill/core/browser/autofill_profile.h index f489747..f5a06442 100644 --- a/components/autofill/core/browser/autofill_profile.h +++ b/components/autofill/core/browser/autofill_profile.h
@@ -36,8 +36,6 @@ LOCAL_PROFILE, // A profile synced down from the server. These are read-only locally. SERVER_PROFILE, - // An auxiliary profile, such as a Mac address book entry. - AUXILIARY_PROFILE, }; enum ValidityState {
diff --git a/components/autofill/core/browser/credit_card_save_manager_unittest.cc b/components/autofill/core/browser/credit_card_save_manager_unittest.cc index d50666f3..e79083f 100644 --- a/components/autofill/core/browser/credit_card_save_manager_unittest.cc +++ b/components/autofill/core/browser/credit_card_save_manager_unittest.cc
@@ -108,7 +108,8 @@ payments_client_, &personal_data_); autofill_manager_.reset(new TestAutofillManager( autofill_driver_.get(), &autofill_client_, &personal_data_, - credit_card_save_manager_, payments_client_)); + std::unique_ptr<CreditCardSaveManager>(credit_card_save_manager_), + payments_client_)); autofill_manager_->SetExpectedObservedSubmission(true); } @@ -146,8 +147,7 @@ scoped_feature_list_.InitWithFeatures( {kAutofillUpstreamRequestCvcIfMissing, kAutofillUpstreamSendDetectedValues}, // Enabled - {} // Disabled - ); + {}); // Disabled } void EnableAutofillUpstreamSendPanFirstSixExperiment() {
diff --git a/components/autofill/core/browser/form_data_importer.h b/components/autofill/core/browser/form_data_importer.h index 68cb8bd8..d3c07d5 100644 --- a/components/autofill/core/browser/form_data_importer.h +++ b/components/autofill/core/browser/form_data_importer.h
@@ -8,6 +8,7 @@ #include <map> #include <memory> #include <string> +#include <utility> #include <vector> #include "build/build_config.h" @@ -49,8 +50,8 @@ protected: // Exposed for testing. void set_credit_card_save_manager( - CreditCardSaveManager* credit_card_save_manager) { - credit_card_save_manager_.reset(credit_card_save_manager); + std::unique_ptr<CreditCardSaveManager> credit_card_save_manager) { + credit_card_save_manager_ = std::move(credit_card_save_manager); } private:
diff --git a/components/autofill/core/browser/personal_data_manager.h b/components/autofill/core/browser/personal_data_manager.h index 02855477..ce8f498 100644 --- a/components/autofill/core/browser/personal_data_manager.h +++ b/components/autofill/core/browser/personal_data_manager.h
@@ -100,8 +100,7 @@ void MarkObserversInsufficientFormDataForImport(); // Called to indicate |data_model| was used (to fill in a form). Updates - // the database accordingly. Can invalidate |data_model|, particularly if - // it's a Mac address book entry. + // the database accordingly. Can invalidate |data_model|. virtual void RecordUseOf(const AutofillDataModel& data_model); // Saves |imported_profile| to the WebDB if it exists. Returns the guid of
diff --git a/components/autofill/core/browser/test_autofill_manager.cc b/components/autofill/core/browser/test_autofill_manager.cc index f368727..3291fecc 100644 --- a/components/autofill/core/browser/test_autofill_manager.cc +++ b/components/autofill/core/browser/test_autofill_manager.cc
@@ -29,14 +29,14 @@ AutofillDriver* driver, AutofillClient* client, TestPersonalDataManager* personal_data, - CreditCardSaveManager* credit_card_save_manager, + std::unique_ptr<CreditCardSaveManager> credit_card_save_manager, payments::TestPaymentsClient* payments_client) : AutofillManager(driver, client, personal_data), personal_data_(personal_data), test_form_data_importer_( new TestFormDataImporter(client, payments_client, - credit_card_save_manager, + std::move(credit_card_save_manager), personal_data, "en-US")) { set_payments_client(payments_client);
diff --git a/components/autofill/core/browser/test_autofill_manager.h b/components/autofill/core/browser/test_autofill_manager.h index 5ad28798e3..56519fd 100644 --- a/components/autofill/core/browser/test_autofill_manager.h +++ b/components/autofill/core/browser/test_autofill_manager.h
@@ -5,7 +5,9 @@ #ifndef COMPONENTS_AUTOFILL_CORE_BROWSER_TEST_AUTOFILL_MANAGER_H_ #define COMPONENTS_AUTOFILL_CORE_BROWSER_TEST_AUTOFILL_MANAGER_H_ +#include <memory> #include <string> +#include <utility> #include <vector> #include "base/optional.h" @@ -34,11 +36,12 @@ AutofillClient* client, TestPersonalDataManager* personal_data); // Called by CreditCardSaveManagerTest. - TestAutofillManager(AutofillDriver* driver, - AutofillClient* client, - TestPersonalDataManager* personal_data, - CreditCardSaveManager* credit_card_save_manager, - payments::TestPaymentsClient* payments_client); + TestAutofillManager( + AutofillDriver* driver, + AutofillClient* client, + TestPersonalDataManager* personal_data, + std::unique_ptr<CreditCardSaveManager> credit_card_save_manager, + payments::TestPaymentsClient* payments_client); ~TestAutofillManager() override; // AutofillManager overrides.
diff --git a/components/autofill/core/browser/test_form_data_importer.cc b/components/autofill/core/browser/test_form_data_importer.cc index 970b322..cd6943e1 100644 --- a/components/autofill/core/browser/test_form_data_importer.cc +++ b/components/autofill/core/browser/test_form_data_importer.cc
@@ -9,14 +9,14 @@ TestFormDataImporter::TestFormDataImporter( AutofillClient* client, payments::PaymentsClient* payments_client, - CreditCardSaveManager* credit_card_save_manager, + std::unique_ptr<CreditCardSaveManager> credit_card_save_manager, PersonalDataManager* personal_data_manager, const std::string& app_locale) : FormDataImporter(client, payments_client, personal_data_manager, app_locale) { - set_credit_card_save_manager(credit_card_save_manager); + set_credit_card_save_manager(std::move(credit_card_save_manager)); } } // namespace autofill
diff --git a/components/autofill/core/browser/test_form_data_importer.h b/components/autofill/core/browser/test_form_data_importer.h index c6bf838..c84887d 100644 --- a/components/autofill/core/browser/test_form_data_importer.h +++ b/components/autofill/core/browser/test_form_data_importer.h
@@ -5,17 +5,21 @@ #ifndef COMPONENTS_AUTOFILL_CORE_BROWSER_TEST_FORM_DATA_IMPORTER_H_ #define COMPONENTS_AUTOFILL_CORE_BROWSER_TEST_FORM_DATA_IMPORTER_H_ +#include <memory> +#include <utility> + #include "components/autofill/core/browser/form_data_importer.h" namespace autofill { class TestFormDataImporter : public FormDataImporter { public: - TestFormDataImporter(AutofillClient* client, - payments::PaymentsClient* payments_client, - CreditCardSaveManager* credit_card_save_manager, - PersonalDataManager* personal_data_manager, - const std::string& app_locale); + TestFormDataImporter( + AutofillClient* client, + payments::PaymentsClient* payments_client, + std::unique_ptr<CreditCardSaveManager> credit_card_save_manager, + PersonalDataManager* personal_data_manager, + const std::string& app_locale); }; } // namespace autofill
diff --git a/components/client_update_protocol/ecdsa.cc b/components/client_update_protocol/ecdsa.cc index 38faa9ab..1af829b7 100644 --- a/components/client_update_protocol/ecdsa.cc +++ b/components/client_update_protocol/ecdsa.cc
@@ -68,13 +68,13 @@ // the SignatureValidator class will handle the actual DER decoding and // ASN.1 parsing. Check for an expected size range only -- valid ECDSA // signatures are between 8 and 72 bytes. - if (!base::HexStringToBytes(sig_hex.as_string(), ecdsa_signature_out)) + if (!base::HexStringToBytes(sig_hex, ecdsa_signature_out)) return false; if (ecdsa_signature_out->size() < 8 || ecdsa_signature_out->size() > 72) return false; // Decode the SHA-256 hash; it should be exactly 32 bytes, no more or less. - if (!base::HexStringToBytes(hash_hex.as_string(), request_hash_out)) + if (!base::HexStringToBytes(hash_hex, request_hash_out)) return false; if (request_hash_out->size() != crypto::kSHA256Length) return false;
diff --git a/components/cronet/android/test/javaperftests/run.py b/components/cronet/android/test/javaperftests/run.py index 9b960a0ad..0e1382d 100755 --- a/components/cronet/android/test/javaperftests/run.py +++ b/components/cronet/android/test/javaperftests/run.py
@@ -65,7 +65,6 @@ from devil.android.sdk import intent import lighttpd_server from pylib import constants -from pylib import pexpect from telemetry import android from telemetry import benchmark from telemetry import benchmark_runner @@ -80,9 +79,9 @@ CERT_PATH = os.path.join('net', 'data', 'ssl', 'certificates') QUIC_CERT_DIR = os.path.join(REPOSITORY_ROOT, CERT_PATH) QUIC_CERT_HOST = 'test.example.com' -QUIC_CERT_FILENAME = 'quic_%s.crt' % QUIC_CERT_HOST +QUIC_CERT_FILENAME = 'quic-chain.pem' QUIC_CERT = os.path.join(QUIC_CERT_DIR, QUIC_CERT_FILENAME) -QUIC_KEY = os.path.join(QUIC_CERT_DIR, 'quic_%s.key.pkcs8' % QUIC_CERT_HOST) +QUIC_KEY = os.path.join(QUIC_CERT_DIR, 'quic-leaf-cert.key') APP_APK = os.path.join(BUILD_DIR, 'apks', 'CronetPerfTest.apk') APP_PACKAGE = 'org.chromium.net' APP_ACTIVITY = '.CronetPerfTestActivity' @@ -229,15 +228,13 @@ self._quic_server_doc_root = quic_server_doc_root def StartupQuicServer(self, device): - # Chromium's presubmit checks aren't smart enough to understand - # the redirect done in build/android/pylib/pexpect.py. - # pylint: disable=no-member - self._process = pexpect.spawn(QUIC_SERVER, - ['--quic_response_cache_dir=%s' % - self._quic_server_doc_root, - '--certificate_file=%s' % QUIC_CERT, - '--key_file=%s' % QUIC_KEY, - '--port=%d' % QUIC_PORT]) + cmd = [QUIC_SERVER, + '--quic_response_cache_dir=%s' % self._quic_server_doc_root, + '--certificate_file=%s' % QUIC_CERT, + '--key_file=%s' % QUIC_KEY, + '--port=%d' % QUIC_PORT] + print "Starting Quic Server", cmd + self._process = subprocess.Popen(cmd) assert self._process != None # Wait for quic_server to start serving. waited_s = 0
diff --git a/components/cronet/cronet_prefs_manager.cc b/components/cronet/cronet_prefs_manager.cc index c1d4ae7e1..e06f21ae 100644 --- a/components/cronet/cronet_prefs_manager.cc +++ b/components/cronet/cronet_prefs_manager.cc
@@ -6,6 +6,7 @@ #include <memory> +#include "base/callback.h" #include "base/files/file_path.h" #include "base/files/file_util.h" #include "base/location.h" @@ -110,11 +111,15 @@ return pref_service_->GetDictionary(path_); } - void SetServerProperties(const base::DictionaryValue& value) override { - return pref_service_->Set(path_, value); + void SetServerProperties(const base::DictionaryValue& value, + base::OnceClosure callback) override { + pref_service_->Set(path_, value); + if (callback) + pref_service_->CommitPendingWrite(std::move(callback)); } - void StartListeningForUpdates(const base::Closure& callback) override { + void StartListeningForUpdates( + const base::RepeatingClosure& callback) override { pref_change_registrar_.Add(path_, callback); // Notify the pref manager that settings are already loaded, as a result // of initializing the pref store synchornously.
diff --git a/components/data_reduction_proxy/core/browser/data_reduction_proxy_delegate.cc b/components/data_reduction_proxy/core/browser/data_reduction_proxy_delegate.cc index 65a3c6c6..ffca2f4 100644 --- a/components/data_reduction_proxy/core/browser/data_reduction_proxy_delegate.cc +++ b/components/data_reduction_proxy/core/browser/data_reduction_proxy_delegate.cc
@@ -194,13 +194,6 @@ } } -void DataReductionProxyDelegate::OnTunnelConnectCompleted( - const net::HostPortPair& endpoint, - const net::HostPortPair& proxy_server, - int net_error) { - DCHECK(thread_checker_.CalledOnValidThread()); -} - void DataReductionProxyDelegate::OnFallback(const net::ProxyServer& bad_proxy, int net_error) { DCHECK(thread_checker_.CalledOnValidThread()); @@ -214,12 +207,6 @@ bypass_stats_->OnProxyFallback(bad_proxy, net_error); } -void DataReductionProxyDelegate::OnBeforeTunnelRequest( - const net::HostPortPair& proxy_server, - net::HttpRequestHeaders* extra_headers) { - DCHECK(thread_checker_.CalledOnValidThread()); -} - bool DataReductionProxyDelegate::IsTrustedSpdyProxy( const net::ProxyServer& proxy_server) { DCHECK(thread_checker_.CalledOnValidThread()); @@ -227,13 +214,6 @@ config_->IsDataReductionProxy(proxy_server, nullptr); } -void DataReductionProxyDelegate::OnTunnelHeadersReceived( - const net::HostPortPair& origin, - const net::HostPortPair& proxy_server, - const net::HttpResponseHeaders& response_headers) { - DCHECK(thread_checker_.CalledOnValidThread()); -} - void DataReductionProxyDelegate::SetTickClockForTesting( base::TickClock* tick_clock) { tick_clock_ = tick_clock;
diff --git a/components/data_reduction_proxy/core/browser/data_reduction_proxy_delegate.h b/components/data_reduction_proxy/core/browser/data_reduction_proxy_delegate.h index 6bde0e5..78cddc6e 100644 --- a/components/data_reduction_proxy/core/browser/data_reduction_proxy_delegate.h +++ b/components/data_reduction_proxy/core/browser/data_reduction_proxy_delegate.h
@@ -19,9 +19,6 @@ } namespace net { -class HostPortPair; -class HttpRequestHeaders; -class HttpResponseHeaders; class NetLog; class ProxyInfo; class ProxyServer; @@ -58,16 +55,7 @@ const net::ProxyRetryInfoMap& proxy_retry_info, net::ProxyInfo* result) override; void OnFallback(const net::ProxyServer& bad_proxy, int net_error) override; - void OnBeforeTunnelRequest(const net::HostPortPair& proxy_server, - net::HttpRequestHeaders* extra_headers) override; - void OnTunnelConnectCompleted(const net::HostPortPair& endpoint, - const net::HostPortPair& proxy_server, - int net_error) override; bool IsTrustedSpdyProxy(const net::ProxyServer& proxy_server) override; - void OnTunnelHeadersReceived( - const net::HostPortPair& origin, - const net::HostPortPair& proxy_server, - const net::HttpResponseHeaders& response_headers) override; void SetTickClockForTesting(base::TickClock* tick_clock);
diff --git a/components/download/BUILD.gn b/components/download/BUILD.gn index 985df7bab..4750fd24 100644 --- a/components/download/BUILD.gn +++ b/components/download/BUILD.gn
@@ -5,15 +5,12 @@ group("unit_tests") { testonly = true - deps = [ - "//components/download/internal:unit_tests", - ] - if (!is_ios) { - deps += [ + deps = [ "//components/download/content/internal:unit_tests", "//components/download/content/public:unit_tests", "//components/download/downloader/in_progress:unit_tests", + "//components/download/internal:unit_tests", ] }
diff --git a/components/download/components_unittests.filter b/components/download/components_unittests.filter index a0360b2..9d1d8bd 100644 --- a/components/download/components_unittests.filter +++ b/components/download/components_unittests.filter
@@ -10,6 +10,7 @@ DownloadStoreTest.* FileMonitorTest.* InProgressConversionsTest.* +InMemoryDownloadTest.* NavigationMonitorImplTest.* NetworkListenerTest.* ProtoConversionsTest.*
diff --git a/components/download/internal/BUILD.gn b/components/download/internal/BUILD.gn index e8f2ef48..de298e9 100644 --- a/components/download/internal/BUILD.gn +++ b/components/download/internal/BUILD.gn
@@ -16,6 +16,8 @@ ] sources = [ + "blob_task_proxy.cc", + "blob_task_proxy.h", "client_set.cc", "client_set.h", "config.cc", @@ -39,6 +41,8 @@ "file_monitor.h", "file_monitor_impl.cc", "file_monitor_impl.h", + "in_memory_download.cc", + "in_memory_download.h", "log_sink.h", "log_source.h", "logger_impl.cc", @@ -75,6 +79,7 @@ "//components/download/public", "//components/leveldb_proto", "//net", + "//storage/browser", ] if (is_android) { @@ -122,6 +127,7 @@ "download_store_unittest.cc", "entry_utils_unittest.cc", "file_monitor_unittest.cc", + "in_memory_download_unittest.cc", "model_impl_unittest.cc", "navigation_monitor_impl_unittests.cc", "proto_conversions_unittest.cc", @@ -138,6 +144,7 @@ "//components/download/public/test:test_support", "//components/leveldb_proto:test_support", "//net:test_support", + "//storage/browser", "//testing/gmock", "//testing/gtest", ]
diff --git a/components/download/internal/DEPS b/components/download/internal/DEPS index 85b754e..ed5bc8c 100644 --- a/components/download/internal/DEPS +++ b/components/download/internal/DEPS
@@ -5,4 +5,6 @@ "+base", "+jni", "+net", + "+storage/browser", + "+storage/common", ]
diff --git a/components/download/internal/blob_task_proxy.cc b/components/download/internal/blob_task_proxy.cc new file mode 100644 index 0000000..1348f13 --- /dev/null +++ b/components/download/internal/blob_task_proxy.cc
@@ -0,0 +1,83 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "components/download/internal/blob_task_proxy.h" + +#include "base/guid.h" +#include "base/task_runner_util.h" +#include "storage/browser/blob/blob_data_builder.h" +#include "storage/browser/blob/blob_data_handle.h" +#include "storage/browser/blob/blob_storage_context.h" + +namespace download { + +// static +std::unique_ptr<BlobTaskProxy> BlobTaskProxy::Create( + BlobContextGetter blob_context_getter, + scoped_refptr<base::SingleThreadTaskRunner> io_task_runner) { + return std::make_unique<BlobTaskProxy>(std::move(blob_context_getter), + io_task_runner); +} + +BlobTaskProxy::BlobTaskProxy( + BlobContextGetter blob_context_getter, + scoped_refptr<base::SingleThreadTaskRunner> io_task_runner) + : main_task_runner_(base::ThreadTaskRunnerHandle::Get()), + io_task_runner_(io_task_runner), + weak_ptr_factory_(this) { + // Unretained the raw pointer because owner on UI thread should destroy this + // object on IO thread. + io_task_runner_->PostTask( + FROM_HERE, + base::BindOnce(&BlobTaskProxy::InitializeOnIO, base::Unretained(this), + std::move(blob_context_getter))); +} + +BlobTaskProxy::~BlobTaskProxy() { + io_task_runner_->BelongsToCurrentThread(); +} + +void BlobTaskProxy::InitializeOnIO(BlobContextGetter blob_context_getter) { + io_task_runner_->BelongsToCurrentThread(); + blob_storage_context_ = std::move(blob_context_getter).Run(); +} + +void BlobTaskProxy::SaveAsBlob(std::unique_ptr<std::string> data, + BlobDataHandleCallback callback) { + // Unretained the raw pointer because owner on UI thread should destroy this + // object on IO thread. + io_task_runner_->PostTask( + FROM_HERE, + base::BindOnce(&BlobTaskProxy::SaveAsBlobOnIO, base::Unretained(this), + std::move(data), std::move(callback))); +} + +void BlobTaskProxy::SaveAsBlobOnIO(std::unique_ptr<std::string> data, + BlobDataHandleCallback callback) { + io_task_runner_->BelongsToCurrentThread(); + + // Build blob data. + std::string blob_uuid = base::GenerateGUID(); + storage::BlobDataBuilder builder(blob_uuid); + builder.AppendData(*data.get()); + blob_data_handle_ = blob_storage_context_->AddFinishedBlob(builder); + + // Wait for blob data construction complete. + auto cb = base::BindRepeating(&BlobTaskProxy::BlobSavedOnIO, + weak_ptr_factory_.GetWeakPtr(), + base::Passed(std::move(callback))); + blob_data_handle_->RunOnConstructionComplete(cb); +} + +void BlobTaskProxy::BlobSavedOnIO(BlobDataHandleCallback callback, + storage::BlobStatus status) { + io_task_runner_->BelongsToCurrentThread(); + + // Relay BlobDataHandle and |status| back to main thread. + auto cb = base::BindOnce(std::move(callback), + base::Passed(std::move(blob_data_handle_)), status); + main_task_runner_->PostTask(FROM_HERE, std::move(cb)); +} + +} // namespace download
diff --git a/components/download/internal/blob_task_proxy.h b/components/download/internal/blob_task_proxy.h new file mode 100644 index 0000000..e757554 --- /dev/null +++ b/components/download/internal/blob_task_proxy.h
@@ -0,0 +1,75 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef COMPONENTS_DOWNLOAD_INTERNAL_BLOB_TASK_PROXY_H_ +#define COMPONENTS_DOWNLOAD_INTERNAL_BLOB_TASK_PROXY_H_ + +#include <memory> +#include <string> + +#include "base/callback.h" +#include "base/macros.h" +#include "base/memory/weak_ptr.h" +#include "base/single_thread_task_runner.h" +#include "storage/common/blob_storage/blob_storage_constants.h" + +namespace storage { +class BlobDataHandle; +class BlobStorageContext; +} // namespace storage + +namespace download { + +// Proxy for blob related task on IO thread. +// Created on main thread and do work on IO thread, destroyed on IO thread. +class BlobTaskProxy { + public: + using BlobContextGetter = + base::OnceCallback<base::WeakPtr<storage::BlobStorageContext>()>; + using BlobDataHandleCallback = + base::OnceCallback<void(std::unique_ptr<storage::BlobDataHandle>, + storage::BlobStatus status)>; + + static std::unique_ptr<BlobTaskProxy> Create( + BlobContextGetter blob_context_getter, + scoped_refptr<base::SingleThreadTaskRunner> io_task_runner); + + BlobTaskProxy(BlobContextGetter blob_context_getter, + scoped_refptr<base::SingleThreadTaskRunner> io_task_runner); + ~BlobTaskProxy(); + + // Save blob data on UI thread. |callback| will be called on main thread after + // blob construction completes. + void SaveAsBlob(std::unique_ptr<std::string> data, + BlobDataHandleCallback callback); + + private: + void InitializeOnIO(BlobContextGetter blob_context_getter); + + void SaveAsBlobOnIO(std::unique_ptr<std::string> data, + BlobDataHandleCallback callback); + + void BlobSavedOnIO(BlobDataHandleCallback callback, + storage::BlobStatus status); + + scoped_refptr<base::SingleThreadTaskRunner> main_task_runner_; + + // Used to build blob data, must accessed on |io_task_runner_|. + base::WeakPtr<storage::BlobStorageContext> blob_storage_context_; + + // Used to access blob storage context. + scoped_refptr<base::SingleThreadTaskRunner> io_task_runner_; + + // BlobDataHandle that will be eventually passed to main thread. + std::unique_ptr<storage::BlobDataHandle> blob_data_handle_; + + // Bounded to IO thread task runner. + base::WeakPtrFactory<BlobTaskProxy> weak_ptr_factory_; + + DISALLOW_COPY_AND_ASSIGN(BlobTaskProxy); +}; + +} // namespace download + +#endif // COMPONENTS_DOWNLOAD_INTERNAL_BLOB_TASK_PROXY_H_
diff --git a/components/download/internal/in_memory_download.cc b/components/download/internal/in_memory_download.cc new file mode 100644 index 0000000..d1d0e55 --- /dev/null +++ b/components/download/internal/in_memory_download.cc
@@ -0,0 +1,162 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "components/download/internal/in_memory_download.h" + +#include <memory> + +#include "base/bind.h" +#include "base/strings/string_util.h" +#include "components/download/internal/blob_task_proxy.h" +#include "net/base/io_buffer.h" +#include "net/base/net_errors.h" +#include "net/http/http_status_code.h" +#include "net/traffic_annotation/network_traffic_annotation.h" +#include "net/url_request/url_fetcher.h" +#include "storage/browser/blob/blob_data_handle.h" +#include "storage/browser/blob/blob_storage_context.h" + +namespace download { + +namespace { + +// Converts a string to HTTP method used by URLFetcher. +net::URLFetcher::RequestType ToRequestType(const std::string& method) { + // Only supports GET and POST. + if (base::EqualsCaseInsensitiveASCII(method, "GET")) + return net::URLFetcher::RequestType::GET; + if (base::EqualsCaseInsensitiveASCII(method, "POST")) + return net::URLFetcher::RequestType::POST; + + NOTREACHED(); + return net::URLFetcher::RequestType::GET; +} + +} // namespace + +InMemoryDownload::InMemoryDownload( + const std::string& guid, + const RequestParams& request_params, + const net::NetworkTrafficAnnotationTag& traffic_annotation, + Delegate* delegate, + scoped_refptr<net::URLRequestContextGetter> request_context_getter, + BlobTaskProxy::BlobContextGetter blob_context_getter, + scoped_refptr<base::SingleThreadTaskRunner> io_task_runner) + : guid_(guid), + request_params_(request_params), + traffic_annotation_(traffic_annotation), + request_context_getter_(request_context_getter), + blob_task_proxy_(BlobTaskProxy::Create(std::move(blob_context_getter), + io_task_runner)), + io_task_runner_(io_task_runner), + state_(State::INITIAL), + delegate_(delegate), + bytes_downloaded_(0u), + weak_ptr_factory_(this) { + DCHECK(!guid_.empty()); +} + +InMemoryDownload::~InMemoryDownload() { + io_task_runner_->DeleteSoon(FROM_HERE, blob_task_proxy_.release()); +} + +void InMemoryDownload::Start() { + DCHECK(state_ == State::INITIAL); + url_fetcher_ = net::URLFetcher::Create(request_params_.url, + ToRequestType(request_params_.method), + this, traffic_annotation_); + url_fetcher_->SetRequestContext(request_context_getter_.get()); + url_fetcher_->SetExtraRequestHeaders( + request_params_.request_headers.ToString()); + url_fetcher_->Start(); + state_ = State::IN_PROGRESS; +} + +std::unique_ptr<storage::BlobDataHandle> InMemoryDownload::ResultAsBlob() { + DCHECK(state_ == State::COMPLETE || state_ == State::FAILED); + // Return a copy. + return std::make_unique<storage::BlobDataHandle>(*blob_data_handle_); +} + +void InMemoryDownload::OnURLFetchDownloadProgress( + const net::URLFetcher* source, + int64_t current, + int64_t total, + int64_t current_network_bytes) { + bytes_downloaded_ = current; + + if (delegate_) + delegate_->OnDownloadProgress(this); +} + +void InMemoryDownload::OnURLFetchComplete(const net::URLFetcher* source) { + switch (source->GetStatus().status()) { + case net::URLRequestStatus::Status::SUCCESS: + if (HandleResponseCode(source->GetResponseCode())) { + SaveAsBlob(); + return; + } + + state_ = State::FAILED; + NotifyDelegateDownloadComplete(); + return; + case net::URLRequestStatus::Status::IO_PENDING: + return; + case net::URLRequestStatus::Status::CANCELED: + case net::URLRequestStatus::Status::FAILED: + state_ = State::FAILED; + NotifyDelegateDownloadComplete(); + break; + } +} + +bool InMemoryDownload::HandleResponseCode(int response_code) { + switch (response_code) { + case -1: // Non-HTTP request. + case net::HTTP_OK: + case net::HTTP_NON_AUTHORITATIVE_INFORMATION: + case net::HTTP_PARTIAL_CONTENT: + case net::HTTP_CREATED: + case net::HTTP_ACCEPTED: + case net::HTTP_NO_CONTENT: + case net::HTTP_RESET_CONTENT: + return true; + // All other codes are considered as failed. + default: + return false; + } +} + +void InMemoryDownload::SaveAsBlob() { + DCHECK(url_fetcher_); + + // This will copy the internal memory in |url_fetcher| into |data|. + // TODO(xingliu): Use response writer to avoid one extra copies. And destroy + // |url_fetcher_| at the correct time. + std::unique_ptr<std::string> data = std::make_unique<std::string>(); + DCHECK(url_fetcher_->GetResponseAsString(data.get())); + + auto callback = base::BindOnce(&InMemoryDownload::OnSaveBlobDone, + weak_ptr_factory_.GetWeakPtr()); + blob_task_proxy_->SaveAsBlob(std::move(data), std::move(callback)); +} + +void InMemoryDownload::OnSaveBlobDone( + std::unique_ptr<storage::BlobDataHandle> blob_handle, + storage::BlobStatus status) { + // |status| is valid on IO thread, consumer of |blob_handle| should validate + // the data when using the blob data. + state_ = + (status == storage::BlobStatus::DONE) ? State::COMPLETE : State::FAILED; + blob_data_handle_ = std::move(blob_handle); + + NotifyDelegateDownloadComplete(); +} + +void InMemoryDownload::NotifyDelegateDownloadComplete() { + if (delegate_) + delegate_->OnDownloadComplete(this); +} + +} // namespace download
diff --git a/components/download/internal/in_memory_download.h b/components/download/internal/in_memory_download.h new file mode 100644 index 0000000..f499758e --- /dev/null +++ b/components/download/internal/in_memory_download.h
@@ -0,0 +1,163 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef COMPONENTS_DOWNLOAD_INTERNAL_IN_MEMORY_DOWNLOAD_H_ +#define COMPONENTS_DOWNLOAD_INTERNAL_IN_MEMORY_DOWNLOAD_H_ + +#include <memory> +#include <string> + +#include "base/callback.h" +#include "base/macros.h" +#include "base/memory/weak_ptr.h" +#include "base/single_thread_task_runner.h" +#include "components/download/internal/blob_task_proxy.h" +#include "components/download/public/download_params.h" +#include "net/base/completion_callback.h" +#include "net/url_request/url_fetcher_delegate.h" +#include "net/url_request/url_request_context_getter.h" + +namespace net { +class URLFetcher; +struct NetworkTrafficAnnotationTag; +} // namespace net + +namespace storage { +class BlobDataHandle; +} // namespace storage + +namespace download { + +struct RequestParams; + +// Object to start a single download and hold in-memory download data. +// Used by download service in Incognito mode, where download files shouldn't +// be persisted to disk. +// +// Life cycle: The object is created before creating the network request. +// Call Start() to send the network request. +// +// Threading contract: +// 1. This object lives on the main thread. +// 2. Reading/writing IO buffer from network is done on another thread, +// based on |request_context_getter_|. When complete, main thread is notified. +// 3. After network IO is done, Blob related work is done on IO thread with +// |blob_task_proxy_|, then notify the result to main thread. + +class InMemoryDownload : public net::URLFetcherDelegate { + public: + // Report download progress with in-memory download backend. + class Delegate { + public: + virtual void OnDownloadProgress(InMemoryDownload* download) = 0; + virtual void OnDownloadComplete(InMemoryDownload* download) = 0; + + protected: + virtual ~Delegate() = default; + }; + + // States of the download. + enum class State { + // The object is created but network request has not been sent. + INITIAL, + + // Download is in progress, including the following procedures. + // 1. Transfer network data. + // 2. Save to blob storage. + IN_PROGRESS, + + // The download can fail due to: + // 1. network layer failure or unsuccessful HTTP server response code. + // 2. Blob system failures after blob construction is done. + FAILED, + + // Download is completed, and data is successfully saved as a blob. + // 1. We guarantee the states of network responses. + // 2. Do not guarantee the state of blob data. The consumer of blob + // should validate its state when using it on IO thread. + COMPLETE, + }; + + InMemoryDownload( + const std::string& guid, + const RequestParams& request_params, + const net::NetworkTrafficAnnotationTag& traffic_annotation, + Delegate* delegate, + scoped_refptr<net::URLRequestContextGetter> request_context_getter, + BlobTaskProxy::BlobContextGetter blob_context_getter, + scoped_refptr<base::SingleThreadTaskRunner> io_task_runner); + ~InMemoryDownload() override; + + // Send the download request. + void Start(); + + // Get a copy of blob data handle. + std::unique_ptr<storage::BlobDataHandle> ResultAsBlob(); + + const std::string& guid() const { return guid_; } + uint64_t bytes_downloaded() const { return bytes_downloaded_; } + State state() const { return state_; } + + private: + // net::URLFetcherDelegate implementation. + void OnURLFetchDownloadProgress(const net::URLFetcher* source, + int64_t current, + int64_t total, + int64_t current_network_bytes) override; + void OnURLFetchComplete(const net::URLFetcher* source) override; + + // Handles response code and change the state accordingly. + // Returns if the response code is considered as successful code. + bool HandleResponseCode(int response_code); + + // Saves the download data into blob storage. + void SaveAsBlob(); + void OnSaveBlobDone(std::unique_ptr<storage::BlobDataHandle> blob_handle, + storage::BlobStatus status); + + // Notifies the delegate about completion. + void NotifyDelegateDownloadComplete(); + + // GUID of the download. + const std::string guid_; + + // Request parameters of the download. + const RequestParams request_params_; + + // Traffic annotation of the request. + const net::NetworkTrafficAnnotationTag traffic_annotation_; + + // Used to send requests to servers. Also contains the download data in its + // string buffer. We should avoid extra copy on the data and release the + // memory when needed. + std::unique_ptr<net::URLFetcher> url_fetcher_; + + // Request context getter used by |url_fetcher_|. + scoped_refptr<net::URLRequestContextGetter> request_context_getter_; + + // Worker that does blob related task on IO thread. + std::unique_ptr<BlobTaskProxy> blob_task_proxy_; + + // Owned blob data handle, so that blob system keeps at least one reference + // count of the underlying data. + std::unique_ptr<storage::BlobDataHandle> blob_data_handle_; + + // Used to access blob storage context. + scoped_refptr<base::SingleThreadTaskRunner> io_task_runner_; + + State state_; + + Delegate* delegate_; + + uint64_t bytes_downloaded_; + + // Bounded to main thread task runner. + base::WeakPtrFactory<InMemoryDownload> weak_ptr_factory_; + + DISALLOW_COPY_AND_ASSIGN(InMemoryDownload); +}; + +} // namespace download + +#endif // COMPONENTS_DOWNLOAD_INTERNAL_IN_MEMORY_DOWNLOAD_H_
diff --git a/components/download/internal/in_memory_download_unittest.cc b/components/download/internal/in_memory_download_unittest.cc new file mode 100644 index 0000000..dce0b15 --- /dev/null +++ b/components/download/internal/in_memory_download_unittest.cc
@@ -0,0 +1,127 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "components/download/internal/in_memory_download.h" + +#include "base/files/file_util.h" +#include "base/guid.h" +#include "base/path_service.h" +#include "base/run_loop.h" +#include "base/threading/thread.h" +#include "net/test/embedded_test_server/embedded_test_server.h" +#include "net/traffic_annotation/network_traffic_annotation_test_helper.h" +#include "net/url_request/url_request_test_util.h" +#include "storage/browser/blob/blob_storage_context.h" +#include "testing/gmock/include/gmock/gmock.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace download { +namespace { + +class MockDelegate : public InMemoryDownload::Delegate { + public: + MockDelegate() = default; + + void WaitForCompletion() { + DCHECK(!run_loop_.running()); + run_loop_.Run(); + } + + // InMemoryDownload::Delegate implementation. + MOCK_METHOD1(OnDownloadProgress, void(InMemoryDownload*)); + void OnDownloadComplete(InMemoryDownload* download) { + if (run_loop_.running()) + run_loop_.Quit(); + } + + private: + base::RunLoop run_loop_; + + DISALLOW_COPY_AND_ASSIGN(MockDelegate); +}; + +// Must run on IO thread task runner. +base::WeakPtr<storage::BlobStorageContext> BlobStorageContextGetter( + storage::BlobStorageContext* blob_context) { + DCHECK(blob_context); + return blob_context->AsWeakPtr(); +} + +class InMemoryDownloadTest : public testing::Test { + public: + InMemoryDownloadTest() = default; + ~InMemoryDownloadTest() override = default; + + void SetUp() override { + test_server_.ServeFilesFromDirectory(GetTestDataDirectory()); + ASSERT_TRUE(test_server_.Start()); + + io_thread_.reset(new base::Thread("Network and Blob IO thread")); + base::Thread::Options options(base::MessageLoop::TYPE_IO, 0); + io_thread_->StartWithOptions(options); + request_context_getter_ = + new net::TestURLRequestContextGetter(io_thread_->task_runner()); + blob_storage_context_ = std::make_unique<storage::BlobStorageContext>(); + } + + void TearDown() override { + // Say goodbye to |blob_storage_context_| on IO thread. + io_thread_->task_runner()->DeleteSoon(FROM_HERE, + blob_storage_context_.release()); + } + + protected: + base::FilePath GetTestDataDirectory() { + base::FilePath test_data_dir; + EXPECT_TRUE(base::PathService::Get(base::DIR_SOURCE_ROOT, &test_data_dir)); + return test_data_dir.AppendASCII("components/test/data/download"); + } + + // Helper method to create a download with request_params. + void CreateDownload(const RequestParams& request_params) { + download_ = std::make_unique<InMemoryDownload>( + base::GenerateGUID(), request_params, TRAFFIC_ANNOTATION_FOR_TESTS, + delegate(), request_context_getter_, + base::BindOnce(&BlobStorageContextGetter, blob_storage_context_.get()), + io_thread_->task_runner()); + } + + InMemoryDownload* download() { return download_.get(); } + MockDelegate* delegate() { return &mock_delegate_; } + net::EmbeddedTestServer* test_server() { return &test_server_; } + + private: + // IO thread used by network and blob IO tasks. + std::unique_ptr<base::Thread> io_thread_; + + // Message loop for the main thread. + base::MessageLoop main_loop; + + std::unique_ptr<InMemoryDownload> download_; + MockDelegate mock_delegate_; + + scoped_refptr<net::TestURLRequestContextGetter> request_context_getter_; + std::unique_ptr<storage::BlobStorageContext> blob_storage_context_; + net::EmbeddedTestServer test_server_; + + DISALLOW_COPY_AND_ASSIGN(InMemoryDownloadTest); +}; + +TEST_F(InMemoryDownloadTest, DownloadTest) { + RequestParams request_params; + request_params.url = test_server()->GetURL("/text_data.json"); + CreateDownload(request_params); + download()->Start(); + delegate()->WaitForCompletion(); + + base::FilePath path = GetTestDataDirectory().AppendASCII("text_data.json"); + std::string data; + EXPECT_TRUE(ReadFileToString(path, &data)); + EXPECT_EQ(InMemoryDownload::State::COMPLETE, download()->state()); + // TODO(xingliu): Read the blob and verify data. +} + +} // namespace + +} // namespace download
diff --git a/components/payments/content/payment_request_dialog.h b/components/payments/content/payment_request_dialog.h index 04603fa..e334129 100644 --- a/components/payments/content/payment_request_dialog.h +++ b/components/payments/content/payment_request_dialog.h
@@ -25,8 +25,12 @@ virtual void ShowErrorMessage() = 0; + // Shows a "Processing..." spinner. virtual void ShowProcessingSpinner() = 0; + // Whether a "Processing..." spinner is showing. + virtual bool IsInteractive() const = 0; + // Shows the CVC unmask sheet and starts a FullCardRequest with the info // entered by the user. virtual void ShowCvcUnmaskPrompt(
diff --git a/components/payments/content/payment_request_spec.h b/components/payments/content/payment_request_spec.h index d95c3fe..4bcdf972 100644 --- a/components/payments/content/payment_request_spec.h +++ b/components/payments/content/payment_request_spec.h
@@ -82,6 +82,8 @@ bool request_payer_email() const override; PaymentShippingType shipping_type() const override; + bool supports_basic_card() const { return !supported_card_networks_.empty(); } + const std::vector<std::string>& supported_card_networks() const { return supported_card_networks_; }
diff --git a/components/sync_sessions/sessions_sync_manager.cc b/components/sync_sessions/sessions_sync_manager.cc index efa9b68c..9972d472 100644 --- a/components/sync_sessions/sessions_sync_manager.cc +++ b/components/sync_sessions/sessions_sync_manager.cc
@@ -79,7 +79,8 @@ } std::string TabNodeIdToTag(const std::string& machine_tag, int tab_node_id) { - CHECK_GT(tab_node_id, TabNodePool::kInvalidTabNodeID) << "crbug.com/673618"; + CHECK_GT(tab_node_id, TabNodePool::kInvalidTabNodeID) + << "https://crbug.com/639009"; return base::StringPrintf("%s %d", machine_tag.c_str(), tab_node_id); } @@ -251,7 +252,7 @@ #endif // Check if anything has changed on the local client side. - AssociateWindows(RELOAD_TABS, &new_changes); + AssociateWindows(RELOAD_TABS, ScanForTabbedWindow(), &new_changes); local_tab_pool_out_of_sync_ = false; merge_result.set_error( @@ -263,6 +264,7 @@ void SessionsSyncManager::AssociateWindows( ReloadTabsOption option, + bool has_tabbed_window, syncer::SyncChangeList* change_output) { // Note that |current_session| is a pointer owned by |session_tracker_|. // |session_tracker_| will continue to update |current_session| under @@ -280,18 +282,10 @@ SyncedWindowDelegatesGetter::SyncedWindowDelegateMap windows = synced_window_delegates_getter()->GetSyncedWindowDelegates(); - // On Android, it's possible to not have any tabbed windows if this is a cold - // start triggered for a custom tab. In that case, the previous session must - // be restored, otherwise it will be lost. On the other hand, if there is at - // least one tabbed window open, it's safe to overwrite the previous session - // entirely. See crbug.com/639009 for more info. - bool found_tabbed_window = false; - for (auto& window_iter_pair : windows) { - if (window_iter_pair.second->IsTypeTabbed()) - found_tabbed_window = true; - } - - if (found_tabbed_window) { + // Without native data, we need be careful not to obliterate any old + // information, while at the same time handling updated tab ids. See + // https://crbug.com/639009 for more info. + if (has_tabbed_window) { // Just reset the session tracking. No need to worry about the previous // session; the current tabbed windows are now the source of truth. session_tracker_.ResetSessionTracking(current_machine_tag()); @@ -326,6 +320,9 @@ } } + // TODO(skym): Scan for duplicate sync ids and remove, + // https://crbug.com/639009. + for (auto& window_iter_pair : windows) { const SyncedWindowDelegate* window_delegate = window_iter_pair.second; if (option == RELOAD_TABS) { @@ -340,7 +337,6 @@ // about to be deleted, so we ignore it. if (window_delegate->ShouldSync() && window_delegate->GetTabCount() && window_delegate->HasWindow()) { - sync_pb::SessionWindow window_s; SessionID::id_type window_id = window_delegate->GetSessionId(); DVLOG(1) << "Associating window " << window_id << " with " << window_delegate->GetTabCount() << " tabs."; @@ -372,7 +368,7 @@ DVLOG(1) << "Placeholder tab " << tab_id << " has no sync id."; } } else if (RELOAD_TABS == option) { - AssociateTab(synced_tab, change_output); + AssociateTab(synced_tab, has_tabbed_window, change_output); } // If the tab was syncable, it would have been added to the tracker @@ -432,6 +428,7 @@ } void SessionsSyncManager::AssociateTab(SyncedTabDelegate* const tab_delegate, + bool has_tabbed_window, syncer::SyncChangeList* change_output) { DCHECK(!tab_delegate->IsPlaceholderTab()); @@ -457,11 +454,20 @@ if (session_tracker_.IsLocalTabNodeAssociated(tab_delegate->GetSyncId())) { tab_node_id = tab_delegate->GetSyncId(); session_tracker_.ReassociateLocalTab(tab_node_id, tab_id); - } else { + } else if (has_tabbed_window) { existing_tab_node = session_tracker_.GetTabNodeFromLocalTabId(tab_id, &tab_node_id); - CHECK_NE(TabNodePool::kInvalidTabNodeID, tab_node_id) << "crbug.com/673618"; + CHECK_NE(TabNodePool::kInvalidTabNodeID, tab_node_id) + << "https://crbug.com/639009"; tab_delegate->SetSyncId(tab_node_id); + } else { + // Only allowed to allocate sync ids when we have native data, which is only + // true when we have a tabbed window. Without a sync id we cannot sync this + // data, the tracker cannot even really track it. So don't do any more work. + // This effectively breaks syncing custom tabs when the native browser isn't + // fully loaded. Ideally this is fixed by saving tab data and sync data + // atomically, see https://crbug.com/681921. + return; } sessions::SessionTab* session_tab = @@ -604,13 +610,14 @@ return; } + bool found_tabbed_window = ScanForTabbedWindow(); syncer::SyncChangeList changes; - AssociateTab(modified_tab, &changes); + AssociateTab(modified_tab, found_tabbed_window, &changes); // Note, we always associate windows because it's possible a tab became // "interesting" by going to a valid URL, in which case it needs to be added // to the window's tab information. Similarly, if a tab became // "uninteresting", we remove it from the window's tab information. - AssociateWindows(DONT_RELOAD_TABS, &changes); + AssociateWindows(DONT_RELOAD_TABS, found_tabbed_window, &changes); sync_processor_->ProcessSyncChanges(FROM_HERE, changes); } @@ -658,7 +665,7 @@ for (auto& tab : win_iter.second->wrapped_window.tabs) { // TODO(zea): replace with with the correct tab node id once there's a // sync specific wrapper for SessionTab. This method is only used in - // tests though, so it's fine for now. crbug.com/662597 + // tests though, so it's fine for now. https://crbug.com/662597 int tab_node_id = 0; sync_pb::EntitySpecifics entity; entity.mutable_session()->CopyFrom( @@ -801,7 +808,7 @@ // to that foreign data (like deletion through garbage collection) to // trigger a data type error because the tag looking mechanism fails. So // look for these and delete via remote SyncData, which uses a server id - // lookup mechanism instead, see crbug.com/604657. + // lookup mechanism instead, see https://crbug.com/604657. bad_foreign_hash_count++; new_changes->push_back( syncer::SyncChange(FROM_HERE, SyncChange::ACTION_DELETE, remote)); @@ -1400,4 +1407,25 @@ } } +bool SessionsSyncManager::ScanForTabbedWindow() { + for (auto& window_iter_pair : + synced_window_delegates_getter()->GetSyncedWindowDelegates()) { + if (window_iter_pair.second->IsTypeTabbed()) { + const SyncedWindowDelegate* window_delegate = window_iter_pair.second; + if (window_delegate->ShouldSync() && window_delegate->GetTabCount() && + window_delegate->HasWindow()) { + // When only custom tab windows are open, often we'll have a seemingly + // okay type tabbed window, but GetTabAt will return null for each + // index. This case is exactly what this method needs to protect + // against. + for (int j = 0; j < window_delegate->GetTabCount(); ++j) { + if (window_delegate->GetTabAt(j)) + return true; + } + } + } + } + return false; +} + }; // namespace sync_sessions
diff --git a/components/sync_sessions/sessions_sync_manager.h b/components/sync_sessions/sessions_sync_manager.h index a42a1fd1..eea4a2f 100644 --- a/components/sync_sessions/sessions_sync_manager.h +++ b/components/sync_sessions/sessions_sync_manager.h
@@ -225,13 +225,16 @@ // changes for processing later. enum ReloadTabsOption { RELOAD_TABS, DONT_RELOAD_TABS }; void AssociateWindows(ReloadTabsOption option, + bool has_tabbed_window, syncer::SyncChangeList* change_output); // Loads and reassociates the local tabs referenced in |tabs|. // |change_output| *must* be provided as a link to the SyncChange pipeline // that exists in the caller's context. This function will append necessary - // changes for processing later. + // changes for processing later. Will only assign a new sync id if there is + // a tabbed window, which results in failure for tabs without sync ids yet. void AssociateTab(SyncedTabDelegate* const tab, + bool has_tabbed_window, syncer::SyncChangeList* change_output); // Set |session_tab| from |tab_delegate| and |mtime|. @@ -282,7 +285,7 @@ // specifics is the model type, ie us. We need to generate the tag because it // is not passed over the wire for remote data. The use case this function was // created for is detecting bad tag hashes from remote data, see - // crbug.com/604657. + // https://crbug.com/604657. static std::string TagHashFromSpecifics( const sync_pb::SessionSpecifics& specifics); @@ -292,6 +295,12 @@ void CleanupNavigationTracking(); + // On Android, it's possible to not have any tabbed windows when only custom + // tabs are currently open. This means that there is tab data that will be + // restored later, but we cannot access it. This method is an elaborate way to + // check if we're currently in that state or not. + bool ScanForTabbedWindow(); + // The client of this sync sessions datatype. SyncSessionsClient* const sessions_client_;
diff --git a/components/sync_sessions/sessions_sync_manager_unittest.cc b/components/sync_sessions/sessions_sync_manager_unittest.cc index 325edf7..c47117a 100644 --- a/components/sync_sessions/sessions_sync_manager_unittest.cc +++ b/components/sync_sessions/sessions_sync_manager_unittest.cc
@@ -1025,6 +1025,17 @@ ASSERT_EQ( restored_tab_id, out[1].sync_data().GetSpecifics().session().header().window(0).tab(0)); + out.clear(); + + // Now actually resurrect the native data, which will end up having different + // native ids, but the tab has the same sync id as before. + AddWindow()->OverrideTabAt(0, tab); + NavigateTab(tab, kBar1); + + ASSERT_TRUE(ChangeTypeMatches( + out, {SyncChange::ACTION_UPDATE, SyncChange::ACTION_UPDATE})); + VerifyLocalTabChange(out[0], 3, kBar1); + VerifyLocalHeaderChange(out[1], 1, 1); } // Ensure that tabbed windows from a previous session are preserved if only @@ -1055,49 +1066,36 @@ window->OverrideTabAt(0, custom_tab.get()); InitWithSyncDataTakeOutput(ConvertToRemote(in), &out); - // The previous session should be preserved, and the transient window should - // be synced as a new transient window. This means that the original tab - // node will be updated with its new tab id, a new tab node will be created, - // and the header will be updated to reflect the two windows and two tabs. - ASSERT_TRUE( - ChangeTypeMatches(out, {SyncChange::ACTION_UPDATE, SyncChange::ACTION_ADD, - SyncChange::ACTION_UPDATE})); + // The previous session should be preserved. The transient window cannot be + // synced because we do not have enough local data to ensure that we wouldn't + // vend the same sync id if our persistent storage didn't match upon the last + // shutdown. + ASSERT_TRUE(ChangeTypeMatches( + out, {SyncChange::ACTION_UPDATE, SyncChange::ACTION_UPDATE})); VerifyLocalTabChange(out[0], 2, kFoo2); - VerifyLocalTabChange(out[1], 1, kBar1); - VerifyLocalHeaderChange(out[2], 2, 2); + VerifyLocalHeaderChange(out[1], 1, 1); + out.clear(); - // The two windows should have different window types. - ASSERT_EQ(sync_pb::SessionWindow::TYPE_CUSTOM_TAB, out[2] - .sync_data() - .GetSpecifics() - .session() - .header() - .window(0) - .browser_type()); - ASSERT_EQ(sync_pb::SessionWindow::TYPE_TABBED, out[2] - .sync_data() - .GetSpecifics() - .session() - .header() - .window(1) - .browser_type()); + // Now re-create local data and modify it. + TestSyncedWindowDelegate* alive_again = AddWindow(); + alive_again->OverrideTabAt(0, tab); + NavigateTab(tab, kBaz1); - // Verify the tab id of the restored tab is updated and consistent. - int restored_tab_id = - out[0].sync_data().GetSpecifics().session().tab().tab_id(); - // SessionId should be rewritten on restore. - ASSERT_NE(tab->GetSessionId(), restored_tab_id); - ASSERT_EQ( - restored_tab_id, - out[2].sync_data().GetSpecifics().session().header().window(1).tab(0)); + // The local change should be created and tracked correctly. This doesn't + // actually start syncing the custom tab yet, because the tab itself isn't + // associated yet. + ASSERT_TRUE(ChangeTypeMatches( + out, {SyncChange::ACTION_UPDATE, SyncChange::ACTION_UPDATE})); + VerifyLocalTabChange(out[0], 3, kBaz1); + VerifyLocalHeaderChange(out[1], 1, 1); + out.clear(); - // Verify the tab id of the custom tab is consistent. - int custom_tab_id = - out[1].sync_data().GetSpecifics().session().tab().tab_id(); - ASSERT_EQ(custom_tab->GetSessionId(), custom_tab_id); - ASSERT_EQ( - custom_tab_id, - out[2].sync_data().GetSpecifics().session().header().window(0).tab(0)); + // Now trigger OnLocalTabModified() for the custom tab again, it should sync. + NavigateTab(custom_tab.get(), kBar2); + ASSERT_TRUE(ChangeTypeMatches( + out, {SyncChange::ACTION_ADD, SyncChange::ACTION_UPDATE})); + VerifyLocalTabChange(out[0], 2, kBar2); + VerifyLocalHeaderChange(out[1], 2, 2); } // Tests MergeDataAndStartSyncing with sync data but no local data. @@ -1787,7 +1785,7 @@ // Verifies that we drop both headers and tabs during merge if their stored tag // hash doesn't match a computer tag hash. This mitigates potential failures -// while cleaning up bad foreign data, see crbug.com/604657. +// while cleaning up bad foreign data, see https://crbug.com/604657. TEST_F(SessionsSyncManagerTest, MergeDeletesBadHash) { SyncDataList foreign_data; std::vector<SessionID::id_type> empty_ids;
diff --git a/components/sync_sessions/synced_session_tracker.cc b/components/sync_sessions/synced_session_tracker.cc index 4b2975a..2a6960c 100644 --- a/components/sync_sessions/synced_session_tracker.cc +++ b/components/sync_sessions/synced_session_tracker.cc
@@ -296,7 +296,7 @@ // TODO(zea): remove this once PutTabInWindow isn't crashing anymore. CHECK(tab) << " Unable to find tab " << tab_id << " within unmapped tabs or previously mapped windows." - << " crbug.com/639009"; + << " https://crbug.com/639009"; } tab->window_id.set_id(window_id); @@ -316,7 +316,8 @@ sessions::SessionTab* SyncedSessionTracker::GetTab( const std::string& session_tag, SessionID::id_type tab_id) { - CHECK_NE(TabNodePool::kInvalidTabNodeID, tab_id) << "crbug.com/673618"; + CHECK_NE(TabNodePool::kInvalidTabNodeID, tab_id) + << "https://crbug.com/639009"; sessions::SessionTab* tab_ptr = nullptr; auto iter = synced_tab_map_[session_tag].find(tab_id); if (iter != synced_tab_map_[session_tag].end()) {
diff --git a/components/sync_sessions/synced_session_tracker.h b/components/sync_sessions/synced_session_tracker.h index 8426935..a8c9480f 100644 --- a/components/sync_sessions/synced_session_tracker.h +++ b/components/sync_sessions/synced_session_tracker.h
@@ -131,7 +131,7 @@ // |tab_id| for the session specified with |session_tag|. // Note: Ownership of the SessionTab remains within the SyncedSessionTracker. // TODO(zea): Replace SessionTab with a Sync specific wrapper. - // crbug.com/662597 + // https://crbug.com/662597 sessions::SessionTab* GetTab(const std::string& session_tag, SessionID::id_type tab_id);
diff --git a/components/sync_sessions/tab_node_pool.cc b/components/sync_sessions/tab_node_pool.cc index 1b4c1f88..19bdd43 100644 --- a/components/sync_sessions/tab_node_pool.cc +++ b/components/sync_sessions/tab_node_pool.cc
@@ -124,7 +124,7 @@ // If number of free nodes exceed kFreeNodesHighWatermark, // delete sync nodes till number reaches kFreeNodesLowWatermark. // Note: This logic is to mitigate temporary disassociation issues with old - // clients: http://crbug.com/259918. Newer versions do not need this. + // clients: https://crbug.com/259918. Newer versions do not need this. if (free_nodes_pool_.size() > kFreeNodesHighWatermark) { for (std::set<int>::iterator free_it = free_nodes_pool_.begin(); free_it != free_nodes_pool_.end();) {
diff --git a/components/test/data/download/text_data.json b/components/test/data/download/text_data.json new file mode 100644 index 0000000..369f7de --- /dev/null +++ b/components/test/data/download/text_data.json
@@ -0,0 +1,3 @@ +{ + "data":"In earlier tellings, the dog had a better reputation than the cat, however the president veto it." +} \ No newline at end of file
diff --git a/components/viz/common/display/renderer_settings.h b/components/viz/common/display/renderer_settings.h index d78867d..653b258 100644 --- a/components/viz/common/display/renderer_settings.h +++ b/components/viz/common/display/renderer_settings.h
@@ -30,6 +30,7 @@ bool show_overdraw_feedback = false; bool enable_draw_occlusion = false; bool use_skia_renderer = false; + bool dont_round_texture_sizes_for_pixel_tests = false; int highp_threshold_min = 0; // Determines whether we disallow non-exact matches when finding resources
diff --git a/components/viz/service/display/direct_renderer.cc b/components/viz/service/display/direct_renderer.cc index f49f853d..9d022c6 100644 --- a/components/viz/service/display/direct_renderer.cc +++ b/components/viz/service/display/direct_renderer.cc
@@ -657,9 +657,18 @@ return render_pass->damage_rect; } -// static gfx::Size DirectRenderer::RenderPassTextureSize(const RenderPass* render_pass) { - return render_pass->output_rect.size(); + // Round the size of the render pass backings to a multiple of 64 pixels. This + // reduces memory fragmentation. https://crbug.com/146070. This also allows + // backings to be more easily reused during a resize operation. + int width = render_pass->output_rect.width(); + int height = render_pass->output_rect.height(); + if (!settings_->dont_round_texture_sizes_for_pixel_tests) { + int multiple = 64; + width = cc::MathUtil::CheckedRoundUp(width, multiple); + height = cc::MathUtil::CheckedRoundUp(height, multiple); + } + return gfx::Size(width, height); } void DirectRenderer::SetCurrentFrameForTesting(const DrawingFrame& frame) {
diff --git a/components/viz/service/display/direct_renderer.h b/components/viz/service/display/direct_renderer.h index f6fe330..ef89a16f 100644 --- a/components/viz/service/display/direct_renderer.h +++ b/components/viz/service/display/direct_renderer.h
@@ -131,7 +131,7 @@ const gfx::Rect& render_pass_scissor); void SetScissorTestRectInDrawSpace(const gfx::Rect& draw_space_rect); - static gfx::Size RenderPassTextureSize(const RenderPass* render_pass); + gfx::Size RenderPassTextureSize(const RenderPass* render_pass); void FlushPolygons( base::circular_deque<std::unique_ptr<DrawPolygon>>* poly_list,
diff --git a/components/viz/service/display/gl_renderer.cc b/components/viz/service/display/gl_renderer.cc index 31622f8..7f47941 100644 --- a/components/viz/service/display/gl_renderer.cc +++ b/components/viz/service/display/gl_renderer.cc
@@ -3347,11 +3347,15 @@ // Round the size of the IOSurface to a multiple of 64 pixels. This reduces // memory fragmentation. https://crbug.com/146070. This also allows IOSurfaces // to be more easily reused during a resize operation. - uint32_t iosurface_multiple = 64; - uint32_t iosurface_width = cc::MathUtil::UncheckedRoundUp( - static_cast<uint32_t>(updated_dst_rect.width()), iosurface_multiple); - uint32_t iosurface_height = cc::MathUtil::UncheckedRoundUp( - static_cast<uint32_t>(updated_dst_rect.height()), iosurface_multiple); + uint32_t iosurface_width = static_cast<uint32_t>(updated_dst_rect.width()); + uint32_t iosurface_height = static_cast<uint32_t>(updated_dst_rect.height()); + if (!settings_->dont_round_texture_sizes_for_pixel_tests) { + uint32_t iosurface_multiple = 64; + iosurface_width = + cc::MathUtil::CheckedRoundUp(iosurface_width, iosurface_multiple); + iosurface_height = + cc::MathUtil::CheckedRoundUp(iosurface_height, iosurface_multiple); + } *resource = overlay_resource_pool_->AcquireResource( gfx::Size(iosurface_width, iosurface_height), ResourceFormat::RGBA_8888,
diff --git a/content/browser/compositor/viz_process_transport_factory.cc b/content/browser/compositor/viz_process_transport_factory.cc index 44f6ff0..75ee4ab 100644 --- a/content/browser/compositor/viz_process_transport_factory.cc +++ b/content/browser/compositor/viz_process_transport_factory.cc
@@ -72,18 +72,12 @@ gpu::SharedMemoryLimits(), attributes, nullptr /* share_context */, type); } -bool CheckContextLost(viz::ContextProvider* context_provider) { - if (!context_provider) - return false; - +bool IsContextLost(viz::ContextProvider* context_provider) { return context_provider->ContextGL()->GetGraphicsResetStatusKHR() != GL_NO_ERROR; } -bool CheckWorkerContextLost(viz::RasterContextProvider* context_provider) { - if (!context_provider) - return false; - +bool IsWorkerContextLost(viz::RasterContextProvider* context_provider) { viz::RasterContextProvider::ScopedRasterContextLock lock(context_provider); return lock.RasterInterface()->GetGraphicsResetStatusKHR() != GL_NO_ERROR; } @@ -124,6 +118,9 @@ } VizProcessTransportFactory::~VizProcessTransportFactory() { + if (main_context_provider_) + main_context_provider_->RemoveObserver(this); + task_graph_runner_->Shutdown(); } @@ -183,8 +180,15 @@ scoped_refptr<viz::ContextProvider> VizProcessTransportFactory::SharedMainThreadContextProvider() { - NOTIMPLEMENTED(); - return nullptr; + if (is_gpu_compositing_disabled_) + return nullptr; + + if (!main_context_provider_) { + CreateContextProviders( + gpu_channel_establish_factory_->EstablishGpuChannelSync()); + } + + return main_context_provider_; } void VizProcessTransportFactory::RemoveCompositor(ui::Compositor* compositor) { @@ -338,8 +342,7 @@ } viz::GLHelper* VizProcessTransportFactory::GetGLHelper() { - // TODO(kylechar): Figure out if GLHelper in the host process makes sense. - NOTREACHED(); + NOTREACHED(); // Readback happens in the GPU process and this isn't used. return nullptr; } @@ -367,8 +370,11 @@ OnLostMainThreadSharedContext(); // Drop our reference on the gpu contexts for the compositors. - shared_worker_context_provider_ = nullptr; - compositor_context_provider_ = nullptr; + worker_context_provider_ = nullptr; + if (main_context_provider_) { + main_context_provider_->RemoveObserver(this); + main_context_provider_ = nullptr; + } // Here we remove the FrameSink from every compositor that needs to fall back // to software compositing. @@ -394,11 +400,19 @@ } } +void VizProcessTransportFactory::OnContextLost() { + // TODO(kylechar): If the context is lost but the GPU process hasn't crashed + // then CompositorFrameSink data in HostFrameSinkManager (browser process) and + // FrameSinkManagerImpl (GPU process) needs to be cleaned up. + base::ThreadTaskRunnerHandle::Get()->PostTask( + FROM_HERE, + base::BindOnce(&VizProcessTransportFactory::OnLostMainThreadSharedContext, + weak_ptr_factory_.GetWeakPtr())); +} + void VizProcessTransportFactory::OnGpuProcessLost() { // Reconnect HostFrameSinkManager to new GPU process. ConnectHostFrameSinkManager(); - - OnLostMainThreadSharedContext(); } void VizProcessTransportFactory::OnEstablishedGpuChannel( @@ -429,8 +443,6 @@ compositor->widget()); #endif - // TODO(crbug.com/776050): Deal with context loss. - // Create interfaces for a root CompositorFrameSink. viz::mojom::CompositorFrameSinkAssociatedPtrInfo sink_info; viz::mojom::CompositorFrameSinkAssociatedRequest sink_request = @@ -476,9 +488,8 @@ scoped_refptr<viz::RasterContextProvider> worker_context; if (gpu_compositing) { // Only pass the contexts to the compositor if it will use gpu compositing. - compositor_context = compositor_context_provider_; - if (shared_worker_context_provider_) - worker_context = shared_worker_context_provider_; + compositor_context = main_context_provider_; + worker_context = worker_context_provider_; } compositor->SetLayerTreeFrameSink( std::make_unique<viz::ClientLayerTreeFrameSink>( @@ -499,38 +510,46 @@ constexpr bool kCompositorContextSupportsGLES2 = true; constexpr bool kCompositorContextSupportsRaster = false; - if (CheckContextLost(compositor_context_provider_.get())) - compositor_context_provider_ = nullptr; + if (main_context_provider_ && IsContextLost(main_context_provider_.get())) { + main_context_provider_->RemoveObserver(this); + main_context_provider_ = nullptr; + } - if (CheckWorkerContextLost(shared_worker_context_provider_.get())) - shared_worker_context_provider_ = nullptr; + if (worker_context_provider_ && + IsWorkerContextLost(worker_context_provider_.get())) + worker_context_provider_ = nullptr; - if (!shared_worker_context_provider_) { - shared_worker_context_provider_ = CreateContextProviderImpl( + if (!worker_context_provider_) { + worker_context_provider_ = CreateContextProviderImpl( gpu_channel_host, GetGpuMemoryBufferManager(), kSharedWorkerContextSupportsLocking, kSharedWorkerContextSupportsGLES2, kSharedWorkerContextSupportsRaster, ui::command_buffer_metrics::BROWSER_WORKER_CONTEXT); - auto result = shared_worker_context_provider_->BindToCurrentThread(); + // Don't observer context loss on |worker_context_provider_| here, that is + // already observered by LayerTreeFrameSink. The lost context will be caught + // when recreating LayerTreeFrameSink(s). + auto result = worker_context_provider_->BindToCurrentThread(); if (result != gpu::ContextResult::kSuccess) { - shared_worker_context_provider_ = nullptr; + worker_context_provider_ = nullptr; return false; } } - if (!compositor_context_provider_) { - compositor_context_provider_ = CreateContextProviderImpl( + if (!main_context_provider_) { + main_context_provider_ = CreateContextProviderImpl( std::move(gpu_channel_host), GetGpuMemoryBufferManager(), kCompositorContextSupportsLocking, kCompositorContextSupportsGLES2, kCompositorContextSupportsRaster, ui::command_buffer_metrics::UI_COMPOSITOR_CONTEXT); - compositor_context_provider_->SetDefaultTaskRunner(resize_task_runner_); + main_context_provider_->SetDefaultTaskRunner(resize_task_runner_); + main_context_provider_->AddObserver(this); - auto result = compositor_context_provider_->BindToCurrentThread(); + auto result = main_context_provider_->BindToCurrentThread(); if (result != gpu::ContextResult::kSuccess) { - compositor_context_provider_ = nullptr; - shared_worker_context_provider_ = nullptr; + main_context_provider_->RemoveObserver(this); + main_context_provider_ = nullptr; + worker_context_provider_ = nullptr; return false; } } @@ -539,8 +558,13 @@ } void VizProcessTransportFactory::OnLostMainThreadSharedContext() { - // TODO(danakj): When we implement making the shared context, we'll also - // have to recreate it here before calling OnLostResources(). + // It's possible that |main_context_provider_| was already reset in + // OnEstablishedGpuChannel(), so check if it's lost before resetting here. + if (main_context_provider_ && IsContextLost(main_context_provider_.get())) { + main_context_provider_->RemoveObserver(this); + main_context_provider_ = nullptr; + } + for (auto& observer : observer_list_) observer.OnLostResources(); }
diff --git a/content/browser/compositor/viz_process_transport_factory.h b/content/browser/compositor/viz_process_transport_factory.h index 034fa567..b7a8d77c 100644 --- a/content/browser/compositor/viz_process_transport_factory.h +++ b/content/browser/compositor/viz_process_transport_factory.h
@@ -11,6 +11,7 @@ #include "base/macros.h" #include "build/build_config.h" #include "components/viz/common/display/renderer_settings.h" +#include "components/viz/common/gpu/context_lost_observer.h" #include "components/viz/common/surfaces/frame_sink_id_allocator.h" #include "content/browser/compositor/image_transport_factory.h" #include "content/browser/compositor/in_process_display_client.h" @@ -51,7 +52,8 @@ class VizProcessTransportFactory : public ui::ContextFactory, public ui::ContextFactoryPrivate, public ImageTransportFactory, - public viz::mojom::CompositingModeWatcher { + public viz::mojom::CompositingModeWatcher, + public viz::ContextLostObserver { public: VizProcessTransportFactory( gpu::GpuChannelEstablishFactory* gpu_channel_establish_factory, @@ -112,6 +114,9 @@ // viz::mojom::CompositingModeWatcher implementation. void CompositingModeFallbackToSoftware() override; + // viz::ContextLostObserver implementation. + void OnContextLost() override; + private: struct CompositorData { CompositorData(); @@ -157,12 +162,16 @@ base::flat_map<ui::Compositor*, CompositorData> compositor_data_map_; bool is_gpu_compositing_disabled_ = false; - // TODO(kylechar): Call OnContextLost() on observers when GPU crashes. base::ObserverList<ui::ContextFactoryObserver> observer_list_; std::unique_ptr<viz::ClientSharedBitmapManager> shared_bitmap_manager_; - scoped_refptr<viz::RasterContextProvider> shared_worker_context_provider_; - scoped_refptr<ui::ContextProviderCommandBuffer> compositor_context_provider_; + + // ContextProvider used on worker threads for rasterization. + scoped_refptr<viz::RasterContextProvider> worker_context_provider_; + + // ContextProvider used on the main thread. Shared by ui::Compositors and also + // returned from GetSharedMainThreadContextProvider(). + scoped_refptr<ui::ContextProviderCommandBuffer> main_context_provider_; viz::FrameSinkIdAllocator frame_sink_id_allocator_; std::unique_ptr<cc::SingleThreadTaskGraphRunner> task_graph_runner_;
diff --git a/content/browser/devtools/devtools_agent_host_impl.cc b/content/browser/devtools/devtools_agent_host_impl.cc index a3f756f..0416602 100644 --- a/content/browser/devtools/devtools_agent_host_impl.cc +++ b/content/browser/devtools/devtools_agent_host_impl.cc
@@ -235,7 +235,7 @@ DevToolsSession* session = SessionById(session_id); if (!session) return false; - session->SendMessageToClient(message); + session->client()->DispatchProtocolMessage(this, message); return true; }
diff --git a/content/browser/devtools/devtools_manager_unittest.cc b/content/browser/devtools/devtools_manager_unittest.cc index 9d1d08f..6275e13 100644 --- a/content/browser/devtools/devtools_manager_unittest.cc +++ b/content/browser/devtools/devtools_manager_unittest.cc
@@ -167,36 +167,6 @@ contents()->SetDelegate(nullptr); } -TEST_F(DevToolsManagerTest, ReattachOnCancelPendingNavigation) { - // This test triggers incorrect notifications with PlzNavigate. - if (IsBrowserSideNavigationEnabled()) - return; - // Navigate to URL. First URL should use first RenderViewHost. - const GURL url("http://www.google.com"); - NavigationSimulator::NavigateAndCommitFromBrowser(web_contents(), url); - EXPECT_FALSE(contents()->CrossProcessNavigationPending()); - - TestDevToolsClientHost client_host; - client_host.InspectAgentHost( - DevToolsAgentHost::GetOrCreateFor(web_contents()).get()); - - // Navigate to new site which should get a new RenderViewHost. - const GURL url2("http://www.yahoo.com"); - auto navigation = - NavigationSimulator::CreateBrowserInitiated(url2, web_contents()); - navigation->ReadyToCommit(); - EXPECT_TRUE(contents()->CrossProcessNavigationPending()); - EXPECT_EQ(client_host.agent_host(), - DevToolsAgentHost::GetOrCreateFor(web_contents()).get()); - - // Interrupt pending navigation and navigate back to the original site. - NavigationSimulator::NavigateAndCommitFromBrowser(web_contents(), url); - EXPECT_FALSE(contents()->CrossProcessNavigationPending()); - EXPECT_EQ(client_host.agent_host(), - DevToolsAgentHost::GetOrCreateFor(web_contents()).get()); - client_host.Close(); -} - class TestExternalAgentDelegate: public DevToolsExternalAgentProxyDelegate { public: TestExternalAgentDelegate() {
diff --git a/content/browser/devtools/devtools_session.cc b/content/browser/devtools/devtools_session.cc index 9d42951..93a74b7 100644 --- a/content/browser/devtools/devtools_session.cc +++ b/content/browser/devtools/devtools_session.cc
@@ -14,8 +14,9 @@ namespace content { -// static -bool DevToolsSession::ShouldSendOnIO(const std::string& method) { +namespace { + +bool ShouldSendOnIO(const std::string& method) { // Keep in sync with WebDevToolsAgent::ShouldInterruptForMethod. // TODO(dgozman): find a way to share this. return method == "Debugger.pause" || method == "Debugger.setBreakpoint" || @@ -25,6 +26,8 @@ method == "Performance.getMetrics"; } +} // namespace + DevToolsSession::DevToolsSession(DevToolsAgentHostImpl* agent_host, DevToolsAgentHostClient* client, int session_id) @@ -55,10 +58,6 @@ handlers_[handler->name()] = std::move(handler); } -void DevToolsSession::SetRenderFrameHost(RenderFrameHostImpl* frame_host) { - SetRenderer(frame_host ? frame_host->GetProcess() : nullptr, frame_host); -} - void DevToolsSession::SetRenderer(RenderProcessHost* process_host, RenderFrameHostImpl* frame_host) { process_ = process_host; @@ -93,10 +92,6 @@ &DevToolsSession::MojoConnectionDestroyed, base::Unretained(this))); } -void DevToolsSession::SendMessageToClient(const std::string& message) { - client_->DispatchProtocolMessage(agent_host_, message); -} - void DevToolsSession::SendMessageFromProcessorIPC(int session_id, const std::string& message) { if (session_id != session_id_)
diff --git a/content/browser/devtools/devtools_session.h b/content/browser/devtools/devtools_session.h index bd9dedac..bc8e982 100644 --- a/content/browser/devtools/devtools_session.h +++ b/content/browser/devtools/devtools_session.h
@@ -32,14 +32,12 @@ int session_id() const { return session_id_; } DevToolsAgentHostClient* client() const { return client_; } void AddHandler(std::unique_ptr<protocol::DevToolsDomainHandler> handler); - void SetRenderFrameHost(RenderFrameHostImpl* frame_host); void SetRenderer(RenderProcessHost* process_host, RenderFrameHostImpl* frame_host); void SetFallThroughForNotFound(bool value); void AttachToAgent(const mojom::DevToolsAgentAssociatedPtr& agent); void ReattachToAgent(const mojom::DevToolsAgentAssociatedPtr& agent); - static bool ShouldSendOnIO(const std::string& method); struct Message { std::string method; std::string message; @@ -57,7 +55,6 @@ const std::string& message); void InspectElement(const gfx::Point& point); bool ReceiveMessageChunk(const DevToolsMessageChunk& chunk); - void SendMessageToClient(const std::string& message); template <typename Handler> static std::vector<Handler*> HandlersForAgentHost(
diff --git a/content/browser/devtools/forwarding_agent_host.cc b/content/browser/devtools/forwarding_agent_host.cc index 72e743c..4b4e439e 100644 --- a/content/browser/devtools/forwarding_agent_host.cc +++ b/content/browser/devtools/forwarding_agent_host.cc
@@ -23,7 +23,7 @@ private: void DispatchOnClientHost(const std::string& message) override { - session_->SendMessageToClient(message); + session_->client()->DispatchProtocolMessage(agent_host_, message); } void ConnectionClosed() override {
diff --git a/content/browser/devtools/protocol/page_handler.cc b/content/browser/devtools/protocol/page_handler.cc index d5b6c4f..cade77a8 100644 --- a/content/browser/devtools/protocol/page_handler.cc +++ b/content/browser/devtools/protocol/page_handler.cc
@@ -355,22 +355,17 @@ gurl, Referrer(GURL(referrer.fromMaybe("")), blink::kWebReferrerPolicyDefault), type, std::string()); - if (IsBrowserSideNavigationEnabled()) { - std::string frame_id = - web_contents->GetMainFrame()->GetDevToolsFrameToken().ToString(); - if (navigate_callback_) { - std::string error_string = net::ErrorToString(net::ERR_ABORTED); - navigate_callback_->sendSuccess(frame_id, Maybe<std::string>(), - Maybe<std::string>(error_string)); - } - if (web_contents->GetMainFrame()->frame_tree_node()->navigation_request()) - navigate_callback_ = std::move(callback); - else - callback->sendSuccess(frame_id, Maybe<std::string>(), - Maybe<std::string>()); - return; + std::string frame_id = + web_contents->GetMainFrame()->GetDevToolsFrameToken().ToString(); + if (navigate_callback_) { + std::string error_string = net::ErrorToString(net::ERR_ABORTED); + navigate_callback_->sendSuccess(frame_id, Maybe<std::string>(), + Maybe<std::string>(error_string)); } - callback->fallThrough(); + if (web_contents->GetMainFrame()->frame_tree_node()->navigation_request()) + navigate_callback_ = std::move(callback); + else + callback->sendSuccess(frame_id, Maybe<std::string>(), Maybe<std::string>()); } void PageHandler::NavigationReset(NavigationRequest* navigation_request) {
diff --git a/content/browser/devtools/protocol/target_auto_attacher.cc b/content/browser/devtools/protocol/target_auto_attacher.cc index 114a5df6..f979ec9 100644 --- a/content/browser/devtools/protocol/target_auto_attacher.cc +++ b/content/browser/devtools/protocol/target_auto_attacher.cc
@@ -141,8 +141,7 @@ } bool TargetAutoAttacher::ShouldThrottleFramesNavigation() { - return IsBrowserSideNavigationEnabled() && auto_attach_ && - attach_to_frames_ && wait_for_debugger_on_start_; + return auto_attach_ && attach_to_frames_ && wait_for_debugger_on_start_; } DevToolsAgentHost* TargetAutoAttacher::AutoAttachToFrame(
diff --git a/content/browser/devtools/render_frame_devtools_agent_host.cc b/content/browser/devtools/render_frame_devtools_agent_host.cc index 679f95a..af6628a 100644 --- a/content/browser/devtools/render_frame_devtools_agent_host.cc +++ b/content/browser/devtools/render_frame_devtools_agent_host.cc
@@ -94,234 +94,6 @@ } // namespace -// RenderFrameDevToolsAgentHost::FrameHostHolder ------------------------------- - -class RenderFrameDevToolsAgentHost::FrameHostHolder { - public: - FrameHostHolder( - RenderFrameDevToolsAgentHost* agent, RenderFrameHostImpl* host); - ~FrameHostHolder(); - - RenderFrameHostImpl* host() const { return host_; } - - void Attach(DevToolsSession* session); - void Reattach(FrameHostHolder* old); - void Detach(int session_id); - void DispatchProtocolMessage(int session_id, - int call_id, - const std::string& method, - const std::string& message); - void InspectElement(int session_id, int x, int y); - void Suspend(); - void Resume(); - std::string StateCookie(int session_id) const; - void ReattachWithCookie(DevToolsSession* session, std::string cookie); - - private: - struct Message { - std::string method; - std::string message; - }; - - class SessionHost : public mojom::DevToolsSessionHost { - public: - SessionHost(FrameHostHolder* owner, - int session_id, - const base::Optional<std::string>& reattach_state) - : owner_(owner), - session_id_(session_id), - binding_(this), - chunk_processor_( - base::Callback<void(int, const std::string&)>(), - base::Bind(&RenderFrameDevToolsAgentHost::FrameHostHolder:: - SessionHost::SendMessageFromProcessor, - base::Unretained(this))) { - if (reattach_state.has_value()) - chunk_processor_.set_state_cookie(reattach_state.value()); - mojom::DevToolsSessionHostAssociatedPtrInfo host_ptr_info; - binding_.Bind(mojo::MakeRequest(&host_ptr_info)); - owner_->agent_ptr_->AttachDevToolsSession( - std::move(host_ptr_info), mojo::MakeRequest(&session_ptr_), - mojo::MakeRequest(&io_session_ptr_), reattach_state); - } - - void RedispatchProtocolMessagesFrom(SessionHost* other) { - for (const auto& pair : other->sent_messages_) { - DispatchProtocolMessage(pair.first, pair.second.method, - pair.second.message); - } - } - - const std::string& state_cookie() const { - return chunk_processor_.state_cookie(); - } - - void DispatchProtocolMessage(int call_id, - const std::string& method, - const std::string& message) { - if (DevToolsSession::ShouldSendOnIO(method)) - io_session_ptr_->DispatchProtocolMessage(call_id, method, message); - else - session_ptr_->DispatchProtocolMessage(call_id, method, message); - sent_messages_[call_id] = {method, message}; - } - - void InspectElement(int x, int y) { - session_ptr_->InspectElement(gfx::Point(x, y)); - } - - // mojom::DevToolsSessionHost implementation. - void DispatchProtocolMessage( - mojom::DevToolsMessageChunkPtr chunk) override { - if (chunk_processor_.ProcessChunkedMessageFromAgent(std::move(chunk))) - return; - - binding_.Close(); - if (owner_->host_->GetProcess()) { - bad_message::ReceivedBadMessage( - owner_->host_->GetProcess(), - bad_message::RFH_INCONSISTENT_DEVTOOLS_MESSAGE); - } - } - - void SendMessageFromProcessor(const std::string& message) { - int id = chunk_processor_.last_call_id(); - Message sent_message = std::move(sent_messages_[id]); - sent_messages_.erase(id); - if (suspended_) { - pending_messages_.push_back(message); - } else { - DevToolsSession* session = owner_->agent_->SessionById(session_id_); - if (session) - session->SendMessageToClient(message); - // |this| may be deleted at this point. - } - } - - void Suspend() { suspended_ = true; } - - void Resume() { - suspended_ = false; - DevToolsSession* session = owner_->agent_->SessionById(session_id_); - std::vector<std::string> messages; - messages.swap(pending_messages_); - for (std::string& message : messages) - session->SendMessageToClient(message); - } - - private: - FrameHostHolder* owner_; - int session_id_; - mojo::AssociatedBinding<mojom::DevToolsSessionHost> binding_; - mojom::DevToolsSessionAssociatedPtr session_ptr_; - mojom::DevToolsSessionPtr io_session_ptr_; - DevToolsMessageChunkProcessor chunk_processor_; - std::vector<std::string> pending_messages_; - using CallId = int; - std::map<CallId, Message> sent_messages_; - bool suspended_ = false; - - DISALLOW_COPY_AND_ASSIGN(SessionHost); - }; - - RenderFrameDevToolsAgentHost* agent_; - RenderFrameHostImpl* host_; - mojom::DevToolsAgentAssociatedPtr agent_ptr_; - base::flat_map<int, std::unique_ptr<SessionHost>> session_hosts_; -}; - -RenderFrameDevToolsAgentHost::FrameHostHolder::FrameHostHolder( - RenderFrameDevToolsAgentHost* agent, - RenderFrameHostImpl* host) - : agent_(agent), host_(host) { - DCHECK(!IsBrowserSideNavigationEnabled()); - DCHECK(agent_); - DCHECK(host_); -} - -RenderFrameDevToolsAgentHost::FrameHostHolder::~FrameHostHolder() { - if (!session_hosts_.empty()) - agent_->RevokePolicy(host_); -} - -void RenderFrameDevToolsAgentHost::FrameHostHolder::Attach( - DevToolsSession* session) { - agent_->GrantPolicy(host_); - // |agent_ptr_| is used by SessionHost in constructor to attach. - if (!agent_ptr_) - host_->GetRemoteAssociatedInterfaces()->GetInterface(&agent_ptr_); - session_hosts_[session->session_id()].reset( - new SessionHost(this, session->session_id(), base::nullopt)); -} - -void RenderFrameDevToolsAgentHost::FrameHostHolder::Reattach( - FrameHostHolder* old) { - for (DevToolsSession* session : agent_->sessions()) { - int session_id = session->session_id(); - std::string cookie = old ? old->StateCookie(session_id) : std::string(); - ReattachWithCookie(session, std::move(cookie)); - if (!old) - continue; - auto it = old->session_hosts_.find(session_id); - if (it != old->session_hosts_.end()) { - session_hosts_[session_id]->RedispatchProtocolMessagesFrom( - it->second.get()); - } - } -} - -std::string RenderFrameDevToolsAgentHost::FrameHostHolder::StateCookie( - int session_id) const { - auto it = session_hosts_.find(session_id); - return it == session_hosts_.end() ? std::string() - : it->second->state_cookie(); -} - -void RenderFrameDevToolsAgentHost::FrameHostHolder::ReattachWithCookie( - DevToolsSession* session, - std::string cookie) { - agent_->GrantPolicy(host_); - // |agent_ptr_| is used by SessionHost in constructor to attach. - if (!agent_ptr_) - host_->GetRemoteAssociatedInterfaces()->GetInterface(&agent_ptr_); - session_hosts_[session->session_id()].reset( - new SessionHost(this, session->session_id(), cookie)); -} - -void RenderFrameDevToolsAgentHost::FrameHostHolder::Detach(int session_id) { - agent_->RevokePolicy(host_); - session_hosts_.erase(session_id); -} - -void RenderFrameDevToolsAgentHost::FrameHostHolder::DispatchProtocolMessage( - int session_id, - int call_id, - const std::string& method, - const std::string& message) { - auto it = session_hosts_.find(session_id); - if (it != session_hosts_.end()) - it->second->DispatchProtocolMessage(call_id, method, message); -} - -void RenderFrameDevToolsAgentHost::FrameHostHolder::InspectElement( - int session_id, int x, int y) { - auto it = session_hosts_.find(session_id); - if (it != session_hosts_.end()) - it->second->InspectElement(x, y); -} - -void RenderFrameDevToolsAgentHost::FrameHostHolder::Suspend() { - for (auto& pair : session_hosts_) - pair.second->Suspend(); -} - -void RenderFrameDevToolsAgentHost::FrameHostHolder::Resume() { - for (auto& pair : session_hosts_) - pair.second->Resume(); -} - -// RenderFrameDevToolsAgentHost ------------------------------------------------ - // static scoped_refptr<DevToolsAgentHost> DevToolsAgentHost::GetOrCreateFor(WebContents* web_contents) { @@ -389,33 +161,6 @@ } // static -void RenderFrameDevToolsAgentHost::OnCancelPendingNavigation( - RenderFrameHost* pending, - RenderFrameHost* current) { - if (IsBrowserSideNavigationEnabled()) - return; - - RenderFrameDevToolsAgentHost* agent_host = FindAgentHost( - static_cast<RenderFrameHostImpl*>(pending)->frame_tree_node()); - if (!agent_host) - return; - if (agent_host->pending_ && agent_host->pending_->host() == pending) { - DCHECK(agent_host->current_ && agent_host->current_->host() == current); - agent_host->DiscardPending(); - DCHECK(agent_host->CheckConsistency()); - } -} - -// static -void RenderFrameDevToolsAgentHost::OnBeforeNavigation( - RenderFrameHost* current, RenderFrameHost* pending) { - RenderFrameDevToolsAgentHost* agent_host = FindAgentHost( - static_cast<RenderFrameHostImpl*>(current)->frame_tree_node()); - if (agent_host) - agent_host->AboutToNavigateRenderFrame(current, pending); -} - -// static void RenderFrameDevToolsAgentHost::OnResetNavigationRequest( NavigationRequest* navigation_request) { RenderFrameDevToolsAgentHost* agent_host = @@ -517,73 +262,18 @@ RenderFrameDevToolsAgentHost::RenderFrameDevToolsAgentHost( FrameTreeNode* frame_tree_node) : DevToolsAgentHostImpl(frame_tree_node->devtools_frame_token().ToString()), - frame_trace_recorder_(nullptr), - handlers_frame_host_(nullptr), - current_frame_crashed_(false), frame_tree_node_(frame_tree_node) { - if (IsBrowserSideNavigationEnabled()) { - frame_host_ = frame_tree_node->current_frame_host(); - render_frame_alive_ = frame_host_ && frame_host_->IsRenderFrameLive(); - } else { - if (frame_tree_node->current_frame_host()) { - SetPending(frame_tree_node->current_frame_host()); - CommitPending(); - } - } + frame_host_ = frame_tree_node->current_frame_host(); + render_frame_alive_ = frame_host_ && frame_host_->IsRenderFrameLive(); WebContentsObserver::Observe( WebContentsImpl::FromFrameTreeNode(frame_tree_node)); - if (web_contents() && web_contents()->GetCrashedStatus() != - base::TERMINATION_STATUS_STILL_RUNNING) { - current_frame_crashed_ = true; - } - g_agent_host_instances.Get().push_back(this); AddRef(); // Balanced in RenderFrameHostDestroyed. NotifyCreated(); } -void RenderFrameDevToolsAgentHost::SetPending(RenderFrameHostImpl* host) { - DCHECK(!IsBrowserSideNavigationEnabled()); - DCHECK(!pending_); - current_frame_crashed_ = false; - pending_.reset(new FrameHostHolder(this, host)); - if (IsAttached()) - pending_->Reattach(current_.get()); - - if (current_) - current_->Suspend(); - pending_->Suspend(); - - UpdateProtocolHandlers(host); -} - -void RenderFrameDevToolsAgentHost::CommitPending() { - DCHECK(!IsBrowserSideNavigationEnabled()); - DCHECK(pending_); - current_frame_crashed_ = false; - - if (!ShouldCreateDevToolsForHost(pending_->host())) { - DestroyOnRenderFrameGone(); - // |this| may be deleted at this point. - return; - } - - current_ = std::move(pending_); - UpdateProtocolHandlers(current_->host()); - current_->Resume(); -} - -void RenderFrameDevToolsAgentHost::DiscardPending() { - DCHECK(!IsBrowserSideNavigationEnabled()); - DCHECK(pending_); - DCHECK(current_); - pending_.reset(); - UpdateProtocolHandlers(current_->host()); - current_->Resume(); -} - BrowserContext* RenderFrameDevToolsAgentHost::GetBrowserContext() { WebContents* contents = web_contents(); return contents ? contents->GetBrowserContext() : nullptr; @@ -595,10 +285,8 @@ void RenderFrameDevToolsAgentHost::AttachSession(DevToolsSession* session) { session->SetFallThroughForNotFound(true); - if (IsBrowserSideNavigationEnabled()) - session->SetRenderFrameHost(frame_host_); - else - session->SetRenderFrameHost(handlers_frame_host_); + session->SetRenderer(frame_host_ ? frame_host_->GetProcess() : nullptr, + frame_host_); protocol::EmulationHandler* emulation_handler = new protocol::EmulationHandler(); @@ -624,31 +312,28 @@ session->AddHandler(base::WrapUnique(new protocol::SecurityHandler())); } - if (IsBrowserSideNavigationEnabled()) { - if (EnsureAgent()) - session->AttachToAgent(agent_ptr_); - } else { - if (current_) - current_->Attach(session); - if (pending_) - pending_->Attach(session); + if (EnsureAgent()) + session->AttachToAgent(agent_ptr_); + + if (sessions().size() == 1) { + frame_trace_recorder_.reset(new DevToolsFrameTraceRecorder()); + GrantPolicy(); +#if defined(OS_ANDROID) + GetWakeLock()->RequestWakeLock(); +#endif } - if (sessions().size() == 1) - OnClientsAttached(); } void RenderFrameDevToolsAgentHost::DetachSession(int session_id) { - if (IsBrowserSideNavigationEnabled()) { - // Destroying session automatically detaches in renderer. - suspended_messages_by_session_id_.erase(session_id); - } else { - if (current_) - current_->Detach(session_id); - if (pending_) - pending_->Detach(session_id); + // Destroying session automatically detaches in renderer. + suspended_messages_by_session_id_.erase(session_id); + if (sessions().empty()) { + frame_trace_recorder_.reset(); + RevokePolicy(); +#if defined(OS_ANDROID) + GetWakeLock()->CancelWakeLock(); +#endif } - if (sessions().empty()) - OnClientsDetached(); } bool RenderFrameDevToolsAgentHost::DispatchProtocolMessage( @@ -662,20 +347,14 @@ return true; } - if (IsBrowserSideNavigationEnabled()) { - if (!navigation_handles_.empty()) { - suspended_messages_by_session_id_[session_id].push_back( - {call_id, method, message}); - return true; - } - session->DispatchProtocolMessageToAgent(call_id, method, message); - session->waiting_messages()[call_id] = {method, message}; - } else { - if (current_) - current_->DispatchProtocolMessage(session_id, call_id, method, message); - if (pending_) - pending_->DispatchProtocolMessage(session_id, call_id, method, message); + if (!navigation_handles_.empty()) { + suspended_messages_by_session_id_[session_id].push_back( + {call_id, method, message}); + return true; } + + session->DispatchProtocolMessageToAgent(call_id, method, message); + session->waiting_messages()[call_id] = {method, message}; return true; } @@ -683,32 +362,7 @@ DevToolsSession* session, int x, int y) { - if (IsBrowserSideNavigationEnabled()) { - session->InspectElement(gfx::Point(x, y)); - } else { - if (current_) - current_->InspectElement(session->session_id(), x, y); - if (pending_) - pending_->InspectElement(session->session_id(), x, y); - } -} - -void RenderFrameDevToolsAgentHost::OnClientsAttached() { - frame_trace_recorder_.reset(new DevToolsFrameTraceRecorder()); -#if defined(OS_ANDROID) - GetWakeLock()->RequestWakeLock(); -#endif - if (IsBrowserSideNavigationEnabled()) - GrantPolicy(frame_host_); -} - -void RenderFrameDevToolsAgentHost::OnClientsDetached() { -#if defined(OS_ANDROID) - GetWakeLock()->CancelWakeLock(); -#endif - frame_trace_recorder_.reset(); - if (IsBrowserSideNavigationEnabled()) - RevokePolicy(frame_host_); + session->InspectElement(gfx::Point(x, y)); } RenderFrameDevToolsAgentHost::~RenderFrameDevToolsAgentHost() { @@ -721,40 +375,18 @@ void RenderFrameDevToolsAgentHost::ReadyToCommitNavigation( NavigationHandle* navigation_handle) { - if (!IsBrowserSideNavigationEnabled()) - return; NavigationHandleImpl* handle = static_cast<NavigationHandleImpl*>(navigation_handle); if (handle->frame_tree_node() != frame_tree_node_) return; - // UpdateFrameHost may destruct |this|. - scoped_refptr<RenderFrameDevToolsAgentHost> protect(this); UpdateFrameHost(handle->GetRenderFrameHost()); - DCHECK(CheckConsistency()); + // UpdateFrameHost may destruct |this|. } void RenderFrameDevToolsAgentHost::DidFinishNavigation( NavigationHandle* navigation_handle) { NotifyNavigated(); - if (!IsBrowserSideNavigationEnabled()) { - // CommitPending may destruct |this|. - scoped_refptr<RenderFrameDevToolsAgentHost> protect(this); - if (navigation_handle->HasCommitted() && - !navigation_handle->IsErrorPage()) { - if (pending_ && - pending_->host() == navigation_handle->GetRenderFrameHost()) { - CommitPending(); - } - for (auto* target : protocol::TargetHandler::ForAgentHost(this)) - target->DidCommitNavigation(); - } else if (pending_ && pending_->host()->GetFrameTreeNodeId() == - navigation_handle->GetFrameTreeNodeId()) { - DiscardPending(); - } - DCHECK(CheckConsistency()); - return; - } NavigationHandleImpl* handle = static_cast<NavigationHandleImpl*>(navigation_handle); @@ -765,7 +397,6 @@ // UpdateFrameHost may destruct |this|. scoped_refptr<RenderFrameDevToolsAgentHost> protect(this); UpdateFrameHost(frame_tree_node_->current_frame_host()); - DCHECK(CheckConsistency()); if (navigation_handles_.empty()) { for (auto& pair : suspended_messages_by_session_id_) { @@ -796,28 +427,28 @@ return; } - if (IsAttached()) - RevokePolicy(frame_host_); - if (frame_host && !ShouldCreateDevToolsForHost(frame_host)) { DestroyOnRenderFrameGone(); // |this| may be deleted at this point. return; } + if (IsAttached()) + RevokePolicy(); frame_host_ = frame_host; agent_ptr_.reset(); render_frame_alive_ = true; if (IsAttached()) { - GrantPolicy(frame_host_); - for (DevToolsSession* session : sessions()) - session->SetRenderFrameHost(frame_host); + GrantPolicy(); + for (DevToolsSession* session : sessions()) { + session->SetRenderer(frame_host ? frame_host->GetProcess() : nullptr, + frame_host); + } MaybeReattachToRenderFrame(); } } void RenderFrameDevToolsAgentHost::MaybeReattachToRenderFrame() { - DCHECK(IsBrowserSideNavigationEnabled()); if (!EnsureAgent()) return; for (DevToolsSession* session : sessions()) { @@ -831,38 +462,27 @@ } } -void RenderFrameDevToolsAgentHost::GrantPolicy(RenderFrameHostImpl* host) { - if (!host) +void RenderFrameDevToolsAgentHost::GrantPolicy() { + if (!frame_host_) return; - uint32_t process_id = host->GetProcess()->GetID(); + uint32_t process_id = frame_host_->GetProcess()->GetID(); if (base::FeatureList::IsEnabled(features::kNetworkService)) GetNetworkService()->SetRawHeadersAccess(process_id, true); ChildProcessSecurityPolicyImpl::GetInstance()->GrantReadRawCookies( process_id); } -void RenderFrameDevToolsAgentHost::RevokePolicy(RenderFrameHostImpl* host) { - if (!host) +void RenderFrameDevToolsAgentHost::RevokePolicy() { + if (!frame_host_) return; bool process_has_agents = false; - RenderProcessHost* process_host = host->GetProcess(); + RenderProcessHost* process_host = frame_host_->GetProcess(); for (RenderFrameDevToolsAgentHost* agent : g_agent_host_instances.Get()) { if (!agent->IsAttached()) continue; - if (IsBrowserSideNavigationEnabled()) { - if (agent->frame_host_ && agent->frame_host_ != host && - agent->frame_host_->GetProcess() == process_host) { - process_has_agents = true; - } - continue; - } - if (agent->current_ && agent->current_->host() != host && - agent->current_->host()->GetProcess() == process_host) { - process_has_agents = true; - } - if (agent->pending_ && agent->pending_->host() != host && - agent->pending_->host()->GetProcess() == process_host) { + if (agent->frame_host_ && agent->frame_host_ != frame_host_ && + agent->frame_host_->GetProcess() == process_host) { process_has_agents = true; } } @@ -876,43 +496,13 @@ } } -void RenderFrameDevToolsAgentHost::AboutToNavigateRenderFrame( - RenderFrameHost* old_host, - RenderFrameHost* new_host) { - if (IsBrowserSideNavigationEnabled()) - return; - - // CommitPending may destruct |this|. - scoped_refptr<RenderFrameDevToolsAgentHost> protect(this); - - DCHECK(!pending_ || pending_->host() != old_host); - if (!current_ || current_->host() != old_host) { - DCHECK(CheckConsistency()); - return; - } - if (old_host == new_host && !current_frame_crashed_) { - DCHECK(CheckConsistency()); - return; - } - DCHECK(!pending_); - SetPending(static_cast<RenderFrameHostImpl*>(new_host)); - // Commit when navigating the same frame after crash, avoiding the same - // host in current_ and pending_. - if (old_host == new_host) - CommitPending(); - DCHECK(CheckConsistency()); -} - void RenderFrameDevToolsAgentHost::DidStartNavigation( NavigationHandle* navigation_handle) { - if (!IsBrowserSideNavigationEnabled()) - return; NavigationHandleImpl* handle = static_cast<NavigationHandleImpl*>(navigation_handle); if (handle->frame_tree_node() != frame_tree_node_) return; navigation_handles_.insert(handle); - DCHECK(CheckConsistency()); } void RenderFrameDevToolsAgentHost::RenderFrameHostChanged( @@ -921,105 +511,39 @@ for (auto* target : protocol::TargetHandler::ForAgentHost(this)) target->RenderFrameHostChanged(); - if (IsBrowserSideNavigationEnabled()) { - if (old_host != frame_host_) - return; - - // UpdateFrameHost may destruct |this|. - scoped_refptr<RenderFrameDevToolsAgentHost> protect(this); - UpdateFrameHost(nullptr); - DCHECK(CheckConsistency()); + if (old_host != frame_host_) return; - } - // CommitPending may destruct |this|. - scoped_refptr<RenderFrameDevToolsAgentHost> protect(this); - - DCHECK(!pending_ || pending_->host() != old_host); - if (!current_ || current_->host() != old_host) { - DCHECK(CheckConsistency()); - return; - } - - // AboutToNavigateRenderFrame was not called for renderer-initiated - // navigation. - if (!pending_) - SetPending(static_cast<RenderFrameHostImpl*>(new_host)); - CommitPending(); - DCHECK(CheckConsistency()); + UpdateFrameHost(nullptr); + // UpdateFrameHost may destruct |this|. } void RenderFrameDevToolsAgentHost::FrameDeleted(RenderFrameHost* rfh) { - if (IsBrowserSideNavigationEnabled()) { - if (static_cast<RenderFrameHostImpl*>(rfh)->frame_tree_node() == - frame_tree_node_) - DestroyOnRenderFrameGone(); // |this| may be deleted at this point. - else - DCHECK(CheckConsistency()); - return; - } - - if (pending_ && pending_->host() == rfh) { - if (!IsBrowserSideNavigationEnabled()) - DiscardPending(); - DCHECK(CheckConsistency()); - return; - } - - if (current_ && current_->host() == rfh) + if (static_cast<RenderFrameHostImpl*>(rfh)->frame_tree_node() == + frame_tree_node_) { DestroyOnRenderFrameGone(); // |this| may be deleted at this point. + } } void RenderFrameDevToolsAgentHost::RenderFrameDeleted(RenderFrameHost* rfh) { - if (IsBrowserSideNavigationEnabled()) { - if (rfh == frame_host_) { - render_frame_alive_ = false; - agent_ptr_.reset(); - } - DCHECK(CheckConsistency()); - return; + if (rfh == frame_host_) { + render_frame_alive_ = false; + agent_ptr_.reset(); } - - if (!current_frame_crashed_) - FrameDeleted(rfh); - else - DCHECK(CheckConsistency()); } void RenderFrameDevToolsAgentHost::DestroyOnRenderFrameGone() { scoped_refptr<RenderFrameDevToolsAgentHost> protect(this); - UpdateProtocolHandlers(nullptr); if (IsAttached()) - OnClientsDetached(); + RevokePolicy(); ForceDetachAllClients(); frame_host_ = nullptr; agent_ptr_.reset(); - pending_.reset(); - current_.reset(); frame_tree_node_ = nullptr; WebContentsObserver::Observe(nullptr); Release(); } -bool RenderFrameDevToolsAgentHost::CheckConsistency() { - if (!IsBrowserSideNavigationEnabled()) { - if (current_ && pending_ && current_->host() == pending_->host()) - return false; - } else { - if (current_ || pending_) - return false; - } - - if (!frame_tree_node_) - return !frame_host_; - - RenderFrameHostManager* manager = frame_tree_node_->render_manager(); - RenderFrameHostImpl* current = manager->current_frame_host(); - RenderFrameHostImpl* speculative = manager->speculative_frame_host(); - RenderFrameHostImpl* host = frame_host_; - return host == current || host == speculative; -} - #if defined(OS_ANDROID) device::mojom::WakeLock* RenderFrameDevToolsAgentHost::GetWakeLock() { // Here is a lazy binding, and will not reconnect after connection error. @@ -1053,32 +577,17 @@ case base::TERMINATION_STATUS_LAUNCH_FAILED: for (auto* inspector : protocol::InspectorHandler::ForAgentHost(this)) inspector->TargetCrashed(); - current_frame_crashed_ = true; break; default: for (auto* inspector : protocol::InspectorHandler::ForAgentHost(this)) inspector->TargetDetached("Render process gone."); break; } - DCHECK(CheckConsistency()); } void RenderFrameDevToolsAgentHost::DidAttachInterstitialPage() { for (auto* page : protocol::PageHandler::ForAgentHost(this)) page->DidAttachInterstitialPage(); - - if (IsBrowserSideNavigationEnabled()) - return; - - // TODO(dgozman): this may break for cross-process subframes. - if (!pending_) { - DCHECK(CheckConsistency()); - return; - } - // Pending set in AboutToNavigateRenderFrame turned out to be interstitial. - // Connect back to the real one. - DiscardPending(); - DCHECK(CheckConsistency()); } void RenderFrameDevToolsAgentHost::DidDetachInterstitialPage() { @@ -1113,84 +622,26 @@ bool did_initiate_recording = false; for (auto* tracing : protocol::TracingHandler::ForAgentHost(this)) did_initiate_recording |= tracing->did_initiate_recording(); - if (did_initiate_recording) { - if (IsBrowserSideNavigationEnabled()) { - frame_trace_recorder_->OnSwapCompositorFrame(frame_host_, metadata); - } else { - frame_trace_recorder_->OnSwapCompositorFrame( - current_ ? current_->host() : nullptr, metadata); - } - } -} - -void RenderFrameDevToolsAgentHost::UpdateProtocolHandlers( - RenderFrameHostImpl* host) { - if (IsBrowserSideNavigationEnabled()) - return; -#if DCHECK_IS_ON() - // Check that we don't have stale host object here by accessing some random - // properties inside. - if (handlers_frame_host_ && handlers_frame_host_->GetRenderWidgetHost()) - handlers_frame_host_->GetRenderWidgetHost()->GetRoutingID(); -#endif - handlers_frame_host_ = host; - for (DevToolsSession* session : sessions()) - session->SetRenderFrameHost(host); + if (did_initiate_recording) + frame_trace_recorder_->OnSwapCompositorFrame(frame_host_, metadata); } void RenderFrameDevToolsAgentHost::DisconnectWebContents() { - if (IsBrowserSideNavigationEnabled()) { - UpdateFrameHost(nullptr); - frame_tree_node_ = nullptr; - navigation_handles_.clear(); - WebContentsObserver::Observe(nullptr); - return; - } - if (pending_) - DiscardPending(); - UpdateProtocolHandlers(nullptr); - for (DevToolsSession* session : sessions()) { - int session_id = session->session_id(); - disconnected_cookie_for_session_[session_id] = - current_->StateCookie(session_id); - current_->Detach(session_id); - } - current_.reset(); frame_tree_node_ = nullptr; + navigation_handles_.clear(); WebContentsObserver::Observe(nullptr); + UpdateFrameHost(nullptr); + // UpdateFrameHost may destruct |this|. } void RenderFrameDevToolsAgentHost::ConnectWebContents(WebContents* wc) { - if (IsBrowserSideNavigationEnabled()) { - RenderFrameHostImpl* host = - static_cast<RenderFrameHostImpl*>(wc->GetMainFrame()); - DCHECK(host); - frame_tree_node_ = host->frame_tree_node(); - WebContentsObserver::Observe(wc); - UpdateFrameHost(host); - return; - } - - // CommitPending may destruct |this|. - scoped_refptr<RenderFrameDevToolsAgentHost> protect(this); - - DCHECK(!current_); - DCHECK(!pending_); RenderFrameHostImpl* host = static_cast<RenderFrameHostImpl*>(wc->GetMainFrame()); DCHECK(host); - current_frame_crashed_ = false; - current_.reset(new FrameHostHolder(this, host)); - for (DevToolsSession* session : sessions()) { - current_->ReattachWithCookie( - session, - std::move(disconnected_cookie_for_session_[session->session_id()])); - } - disconnected_cookie_for_session_.clear(); - - UpdateProtocolHandlers(host); frame_tree_node_ = host->frame_tree_node(); - WebContentsObserver::Observe(WebContents::FromRenderFrameHost(host)); + WebContentsObserver::Observe(wc); + UpdateFrameHost(host); + // UpdateFrameHost may destruct |this|. } std::string RenderFrameDevToolsAgentHost::GetParentId() { @@ -1240,13 +691,8 @@ if (!title.empty()) return title; } - if (IsBrowserSideNavigationEnabled()) { - if (IsChildFrame() && frame_host_) - return frame_host_->GetLastCommittedURL().spec(); - } else { - if (current_ && current_->host()->GetParent()) - return current_->host()->GetLastCommittedURL().spec(); - } + if (IsChildFrame() && frame_host_) + return frame_host_->GetLastCommittedURL().spec(); if (web_contents()) return base::UTF16ToUTF8(web_contents()->GetTitle()); return GetURL().spec(); @@ -1264,15 +710,8 @@ WebContents* web_contents = GetWebContents(); if (web_contents && !IsChildFrame()) return web_contents->GetVisibleURL(); - if (IsBrowserSideNavigationEnabled()) { - if (frame_host_) - return frame_host_->GetLastCommittedURL(); - } else { - if (pending_) - return pending_->host()->GetLastCommittedURL(); - if (current_) - return current_->host()->GetLastCommittedURL(); - } + if (frame_host_) + return frame_host_->GetLastCommittedURL(); return GURL(); } @@ -1343,13 +782,8 @@ for (auto* tracing : protocol::TracingHandler::ForAgentHost(this)) did_initiate_recording |= tracing->did_initiate_recording(); if (did_initiate_recording) { - if (IsBrowserSideNavigationEnabled()) { - frame_trace_recorder_->OnSynchronousSwapCompositorFrame(frame_host_, - frame_metadata); - } else { - frame_trace_recorder_->OnSynchronousSwapCompositorFrame( - current_ ? current_->host() : nullptr, frame_metadata); - } + frame_trace_recorder_->OnSynchronousSwapCompositorFrame(frame_host_, + frame_metadata); } }
diff --git a/content/browser/devtools/render_frame_devtools_agent_host.h b/content/browser/devtools/render_frame_devtools_agent_host.h index 809c965..cc49c35 100644 --- a/content/browser/devtools/render_frame_devtools_agent_host.h +++ b/content/browser/devtools/render_frame_devtools_agent_host.h
@@ -59,10 +59,6 @@ mojom::BeginNavigationParams* begin_params, bool* report_raw_headers); - static void OnCancelPendingNavigation(RenderFrameHost* pending, - RenderFrameHost* current); - static void OnBeforeNavigation(RenderFrameHost* current, - RenderFrameHost* pending); static void OnResetNavigationRequest(NavigationRequest* navigation_request); static std::vector<std::unique_ptr<NavigationThrottle>> @@ -94,7 +90,6 @@ bool Close() override; base::TimeTicks GetLastActivityTime() override; - // PlzNavigate RenderFrameHostImpl* GetFrameHostForTesting() { return frame_host_; } private: @@ -125,28 +120,14 @@ void WasHidden() override; void DidReceiveCompositorFrame() override; - void AboutToNavigateRenderFrame(RenderFrameHost* old_host, - RenderFrameHost* new_host); - - void SetPending(RenderFrameHostImpl* host); - void CommitPending(); - void DiscardPending(); - void UpdateProtocolHandlers(RenderFrameHostImpl* host); - bool IsChildFrame(); - void OnClientsAttached(); - void OnClientsDetached(); - - void RenderFrameCrashed(); void OnSwapCompositorFrame(const IPC::Message& message); void DestroyOnRenderFrameGone(); - - bool CheckConsistency(); void UpdateFrameHost(RenderFrameHostImpl* frame_host); void MaybeReattachToRenderFrame(); - void GrantPolicy(RenderFrameHostImpl* host); - void RevokePolicy(RenderFrameHostImpl* host); + void GrantPolicy(); + void RevokePolicy(); #if defined(OS_ANDROID) device::mojom::WakeLock* GetWakeLock(); @@ -156,22 +137,10 @@ viz::CompositorFrameMetadata frame_metadata); bool EnsureAgent(); - class FrameHostHolder; - - std::unique_ptr<FrameHostHolder> current_; - std::unique_ptr<FrameHostHolder> pending_; - - // Stores per-host state between DisconnectWebContents and ConnectWebContents. - base::flat_map<int, std::string> disconnected_cookie_for_session_; - std::unique_ptr<DevToolsFrameTraceRecorder> frame_trace_recorder_; #if defined(OS_ANDROID) device::mojom::WakeLockPtr wake_lock_; #endif - RenderFrameHostImpl* handlers_frame_host_; - bool current_frame_crashed_; - - // PlzNavigate // The active host we are talking to. RenderFrameHostImpl* frame_host_ = nullptr;
diff --git a/content/browser/devtools/render_frame_devtools_agent_host_browsertest.cc b/content/browser/devtools/render_frame_devtools_agent_host_browsertest.cc index d166e08..d4d30a5b 100644 --- a/content/browser/devtools/render_frame_devtools_agent_host_browsertest.cc +++ b/content/browser/devtools/render_frame_devtools_agent_host_browsertest.cc
@@ -31,9 +31,6 @@ // See https://crbug.com/695203. IN_PROC_BROWSER_TEST_F(RenderFrameDevToolsAgentHostBrowserTest, CancelCrossOriginNavigationAfterReadyToCommit) { - if (!IsBrowserSideNavigationEnabled()) - return; - ControllableHttpResponse response_b(embedded_test_server(), "/response_b"); ControllableHttpResponse response_c(embedded_test_server(), "/response_c"); EXPECT_TRUE(embedded_test_server()->Start());
diff --git a/content/browser/file_url_loader_factory.cc b/content/browser/file_url_loader_factory.cc index 30b8caa0..afd1a75 100644 --- a/content/browser/file_url_loader_factory.cc +++ b/content/browser/file_url_loader_factory.cc
@@ -38,6 +38,7 @@ #include "net/http/http_byte_range.h" #include "net/http/http_util.h" #include "net/url_request/redirect_info.h" +#include "storage/common/fileapi/file_system_util.h" #include "url/gurl.h" #if defined(OS_WIN) @@ -90,13 +91,14 @@ static void CreateAndStart(const base::FilePath& profile_path, const ResourceRequest& request, mojom::URLLoaderRequest loader, - mojom::URLLoaderClientPtrInfo client_info) { + mojom::URLLoaderClientPtrInfo client_info, + std::unique_ptr<FileURLLoaderObserver> observer) { // Owns itself. Will live as long as its URLLoader and URLLoaderClientPtr // bindings are alive - essentially until either the client gives up or all // file data has been sent to it. auto* file_url_loader = new FileURLDirectoryLoader; file_url_loader->Start(profile_path, request, std::move(loader), - std::move(client_info)); + std::move(client_info), std::move(observer)); } // mojom::URLLoader: @@ -114,7 +116,8 @@ void Start(const base::FilePath& profile_path, const ResourceRequest& request, mojom::URLLoaderRequest loader, - mojom::URLLoaderClientPtrInfo client_info) { + mojom::URLLoaderClientPtrInfo client_info, + std::unique_ptr<content::FileURLLoaderObserver> observer) { binding_.Bind(std::move(loader)); binding_.set_connection_error_handler(base::BindOnce( &FileURLDirectoryLoader::OnConnectionError, base::Unretained(this))); @@ -289,14 +292,16 @@ mojom::URLLoaderClientPtrInfo client_info, DirectoryLoadingPolicy directory_loading_policy, FileAccessPolicy file_access_policy, - LinkFollowingPolicy link_following_policy) { + LinkFollowingPolicy link_following_policy, + std::unique_ptr<FileURLLoaderObserver> observer) { // Owns itself. Will live as long as its URLLoader and URLLoaderClientPtr // bindings are alive - essentially until either the client gives up or all // file data has been sent to it. auto* file_url_loader = new FileURLLoader; file_url_loader->Start(profile_path, request, std::move(loader), std::move(client_info), directory_loading_policy, - file_access_policy, link_following_policy); + file_access_policy, link_following_policy, + std::move(observer)); } // mojom::URLLoader: @@ -317,7 +322,8 @@ mojom::URLLoaderClientPtrInfo client_info, DirectoryLoadingPolicy directory_loading_policy, FileAccessPolicy file_access_policy, - LinkFollowingPolicy link_following_policy) { + LinkFollowingPolicy link_following_policy, + std::unique_ptr<FileURLLoaderObserver> observer) { ResourceResponseHead head; head.request_start = base::TimeTicks::Now(); head.response_start = base::TimeTicks::Now(); @@ -331,6 +337,8 @@ base::FilePath path; if (!net::FileURLToFilePath(request.url, &path)) { client->OnComplete(network::URLLoaderCompletionStatus(net::ERR_FAILED)); + if (observer) + observer->OnDoneReading(); return; } @@ -338,6 +346,8 @@ if (!base::GetFileInfo(path, &info)) { client->OnComplete( network::URLLoaderCompletionStatus(net::ERR_FILE_NOT_FOUND)); + if (observer) + observer->OnDoneReading(); return; } @@ -345,6 +355,8 @@ if (directory_loading_policy == DirectoryLoadingPolicy::kFail) { client->OnComplete( network::URLLoaderCompletionStatus(net::ERR_FILE_NOT_FOUND)); + if (observer) + observer->OnDoneReading(); return; } @@ -372,7 +384,8 @@ ResourceRequest new_request = request; new_request.url = directory_url; FileURLDirectoryLoader::CreateAndStart( - profile_path, new_request, binding_.Unbind(), client.PassInterface()); + profile_path, new_request, binding_.Unbind(), client.PassInterface(), + std::move(observer)); MaybeDeleteSelf(); return; } @@ -397,7 +410,8 @@ new_request.url = redirect_info.new_url; return Start(profile_path, request, binding_.Unbind(), client.PassInterface(), directory_loading_policy, - file_access_policy, link_following_policy); + file_access_policy, link_following_policy, + std::move(observer)); } #endif // defined(OS_WIN) @@ -406,12 +420,16 @@ path, base::MakeAbsoluteFilePath(path), profile_path)) { client->OnComplete( network::URLLoaderCompletionStatus(net::ERR_ACCESS_DENIED)); + if (observer) + observer->OnDoneReading(); return; } mojo::DataPipe pipe(kDefaultFileUrlPipeSize); if (!pipe.consumer_handle.is_valid()) { client->OnComplete(network::URLLoaderCompletionStatus(net::ERR_FAILED)); + if (observer) + observer->OnDoneReading(); return; } @@ -420,14 +438,28 @@ // path didn't have a trailing path separator. In that case we finish with // a redirect above which will in turn be handled by FileURLDirectoryLoader. DCHECK(!info.is_directory); + if (observer) + observer->OnStart(); base::File file(path, base::File::FLAG_OPEN | base::File::FLAG_READ); + if (observer) + observer->OnOpenComplete(net::FileErrorToNetError(file.error_details())); char initial_read_buffer[net::kMaxBytesToSniff]; int initial_read_result = file.ReadAtCurrentPos(initial_read_buffer, net::kMaxBytesToSniff); if (initial_read_result < 0) { - client->OnComplete(network::URLLoaderCompletionStatus(net::ERR_FAILED)); + base::File::Error read_error = base::File::GetLastFileError(); + DCHECK_NE(base::File::FILE_OK, read_error); + if (observer) { + observer->OnBytesRead(nullptr, 0u, read_error); + observer->OnDoneReading(); + } + net::Error net_error = net::FileErrorToNetError(read_error); + client->OnComplete(network::URLLoaderCompletionStatus(net_error)); return; + } else if (observer) { + observer->OnBytesRead(initial_read_buffer, initial_read_result, + base::File::FILE_OK); } size_t initial_read_size = static_cast<size_t>(initial_read_result); @@ -450,6 +482,8 @@ if (fail) { client->OnComplete(network::URLLoaderCompletionStatus( net::ERR_REQUEST_RANGE_NOT_SATISFIABLE)); + if (observer) + observer->OnDoneReading(); return; } } @@ -478,7 +512,7 @@ &initial_read_buffer[first_byte_to_send], &write_size, MOJO_WRITE_DATA_FLAG_NONE); if (result != MOJO_RESULT_OK || write_size != expected_write_size) { - OnFileWritten(result); + OnFileWritten(std::move(observer), result); return; } @@ -497,20 +531,24 @@ if (total_bytes_to_send == 0) { // There's definitely no more data, so we're already done. - OnFileWritten(MOJO_RESULT_OK); + OnFileWritten(std::move(observer), MOJO_RESULT_OK); return; } // In case of a range request, seek to the appropriate position before // sending the remaining bytes asynchronously. Under normal conditions // (i.e., no range request) this Seek is effectively a no-op. - file.Seek(base::File::FROM_BEGIN, static_cast<int64_t>(first_byte_to_send)); + int new_position = file.Seek(base::File::FROM_BEGIN, + static_cast<int64_t>(first_byte_to_send)); + if (observer) + observer->OnSeekComplete(new_position); data_producer_ = std::make_unique<mojo::FileDataPipeProducer>( - std::move(pipe.producer_handle)); + std::move(pipe.producer_handle), std::move(observer)); data_producer_->WriteFromFile( std::move(file), total_bytes_to_send, - base::BindOnce(&FileURLLoader::OnFileWritten, base::Unretained(this))); + base::BindOnce(&FileURLLoader::OnFileWritten, base::Unretained(this), + nullptr)); } void OnConnectionError() { @@ -523,10 +561,13 @@ delete this; } - void OnFileWritten(MojoResult result) { + void OnFileWritten(std::unique_ptr<FileURLLoaderObserver> observer, + MojoResult result) { // All the data has been written now. Close the data pipe. The consumer will // be notified that there will be no more data to read from now. data_producer_.reset(); + if (observer) + observer->OnDoneReading(); if (result == MOJO_RESULT_OK) client_->OnComplete(network::URLLoaderCompletionStatus(net::OK)); @@ -566,7 +607,8 @@ task_runner_->PostTask( FROM_HERE, base::BindOnce(&FileURLDirectoryLoader::CreateAndStart, profile_path_, - request, std::move(loader), client.PassInterface())); + request, std::move(loader), client.PassInterface(), + std::unique_ptr<FileURLLoaderObserver>())); } else { task_runner_->PostTask( FROM_HERE, @@ -574,7 +616,8 @@ std::move(loader), client.PassInterface(), DirectoryLoadingPolicy::kRespondWithListing, FileAccessPolicy::kRestricted, - LinkFollowingPolicy::kFollow)); + LinkFollowingPolicy::kFollow, + std::unique_ptr<FileURLLoaderObserver>())); } } @@ -584,7 +627,8 @@ void CreateFileURLLoader(const ResourceRequest& request, mojom::URLLoaderRequest loader, - mojom::URLLoaderClientPtr client) { + mojom::URLLoaderClientPtr client, + std::unique_ptr<FileURLLoaderObserver> observer) { auto task_runner = base::CreateSequencedTaskRunnerWithTraits( {base::MayBlock(), base::TaskPriority::BACKGROUND, base::TaskShutdownBehavior::SKIP_ON_SHUTDOWN}); @@ -594,7 +638,7 @@ std::move(loader), client.PassInterface(), DirectoryLoadingPolicy::kFail, FileAccessPolicy::kUnrestricted, - LinkFollowingPolicy::kDoNotFollow)); + LinkFollowingPolicy::kDoNotFollow, std::move(observer))); } } // namespace content
diff --git a/content/browser/histogram_synchronizer.cc b/content/browser/histogram_synchronizer.cc index bbfb0e48..76d0bf9 100644 --- a/content/browser/histogram_synchronizer.cc +++ b/content/browser/histogram_synchronizer.cc
@@ -21,6 +21,8 @@ #include "content/public/browser/histogram_fetcher.h" #include "content/public/common/content_constants.h" +namespace content { + using base::Time; using base::TimeDelta; using base::TimeTicks; @@ -36,8 +38,6 @@ } // anonymous namespace -namespace content { - // The "RequestContext" structure describes an individual request received from // the UI. All methods are accessible on UI thread. class HistogramSynchronizer::RequestContext {
diff --git a/content/browser/loader/resource_dispatcher_host_impl.cc b/content/browser/loader/resource_dispatcher_host_impl.cc index 563f9a88..36c4ff74 100644 --- a/content/browser/loader/resource_dispatcher_host_impl.cc +++ b/content/browser/loader/resource_dispatcher_host_impl.cc
@@ -123,15 +123,15 @@ #include "url/third_party/mozilla/url_parse.h" #include "url/url_constants.h" +// ---------------------------------------------------------------------------- + +namespace content { + using base::Time; using base::TimeDelta; using base::TimeTicks; using storage::ShareableFileReference; -// ---------------------------------------------------------------------------- - -namespace content { - namespace { static ResourceDispatcherHostImpl* g_resource_dispatcher_host;
diff --git a/content/browser/renderer_host/input/fling_controller.cc b/content/browser/renderer_host/input/fling_controller.cc index fb43d429..bef1223d 100644 --- a/content/browser/renderer_host/input/fling_controller.cc +++ b/content/browser/renderer_host/input/fling_controller.cc
@@ -228,8 +228,10 @@ : blink::WebMouseWheelEvent::kPhaseBegan; GenerateAndSendWheelEvents(delta_to_scroll, phase); has_fling_animation_started_ = true; - ScheduleFlingProgress(); } + // As long as the fling curve is active, the fling progress must get + // scheduled even when the last delta to scroll was zero. + ScheduleFlingProgress(); } else { // !is_fling_active CancelCurrentFling(); }
diff --git a/content/browser/renderer_host/input/fling_controller_unittest.cc b/content/browser/renderer_host/input/fling_controller_unittest.cc index 2fb8725..591a88f 100644 --- a/content/browser/renderer_host/input/fling_controller_unittest.cc +++ b/content/browser/renderer_host/input/fling_controller_unittest.cc
@@ -17,16 +17,6 @@ using blink::WebInputEvent; using blink::WebMouseWheelEvent; -namespace { -void GiveItSomeTime(uint64_t delay_in_ms) { - base::RunLoop run_loop; - base::ThreadTaskRunnerHandle::Get()->PostDelayedTask( - FROM_HERE, run_loop.QuitClosure(), - base::TimeDelta::FromMillisecondsD(delay_in_ms)); - run_loop.Run(); -} -} // namespace - namespace content { class FakeFlingController : public FlingController { @@ -111,10 +101,10 @@ fling_controller_->ProcessGestureFlingCancel(fling_cancel_with_latency); } - void ProgressFling() { + void ProgressFling(base::TimeTicks current_time) { DCHECK(scheduled_next_fling_progress_); scheduled_next_fling_progress_ = false; - fling_controller_->ProgressFling(base::TimeTicks::Now()); + fling_controller_->ProgressFling(current_time); } bool FlingInProgress() { return fling_controller_->fling_in_progress(); } @@ -142,53 +132,46 @@ EXPECT_EQ(0.f, last_sent_wheel_.delta_y); } -// TODO(crbug.com/795617): Test timing expectations make it flaky. -TEST_F(FlingControllerTest, DISABLED_ControllerHandlesGestureFling) { +TEST_F(FlingControllerTest, ControllerHandlesGestureFling) { + base::TimeTicks progress_time = base::TimeTicks::Now(); SimulateFlingStart(blink::kWebGestureDeviceTouchpad, gfx::Vector2dF(1000, 0)); EXPECT_TRUE(FlingInProgress()); // The first wheel event must have momentum_phase == KPhaseBegan. - GiveItSomeTime(17); - ProgressFling(); + progress_time += base::TimeDelta::FromMilliseconds(17); + ProgressFling(progress_time); EXPECT_EQ(WebMouseWheelEvent::kPhaseBegan, last_sent_wheel_.momentum_phase); EXPECT_GT(last_sent_wheel_.delta_x, 0.f); // The rest of the wheel events must have momentum_phase == KPhaseChanged. - GiveItSomeTime(17); - ProgressFling(); + progress_time += base::TimeDelta::FromMilliseconds(17); + ProgressFling(progress_time); EXPECT_EQ(WebMouseWheelEvent::kPhaseChanged, last_sent_wheel_.momentum_phase); EXPECT_GT(last_sent_wheel_.delta_x, 0.f); - // Now cancel the fling. The GFC will get suppressed by fling booster. + // Now cancel the fling. The GFC will end the fling. SimulateFlingCancel(blink::kWebGestureDeviceTouchpad); - EXPECT_TRUE(last_fling_cancel_filtered_); - EXPECT_TRUE(FlingInProgress()); - - // Wait for the boosting timer to expire. The delayed cancelation must work. - GiveItSomeTime(500); - ProgressFling(); - EXPECT_FALSE(FlingInProgress()); EXPECT_EQ(WebMouseWheelEvent::kPhaseEnded, last_sent_wheel_.momentum_phase); EXPECT_EQ(0.f, last_sent_wheel_.delta_x); EXPECT_EQ(0.f, last_sent_wheel_.delta_y); } -// TODO(crbug.com/795617): Test timing expectations make it flaky. -TEST_F(FlingControllerTest, DISABLED_ControllerSendsWheelEndWhenFlingIsOver) { +TEST_F(FlingControllerTest, ControllerSendsWheelEndWhenFlingIsOver) { + base::TimeTicks progress_time = base::TimeTicks::Now(); SimulateFlingStart(blink::kWebGestureDeviceTouchpad, gfx::Vector2dF(100, 0)); EXPECT_TRUE(FlingInProgress()); - GiveItSomeTime(17); - ProgressFling(); + progress_time += base::TimeDelta::FromMilliseconds(17); + ProgressFling(progress_time); EXPECT_EQ(WebMouseWheelEvent::kPhaseBegan, last_sent_wheel_.momentum_phase); EXPECT_GT(last_sent_wheel_.delta_x, 0.f); - GiveItSomeTime(17); - ProgressFling(); + progress_time += base::TimeDelta::FromMilliseconds(17); + ProgressFling(progress_time); while (FlingInProgress()) { EXPECT_EQ(WebMouseWheelEvent::kPhaseChanged, last_sent_wheel_.momentum_phase); EXPECT_GT(last_sent_wheel_.delta_x, 0.f); - GiveItSomeTime(17); - ProgressFling(); + progress_time += base::TimeDelta::FromMilliseconds(17); + ProgressFling(progress_time); } EXPECT_EQ(WebMouseWheelEvent::kPhaseEnded, last_sent_wheel_.momentum_phase); @@ -196,13 +179,12 @@ EXPECT_EQ(0.f, last_sent_wheel_.delta_y); } -// TODO(crbug.com/795617): Test timing expectations make it flaky. -TEST_F(FlingControllerTest, - DISABLED_EarlyFlingCancelationOnInertialGSUAckNotConsumed) { +TEST_F(FlingControllerTest, EarlyFlingCancelationOnInertialGSUAckNotConsumed) { + base::TimeTicks progress_time = base::TimeTicks::Now(); SimulateFlingStart(blink::kWebGestureDeviceTouchpad, gfx::Vector2dF(1000, 0)); EXPECT_TRUE(FlingInProgress()); - GiveItSomeTime(17); - ProgressFling(); + progress_time += base::TimeDelta::FromMilliseconds(17); + ProgressFling(progress_time); EXPECT_EQ(WebMouseWheelEvent::kPhaseBegan, last_sent_wheel_.momentum_phase); EXPECT_GT(last_sent_wheel_.delta_x, 0.f); @@ -222,19 +204,21 @@ EXPECT_EQ(0.f, last_sent_wheel_.delta_y); } -// TODO(crbug.com/795617): Test timing expectations make it flaky. +// TODO(sahel): Enable the test once boosting is enabled for touchpad fling. +// https://crbug.com/249063 TEST_F(FlingControllerTest, DISABLED_ControllerBoostsFling) { + base::TimeTicks progress_time = base::TimeTicks::Now(); SimulateFlingStart(blink::kWebGestureDeviceTouchpad, gfx::Vector2dF(1000, 0)); EXPECT_TRUE(FlingInProgress()); // The first wheel event must have momentum_phase == KPhaseBegan. - GiveItSomeTime(17); - ProgressFling(); + progress_time += base::TimeDelta::FromMilliseconds(17); + ProgressFling(progress_time); EXPECT_EQ(WebMouseWheelEvent::kPhaseBegan, last_sent_wheel_.momentum_phase); EXPECT_GT(last_sent_wheel_.delta_x, 0.f); // The rest of the wheel events must have momentum_phase == KPhaseChanged. - GiveItSomeTime(17); - ProgressFling(); + progress_time += base::TimeDelta::FromMilliseconds(17); + ProgressFling(progress_time); EXPECT_EQ(WebMouseWheelEvent::kPhaseChanged, last_sent_wheel_.momentum_phase); EXPECT_GT(last_sent_wheel_.delta_x, 0.f);
diff --git a/content/browser/renderer_host/input/input_router_impl.cc b/content/browser/renderer_host/input/input_router_impl.cc index 793a1941..ab3df8f 100644 --- a/content/browser/renderer_host/input/input_router_impl.cc +++ b/content/browser/renderer_host/input/input_router_impl.cc
@@ -34,6 +34,8 @@ #include "ui/events/event.h" #include "ui/events/keycodes/keyboard_codes.h" +namespace content { + using base::Time; using base::TimeDelta; using base::TimeTicks; @@ -45,7 +47,6 @@ using blink::WebTouchEvent; using ui::WebInputEventTraits; -namespace content { namespace { bool WasHandled(InputEventAckState state) { @@ -551,11 +552,14 @@ } void InputRouterImpl::OnSetTouchAction(cc::TouchAction touch_action) { - // Synthetic touchstart events should get filtered out in RenderWidget. - DCHECK(touch_event_queue_.IsPendingAckTouchStart()); TRACE_EVENT1("input", "InputRouterImpl::OnSetTouchAction", "action", touch_action); + // It is possible we get a touch action for a touch start that is no longer + // in the queue. eg. Events that have fired the Touch ACK timeout. + if (!touch_event_queue_.IsPendingAckTouchStart()) + return; + touch_action_filter_.OnSetTouchAction(touch_action); // kTouchActionNone should disable the touch ack timeout.
diff --git a/content/browser/renderer_host/input/legacy_input_router_impl.cc b/content/browser/renderer_host/input/legacy_input_router_impl.cc index 4bfe6481..4331c9f 100644 --- a/content/browser/renderer_host/input/legacy_input_router_impl.cc +++ b/content/browser/renderer_host/input/legacy_input_router_impl.cc
@@ -484,11 +484,14 @@ } void LegacyInputRouterImpl::OnSetTouchAction(cc::TouchAction touch_action) { - // Synthetic touchstart events should get filtered out in RenderWidget. - DCHECK(touch_event_queue_->IsPendingAckTouchStart()); TRACE_EVENT1("input", "LegacyInputRouterImpl::OnSetTouchAction", "action", touch_action); + // It is possible we get a touch action for a touch start that is no longer + // in the queue. eg. Events that have fired the Touch ACK timeout. + if (!touch_event_queue_->IsPendingAckTouchStart()) + return; + touch_action_filter_.OnSetTouchAction(touch_action); // kTouchActionNone should disable the touch ack timeout.
diff --git a/content/browser/renderer_host/input/render_widget_host_latency_tracker_unittest.cc b/content/browser/renderer_host/input/render_widget_host_latency_tracker_unittest.cc index 2d7d1d2..b77cf6b 100644 --- a/content/browser/renderer_host/input/render_widget_host_latency_tracker_unittest.cc +++ b/content/browser/renderer_host/input/render_widget_host_latency_tracker_unittest.cc
@@ -144,7 +144,7 @@ } void ExpectUkmReported(const char* event_name, - const char* metric_name, + const std::vector<std::string>& metric_names, size_t expected_count) { const ukm::TestUkmRecorder* ukm_recoder = test_browser_client_.GetTestUkmRecorder(); @@ -153,7 +153,9 @@ EXPECT_EQ(expected_count, entries.size()); for (const auto* const entry : entries) { ukm_recoder->ExpectEntrySourceHasUrl(entry, GURL(kUrl)); - EXPECT_TRUE(ukm_recoder->EntryHasMetric(entry, metric_name)); + for (const auto& metric_name : metric_names) { + EXPECT_TRUE(ukm_recoder->EntryHasMetric(entry, metric_name.c_str())); + } } } @@ -289,8 +291,10 @@ // UKM metrics. total_ukm_entry_count++; - ExpectUkmReported("Event.ScrollBegin.Wheel", - "TimeToScrollUpdateSwapBegin", total_ukm_entry_count); + ExpectUkmReported( + "Event.ScrollBegin.Wheel", + {"TimeToScrollUpdateSwapBegin", "TimeToHandled", "IsMainThread"}, + total_ukm_entry_count); // Rappor metrics. EXPECT_TRUE( RapporSampleAssert("Event.Latency.ScrollUpdate.Touch." @@ -402,8 +406,10 @@ // UKM metrics. total_ukm_entry_count++; - ExpectUkmReported("Event.ScrollUpdate.Wheel", - "TimeToScrollUpdateSwapBegin", total_ukm_entry_count); + ExpectUkmReported( + "Event.ScrollUpdate.Wheel", + {"TimeToScrollUpdateSwapBegin", "TimeToHandled", "IsMainThread"}, + total_ukm_entry_count); // Rappor metrics. EXPECT_TRUE( RapporSampleAssert("Event.Latency.ScrollUpdate.Touch." @@ -538,8 +544,10 @@ // UKM metrics. total_ukm_entry_count++; - ExpectUkmReported("Event.ScrollBegin.Touch", "TimeToScrollUpdateSwapBegin", - total_ukm_entry_count); + ExpectUkmReported( + "Event.ScrollBegin.Touch", + {"TimeToScrollUpdateSwapBegin", "TimeToHandled", "IsMainThread"}, + total_ukm_entry_count); // Rappor metrics. EXPECT_TRUE( RapporSampleAssert("Event.Latency.ScrollUpdate.Touch." @@ -659,8 +667,10 @@ // UKM metrics. total_ukm_entry_count++; - ExpectUkmReported("Event.ScrollUpdate.Touch", "TimeToScrollUpdateSwapBegin", - total_ukm_entry_count); + ExpectUkmReported( + "Event.ScrollUpdate.Touch", + {"TimeToScrollUpdateSwapBegin", "TimeToHandled", "IsMainThread"}, + total_ukm_entry_count); // Rappor metrics. EXPECT_TRUE(
diff --git a/content/browser/renderer_host/input/synthetic_gesture_target_base.cc b/content/browser/renderer_host/input/synthetic_gesture_target_base.cc index 680b676c..f451534b 100644 --- a/content/browser/renderer_host/input/synthetic_gesture_target_base.cc +++ b/content/browser/renderer_host/input/synthetic_gesture_target_base.cc
@@ -55,27 +55,35 @@ static_cast<const WebTouchEvent&>(event); // Check that all touch pointers are within the content bounds. - for (unsigned i = 0; i < web_touch.touches_length; i++) - CHECK(web_touch.touches[i].state != WebTouchPoint::kStatePressed || - PointIsWithinContents(web_touch.touches[i].PositionInWidget().x, - web_touch.touches[i].PositionInWidget().y)) - << "Touch coordinates are not within content bounds on TouchStart."; - + for (unsigned i = 0; i < web_touch.touches_length; i++) { + if (web_touch.touches[i].state == WebTouchPoint::kStatePressed && + !PointIsWithinContents(web_touch.touches[i].PositionInWidget().x, + web_touch.touches[i].PositionInWidget().y)) { + LOG(WARNING) + << "Touch coordinates are not within content bounds on TouchStart."; + return; + } + } DispatchWebTouchEventToPlatform(web_touch, latency_info); } else if (event.GetType() == WebInputEvent::kMouseWheel) { const WebMouseWheelEvent& web_wheel = static_cast<const WebMouseWheelEvent&>(event); - CHECK(PointIsWithinContents(web_wheel.PositionInWidget().x, - web_wheel.PositionInWidget().y)) - << "Mouse wheel position is not within content bounds."; + if (!PointIsWithinContents(web_wheel.PositionInWidget().x, + web_wheel.PositionInWidget().y)) { + LOG(WARNING) << "Mouse wheel position is not within content bounds."; + return; + } DispatchWebMouseWheelEventToPlatform(web_wheel, latency_info); } else if (WebInputEvent::IsMouseEventType(event.GetType())) { const WebMouseEvent& web_mouse = static_cast<const WebMouseEvent&>(event); - CHECK(event.GetType() != WebInputEvent::kMouseDown || - PointIsWithinContents(web_mouse.PositionInWidget().x, - web_mouse.PositionInWidget().y)) - << "Mouse pointer is not within content bounds on MouseDown."; + if (event.GetType() == WebInputEvent::kMouseDown && + !PointIsWithinContents(web_mouse.PositionInWidget().x, + web_mouse.PositionInWidget().y)) { + LOG(WARNING) + << "Mouse pointer is not within content bounds on MouseDown."; + return; + } DispatchWebMouseEventToPlatform(web_mouse, latency_info); } else { NOTREACHED();
diff --git a/content/browser/renderer_host/media/video_capture_controller.cc b/content/browser/renderer_host/media/video_capture_controller.cc index d4fa9fb..66487ed 100644 --- a/content/browser/renderer_host/media/video_capture_controller.cc +++ b/content/browser/renderer_host/media/video_capture_controller.cc
@@ -160,7 +160,14 @@ mojo::ScopedSharedBufferHandle VideoCaptureController::BufferContext::CloneHandle() { - return buffer_handle_->Clone(mojo::SharedBufferHandle::AccessMode::READ_ONLY); + // Special behavior here: If the handle was already read-only, the Clone() + // call here will maintain that read-only permission. If it was read-write, + // the cloned handle will have read-write permission. + // + // TODO(crbug.com/797470): We should be able to demote read-write to read-only + // permissions when Clone()'ing handles. Currently, this causes a crash. + return buffer_handle_->Clone( + mojo::SharedBufferHandle::AccessMode::READ_WRITE); } VideoCaptureController::VideoCaptureController(
diff --git a/content/browser/renderer_host/render_widget_host_view_aura_unittest.cc b/content/browser/renderer_host/render_widget_host_view_aura_unittest.cc index f87d722b..6123277 100644 --- a/content/browser/renderer_host/render_widget_host_view_aura_unittest.cc +++ b/content/browser/renderer_host/render_widget_host_view_aura_unittest.cc
@@ -4372,27 +4372,25 @@ EXPECT_EQ(OVERSCROLL_EAST, overscroll_mode()); EXPECT_EQ(OverscrollSource::TOUCHPAD, overscroll_source()); - // ProgressFling will send a nonblocking wheel end event. The generated GSE - // resets the overscroll state. - widget_host_->ProgressFling(base::TimeTicks::Now() + - base::TimeDelta::FromMilliseconds(20)); - - EXPECT_EQ(OVERSCROLL_NONE, overscroll_mode()); + base::TimeTicks progress_time = + base::TimeTicks::Now() + base::TimeDelta::FromMilliseconds(17); + // Overscroll mode will get reset at the end of the fling progress. + while (overscroll_mode() != OVERSCROLL_NONE) { + widget_host_->ProgressFling(progress_time); + progress_time += base::TimeDelta::FromMilliseconds(17); + } EXPECT_EQ(OverscrollSource::NONE, overscroll_source()); } -// TODO(crbug.com/795617): Test timing expectations make it flaky. TEST_F(RenderWidgetHostViewAuraOverscrollTest, - DISABLED_ScrollEventsOverscrollWithFling) { + ScrollEventsOverscrollWithFling) { ScrollEventsOverscrollWithFling(); } -// TODO(crbug.com/795617): Test timing expectations make it flaky. TEST_F(RenderWidgetHostViewAuraOverscrollWithoutWheelScrollLatchingTest, - DISABLED_ScrollEventsOverscrollWithFling) { + ScrollEventsOverscrollWithFling) { ScrollEventsOverscrollWithFling(); } -// TODO(crbug.com/795617): Test timing expectations make it flaky. TEST_F(RenderWidgetHostViewAuraOverScrollAsyncWheelEventsEnabledTest, - DISABLED_ScrollEventsOverscrollWithFling) { + ScrollEventsOverscrollWithFling) { ScrollEventsOverscrollWithFling(); } @@ -5829,27 +5827,23 @@ // queued in gesture event queue. EXPECT_EQ(0U, events.size()); - // The first ProgressFling will send a nonblocking wheel end event. The GSE - // generated from the wheel end event resets the overscroll state. - widget_host_->ProgressFling(base::TimeTicks::Now() + - base::TimeDelta::FromMilliseconds(20)); - - EXPECT_EQ(0.f, overscroll_delta_x()); - EXPECT_EQ(0.f, overscroll_delta_y()); + base::TimeTicks progress_time = + base::TimeTicks::Now() + base::TimeDelta::FromMilliseconds(17); + // Overscroll delta will get reset at the end of the fling progress. + while (overscroll_delta_y() != 0.f) { + widget_host_->ProgressFling(progress_time); + progress_time += base::TimeDelta::FromMilliseconds(17); + } } -// TODO(crbug.com/795617): Test timing expectations make it flaky. -TEST_F(RenderWidgetHostViewAuraOverscrollTest, - DISABLED_ScrollDeltasResetOnEnd) { +TEST_F(RenderWidgetHostViewAuraOverscrollTest, ScrollDeltasResetOnEnd) { ScrollDeltasResetOnEnd(); } -// TODO(crbug.com/795617): Test timing expectations make it flaky. TEST_F(RenderWidgetHostViewAuraOverscrollWithoutWheelScrollLatchingTest, - DISABLED_ScrollDeltasResetOnEnd) { + ScrollDeltasResetOnEnd) { ScrollDeltasResetOnEnd(); } -// TODO(crbug.com/795617): Test timing expectations make it flaky. TEST_F(RenderWidgetHostViewAuraOverScrollAsyncWheelEventsEnabledTest, - DISABLED_ScrollDeltasResetOnEnd) { + ScrollDeltasResetOnEnd) { ScrollDeltasResetOnEnd(); }
diff --git a/content/browser/renderer_host/render_widget_host_view_child_frame.cc b/content/browser/renderer_host/render_widget_host_view_child_frame.cc index 4a2d0fc5..abecc15 100644 --- a/content/browser/renderer_host/render_widget_host_view_child_frame.cc +++ b/content/browser/renderer_host/render_widget_host_view_child_frame.cc
@@ -605,7 +605,8 @@ void RenderWidgetHostViewChildFrame::SendSurfaceInfoToEmbedderImpl( const viz::SurfaceInfo& surface_info, const viz::SurfaceSequence& sequence) { - frame_connector_->SetChildFrameSurface(surface_info, sequence); + if (frame_connector_) + frame_connector_->SetChildFrameSurface(surface_info, sequence); } void RenderWidgetHostViewChildFrame::SubmitCompositorFrame(
diff --git a/content/browser/renderer_interface_binders.cc b/content/browser/renderer_interface_binders.cc index 17af3972..79948d6 100644 --- a/content/browser/renderer_interface_binders.cc +++ b/content/browser/renderer_interface_binders.cc
@@ -87,7 +87,7 @@ connector->BindInterface(service_name, std::move(request)); } -void GetRestrictedCookieManager( +void GetRestrictedCookieManagerForWorker( network::mojom::RestrictedCookieManagerRequest request, RenderProcessHost* render_process_host, const url::Origin& origin) { @@ -163,7 +163,7 @@ parameterized_binder_registry_.AddInterface( base::BindRepeating(&BackgroundFetchServiceImpl::Create)); parameterized_binder_registry_.AddInterface( - base::BindRepeating(GetRestrictedCookieManager)); + base::BindRepeating(GetRestrictedCookieManagerForWorker)); } RendererInterfaceBinders& GetRendererInterfaceBinders() {
diff --git a/content/browser/service_manager/service_manager_context.cc b/content/browser/service_manager/service_manager_context.cc index dc20985..a7e9505 100644 --- a/content/browser/service_manager/service_manager_context.cc +++ b/content/browser/service_manager/service_manager_context.cc
@@ -4,6 +4,7 @@ #include "content/browser/service_manager/service_manager_context.h" +#include <map> #include <memory> #include <string> #include <utility> @@ -14,6 +15,7 @@ #include "base/json/json_reader.h" #include "base/lazy_instance.h" #include "base/macros.h" +#include "base/memory/weak_ptr.h" #include "base/message_loop/message_loop.h" #include "base/process/process_handle.h" #include "base/single_thread_task_runner.h" @@ -101,12 +103,16 @@ base::LazyInstance<std::unique_ptr<service_manager::Connector>>::Leaky g_io_thread_connector = LAZY_INSTANCE_INITIALIZER; +base::LazyInstance<std::map<std::string, base::WeakPtr<UtilityProcessHost>>>:: + Leaky g_active_process_groups; + void DestroyConnectorOnIOThread() { g_io_thread_connector.Get().reset(); } // Launch a process for a service once its sandbox type is known. void StartServiceInUtilityProcess( const std::string& service_name, const base::string16& process_name, + base::Optional<std::string> process_group, service_manager::mojom::ServiceRequest request, service_manager::mojom::ConnectResult query_result, const std::string& sandbox_string) { @@ -114,16 +120,30 @@ service_manager::SandboxType sandbox_type = service_manager::UtilitySandboxTypeFromString(sandbox_string); - UtilityProcessHostImpl* process_host = - new UtilityProcessHostImpl(nullptr, nullptr); + // Look for an existing process group. + base::WeakPtr<UtilityProcessHost>* weak_host = nullptr; + if (process_group) + weak_host = &g_active_process_groups.Get()[*process_group]; + + UtilityProcessHost* process_host = nullptr; + if (weak_host && *weak_host) { + // Start service in an existing process. + process_host = weak_host->get(); + } else { + // Start a new process for this service. + UtilityProcessHostImpl* impl = new UtilityProcessHostImpl(nullptr, nullptr); #if defined(OS_WIN) - if (sandbox_type == service_manager::SANDBOX_TYPE_PDF_COMPOSITOR) - process_host->AddFilter(new DWriteFontProxyMessageFilter()); + if (sandbox_type == service_manager::SANDBOX_TYPE_PDF_COMPOSITOR) + impl->AddFilter(new DWriteFontProxyMessageFilter()); #endif - process_host->SetName(process_name); - process_host->SetServiceIdentity(service_manager::Identity(service_name)); - process_host->SetSandboxType(sandbox_type); - process_host->Start(); + impl->SetName(process_name); + impl->SetServiceIdentity(service_manager::Identity(service_name)); + impl->SetSandboxType(sandbox_type); + impl->Start(); + if (weak_host) + *weak_host = impl->AsWeakPtr(); + process_host = impl; + } service_manager::mojom::ServiceFactoryPtr service_factory; BindInterface(process_host, mojo::MakeRequest(&service_factory)); @@ -134,12 +154,13 @@ void QueryAndStartServiceInUtilityProcess( const std::string& service_name, const base::string16& process_name, + base::Optional<std::string> process_group, service_manager::mojom::ServiceRequest request) { DCHECK_CURRENTLY_ON(BrowserThread::IO); ServiceManagerContext::GetConnectorForIOThread()->QueryService( service_manager::Identity(service_name), base::BindOnce(&StartServiceInUtilityProcess, service_name, process_name, - std::move(request))); + std::move(process_group), std::move(request))); } // Request service_manager::mojom::ServiceFactory from GPU process host. Must be @@ -556,8 +577,10 @@ for (const auto& service : out_of_process_services) { packaged_services_connection_->AddServiceRequestHandler( - service.first, base::Bind(&QueryAndStartServiceInUtilityProcess, - service.first, service.second)); + service.first, + base::BindRepeating(&QueryAndStartServiceInUtilityProcess, + service.first, service.second.process_name, + service.second.process_group)); } #if BUILDFLAG(ENABLE_MOJO_MEDIA_IN_GPU_PROCESS) @@ -603,4 +626,11 @@ return g_io_thread_connector.Get().get(); } +// static +std::map<std::string, base::WeakPtr<UtilityProcessHost>>* +ServiceManagerContext::GetProcessGroupsForTesting() { + DCHECK_CURRENTLY_ON(BrowserThread::IO); + return &g_active_process_groups.Get(); +} + } // namespace content
diff --git a/content/browser/service_manager/service_manager_context.h b/content/browser/service_manager/service_manager_context.h index d5efe08..4fa4ce6f 100644 --- a/content/browser/service_manager/service_manager_context.h +++ b/content/browser/service_manager/service_manager_context.h
@@ -5,8 +5,11 @@ #ifndef CONTENT_BROWSER_SERVICE_MANAGER_SERVICE_MANAGER_CONTEXT_H_ #define CONTENT_BROWSER_SERVICE_MANAGER_SERVICE_MANAGER_CONTEXT_H_ +#include <map> + #include "base/macros.h" #include "base/memory/ref_counted.h" +#include "base/memory/weak_ptr.h" #include "content/common/content_export.h" namespace service_manager { @@ -16,6 +19,7 @@ namespace content { class ServiceManagerConnection; +class UtilityProcessHost; // ServiceManagerContext manages the browser's connection to the ServiceManager, // hosting a new in-process ServiceManagerContext if the browser was not @@ -28,6 +32,9 @@ // Returns a service_manager::Connector that can be used on the IO thread. static service_manager::Connector* GetConnectorForIOThread(); + static std::map<std::string, base::WeakPtr<UtilityProcessHost>>* + GetProcessGroupsForTesting(); + private: class InProcessServiceManagerContext;
diff --git a/content/child/service_factory.cc b/content/child/service_factory.cc index cb1fcd5..3810699 100644 --- a/content/child/service_factory.cc +++ b/content/child/service_factory.cc
@@ -37,6 +37,11 @@ auto it = services_.find(name); if (it == services_.end()) { + // DCHECK in developer builds to make these errors easier to identify. + // Otherwise they result only in cryptic browser error messages. + NOTREACHED() << "Unable to start service \"" << name << "\". Did you " + << "forget to register the service in the utility process's" + << "ServiceFactory?"; OnLoadFailed(); return; }
diff --git a/content/network/BUILD.gn b/content/network/BUILD.gn index 54cbb91..64c24690 100644 --- a/content/network/BUILD.gn +++ b/content/network/BUILD.gn
@@ -36,8 +36,6 @@ sources = [ "cache_url_loader.cc", "cache_url_loader.h", - "cookie_manager.cc", - "cookie_manager.h", "data_pipe_element_reader.cc", "data_pipe_element_reader.h", "http_server_properties_pref_delegate.cc", @@ -96,6 +94,7 @@ "//net", "//net:extras", "//net:net_browser_services", + "//services/network:network_service", "//services/network/public/cpp", "//services/proxy_resolver/public/interfaces", "//services/service_manager/public/cpp",
diff --git a/content/network/http_server_properties_pref_delegate.cc b/content/network/http_server_properties_pref_delegate.cc index af2aebc9..8621b81 100644 --- a/content/network/http_server_properties_pref_delegate.cc +++ b/content/network/http_server_properties_pref_delegate.cc
@@ -32,12 +32,15 @@ } void HttpServerPropertiesPrefDelegate::SetServerProperties( - const base::DictionaryValue& value) { - return pref_service_->Set(kPrefPath, value); + const base::DictionaryValue& value, + base::OnceClosure callback) { + pref_service_->Set(kPrefPath, value); + if (callback) + pref_service_->CommitPendingWrite(std::move(callback)); } void HttpServerPropertiesPrefDelegate::StartListeningForUpdates( - const base::Closure& callback) { + const base::RepeatingClosure& callback) { pref_change_registrar_.Add(kPrefPath, callback); // PrefChangeRegistrar isn't notified of initial pref load, so watch for that, // too.
diff --git a/content/network/http_server_properties_pref_delegate.h b/content/network/http_server_properties_pref_delegate.h index 8e5ed906..a2f88b59 100644 --- a/content/network/http_server_properties_pref_delegate.h +++ b/content/network/http_server_properties_pref_delegate.h
@@ -5,6 +5,7 @@ #ifndef CONTENT_NETWORK_HTTP_SERVER_PROPERTIES_PREF_DELEGATE_H_ #define CONTENT_NETWORK_HTTP_SERVER_PROPERTIES_PREF_DELEGATE_H_ +#include "base/callback.h" #include "base/macros.h" #include "components/prefs/pref_change_registrar.h" #include "net/http/http_server_properties.h" @@ -26,8 +27,10 @@ // net::HttpServerPropertiesManager::PrefDelegate implementation. const base::DictionaryValue* GetServerProperties() const override; - void SetServerProperties(const base::DictionaryValue& value) override; - void StartListeningForUpdates(const base::Closure& callback) override; + void SetServerProperties(const base::DictionaryValue& value, + base::OnceClosure callback) override; + void StartListeningForUpdates( + const base::RepeatingClosure& callback) override; private: PrefService* pref_service_;
diff --git a/content/network/network_context.cc b/content/network/network_context.cc index b5afdd3d..c9434e5 100644 --- a/content/network/network_context.cc +++ b/content/network/network_context.cc
@@ -61,8 +61,8 @@ binding_(this, std::move(request)) { url_request_context_owner_ = MakeURLRequestContext(params_.get()); url_request_context_ = url_request_context_owner_.url_request_context.get(); - cookie_manager_ = - std::make_unique<CookieManager>(url_request_context_->cookie_store()); + cookie_manager_ = std::make_unique<network::CookieManager>( + url_request_context_->cookie_store()); network_service_->RegisterNetworkContext(this); binding_.set_connection_error_handler(base::BindOnce( &NetworkContext::OnConnectionError, base::Unretained(this))); @@ -84,8 +84,8 @@ network_service->net_log()); url_request_context_ = url_request_context_owner_.url_request_context.get(); network_service_->RegisterNetworkContext(this); - cookie_manager_ = - std::make_unique<CookieManager>(url_request_context_->cookie_store()); + cookie_manager_ = std::make_unique<network::CookieManager>( + url_request_context_->cookie_store()); } NetworkContext::NetworkContext(NetworkServiceImpl* network_service, @@ -94,7 +94,7 @@ : network_service_(network_service), url_request_context_(url_request_context), binding_(this, std::move(request)), - cookie_manager_(std::make_unique<CookieManager>( + cookie_manager_(std::make_unique<network::CookieManager>( url_request_context->cookie_store())) { // May be nullptr in tests. if (network_service_) @@ -373,8 +373,8 @@ url_request_context_->transport_security_state()->DeleteAllDynamicDataSince( time); - url_request_context_->http_server_properties()->Clear(); - std::move(completion_callback).Run(); + url_request_context_->http_server_properties()->Clear( + std::move(completion_callback)); } void NetworkContext::SetNetworkConditions(
diff --git a/content/network/network_context.h b/content/network/network_context.h index a877ede..3e65451 100644 --- a/content/network/network_context.h +++ b/content/network/network_context.h
@@ -14,12 +14,12 @@ #include "base/macros.h" #include "base/time/time.h" #include "content/common/content_export.h" -#include "content/network/cookie_manager.h" #include "content/public/common/network_service.mojom.h" #include "content/public/common/url_loader_factory.mojom.h" #include "content/public/network/url_request_context_owner.h" #include "mojo/public/cpp/bindings/binding.h" #include "mojo/public/cpp/bindings/strong_binding_set.h" +#include "services/network/cookie_manager.h" namespace net { class URLRequestContext; @@ -142,7 +142,7 @@ mojo::Binding<mojom::NetworkContext> binding_; - std::unique_ptr<CookieManager> cookie_manager_; + std::unique_ptr<network::CookieManager> cookie_manager_; DISALLOW_COPY_AND_ASSIGN(NetworkContext); };
diff --git a/content/public/browser/content_browser_client.cc b/content/public/browser/content_browser_client.cc index 89486de..445422c 100644 --- a/content/public/browser/content_browser_client.cc +++ b/content/public/browser/content_browser_client.cc
@@ -519,6 +519,26 @@ return nullptr; } +ContentBrowserClient::OutOfProcessServiceInfo::OutOfProcessServiceInfo() = + default; + +ContentBrowserClient::OutOfProcessServiceInfo::OutOfProcessServiceInfo( + const base::string16& process_name) + : process_name(process_name) { + DCHECK(!process_name.empty()); +} + +ContentBrowserClient::OutOfProcessServiceInfo::OutOfProcessServiceInfo( + const base::string16& process_name, + const std::string& process_group) + : process_name(process_name), process_group(process_group) { + DCHECK(!process_name.empty()); + DCHECK(!process_group.empty()); +} + +ContentBrowserClient::OutOfProcessServiceInfo::~OutOfProcessServiceInfo() = + default; + bool ContentBrowserClient::ShouldTerminateOnServiceQuit( const service_manager::Identity& id) { return false;
diff --git a/content/public/browser/content_browser_client.h b/content/public/browser/content_browser_client.h index d83ad513..bb21f85 100644 --- a/content/public/browser/content_browser_client.h +++ b/content/public/browser/content_browser_client.h
@@ -14,6 +14,7 @@ #include <vector> #include "base/callback.h" +#include "base/optional.h" #include "base/task_scheduler/task_scheduler.h" #include "base/values.h" #include "build/build_config.h" @@ -788,7 +789,22 @@ const std::string& name, mojo::ScopedMessagePipeHandle* handle) {} - using OutOfProcessServiceMap = std::map<std::string, base::string16>; + struct CONTENT_EXPORT OutOfProcessServiceInfo { + OutOfProcessServiceInfo(); + OutOfProcessServiceInfo(const base::string16& process_name); + OutOfProcessServiceInfo(const base::string16& process_name, + const std::string& process_group); + ~OutOfProcessServiceInfo(); + + // The display name of the service process launched for the service. + base::string16 process_name; + + // If provided, a string which groups this service into a process shared + // by other services using the same string. + base::Optional<std::string> process_group; + }; + + using OutOfProcessServiceMap = std::map<std::string, OutOfProcessServiceInfo>; // Registers services to be loaded out of the browser process in an // utility process. The value of each map entry should be a process name,
diff --git a/content/public/browser/file_url_loader.h b/content/public/browser/file_url_loader.h index e467256a..8fce1a4 100644 --- a/content/public/browser/file_url_loader.h +++ b/content/public/browser/file_url_loader.h
@@ -5,16 +5,34 @@ #ifndef CONTENT_PUBLIC_BROWSER_FILE_URL_LOADER_H_ #define CONTENT_PUBLIC_BROWSER_FILE_URL_LOADER_H_ +#include <memory> + #include "content/common/content_export.h" #include "content/public/common/url_loader.mojom.h" +#include "mojo/public/cpp/system/file_data_pipe_producer.h" namespace content { struct ResourceRequest; +class CONTENT_EXPORT FileURLLoaderObserver + : public mojo::FileDataPipeProducer::Observer { + public: + FileURLLoaderObserver() {} + ~FileURLLoaderObserver() override {} + + virtual void OnStart() {} + virtual void OnOpenComplete(int result) {} + virtual void OnSeekComplete(int64_t result) {} + + private: + DISALLOW_COPY_AND_ASSIGN(FileURLLoaderObserver); +}; + // Helper to create a self-owned URLLoader instance which fulfills |request| // using the contents of the file at |path|. The URL in |request| must be a -// file:// URL. +// file:// URL. The *optionally* supplied |observer| will be called to report +// progress during the file loading. // // Note that this does not restrict filesystem access *in any way*, so if the // file at |path| is accessible to the browser, it will be loaded and used to @@ -23,9 +41,11 @@ // The URLLoader created by this function does *not* automatically follow // filesytem links (e.g. Windows shortcuts) or support directory listing. // A directory path will always yield a FILE_NOT_FOUND network error. -CONTENT_EXPORT void CreateFileURLLoader(const ResourceRequest& request, - mojom::URLLoaderRequest loader, - mojom::URLLoaderClientPtr client); +CONTENT_EXPORT void CreateFileURLLoader( + const ResourceRequest& request, + mojom::URLLoaderRequest loader, + mojom::URLLoaderClientPtr client, + std::unique_ptr<FileURLLoaderObserver> observer); } // namespace content
diff --git a/content/public/test/android/javatests/src/org/chromium/content/browser/test/ContentJUnit4ClassRunner.java b/content/public/test/android/javatests/src/org/chromium/content/browser/test/ContentJUnit4ClassRunner.java index 7f98748..0d48cc9 100644 --- a/content/public/test/android/javatests/src/org/chromium/content/browser/test/ContentJUnit4ClassRunner.java +++ b/content/public/test/android/javatests/src/org/chromium/content/browser/test/ContentJUnit4ClassRunner.java
@@ -8,9 +8,9 @@ import org.junit.runners.model.InitializationError; -import org.chromium.base.BaseChromiumApplication; import org.chromium.base.CollectionUtil; import org.chromium.base.CommandLine; +import org.chromium.base.CommandLineInitUtil; import org.chromium.base.test.BaseJUnit4ClassRunner; import org.chromium.base.test.BaseTestResult.PreTestHook; import org.chromium.base.test.util.CommandLineFlags; @@ -51,6 +51,7 @@ @Override protected void initCommandLineForTest() { - BaseChromiumApplication.initCommandLine(InstrumentationRegistry.getTargetContext()); + CommandLineInitUtil.initCommandLine( + InstrumentationRegistry.getTargetContext(), CommandLineFlags.getTestCmdLineFile()); } }
diff --git a/content/public/test/browser_test_utils.cc b/content/public/test/browser_test_utils.cc index 611e51e..29f4a84 100644 --- a/content/public/test/browser_test_utils.cc +++ b/content/public/test/browser_test_utils.cc
@@ -44,6 +44,7 @@ #include "content/browser/renderer_host/render_widget_host_impl.h" #include "content/browser/renderer_host/render_widget_host_input_event_router.h" #include "content/browser/renderer_host/render_widget_host_view_child_frame.h" +#include "content/browser/service_manager/service_manager_context.h" #include "content/browser/web_contents/web_contents_impl.h" #include "content/browser/web_contents/web_contents_view.h" #include "content/common/fileapi/file_system_messages.h" @@ -2405,4 +2406,9 @@ return simple_loader->NetError(); } +std::map<std::string, base::WeakPtr<UtilityProcessHost>>* +GetServiceManagerProcessGroups() { + return ServiceManagerContext::GetProcessGroupsForTesting(); +} + } // namespace content
diff --git a/content/public/test/browser_test_utils.h b/content/public/test/browser_test_utils.h index 3a08b5b..905a078 100644 --- a/content/public/test/browser_test_utils.h +++ b/content/public/test/browser_test_utils.h
@@ -15,6 +15,7 @@ #include "base/files/scoped_temp_dir.h" #include "base/macros.h" #include "base/memory/ref_counted.h" +#include "base/memory/weak_ptr.h" #include "base/process/process.h" #include "base/run_loop.h" #include "base/strings/string16.h" @@ -75,6 +76,7 @@ class RenderViewHost; class RenderWidgetHost; class RenderWidgetHostView; +class UtilityProcessHost; class WebContents; // Navigate a frame with ID |iframe_id| to |url|, blocking until the navigation @@ -1077,6 +1079,9 @@ int process_id = 0, int render_frame_id = 0); +std::map<std::string, base::WeakPtr<UtilityProcessHost>>* +GetServiceManagerProcessGroups(); + } // namespace content #endif // CONTENT_PUBLIC_TEST_BROWSER_TEST_UTILS_H_
diff --git a/content/renderer/device_sensors/device_sensor_event_pump.h b/content/renderer/device_sensors/device_sensor_event_pump.h index acfa17d..3fdc3d9 100644 --- a/content/renderer/device_sensors/device_sensor_event_pump.h +++ b/content/renderer/device_sensors/device_sensor_event_pump.h
@@ -102,6 +102,11 @@ // Mojo callback for SensorProvider::GetSensor(). void OnSensorCreated(device::mojom::SensorInitParamsPtr params) { + // TODO(798409): `OnSensorCreated` can be called twice in some cases, this + // is a workaround to avoid hitting unexpected code paths. + if (sensor.is_bound()) + return; + if (!params) { HandleSensorError(); event_pump->DidStartIfPossible();
diff --git a/content/renderer/media/video_capture_impl.cc b/content/renderer/media/video_capture_impl.cc index 6c26751d..f658e91 100644 --- a/content/renderer/media/video_capture_impl.cc +++ b/content/renderer/media/video_capture_impl.cc
@@ -309,7 +309,7 @@ const auto& iter = client_buffers_.find(buffer_id); DCHECK(iter != client_buffers_.end()); - const scoped_refptr<ClientBuffer> buffer = iter->second; + scoped_refptr<ClientBuffer> buffer = iter->second; scoped_refptr<media::VideoFrame> frame = media::VideoFrame::WrapExternalSharedMemory( static_cast<media::VideoPixelFormat>(info->pixel_format), @@ -322,12 +322,11 @@ return; } - BufferFinishedCallback buffer_finished_callback = media::BindToCurrentLoop( - base::Bind(&VideoCaptureImpl::OnClientBufferFinished, - weak_factory_.GetWeakPtr(), buffer_id, buffer)); - frame->AddDestructionObserver( - base::BindOnce(&VideoCaptureImpl::DidFinishConsumingFrame, - frame->metadata(), buffer_finished_callback)); + frame->AddDestructionObserver(base::BindOnce( + &VideoCaptureImpl::DidFinishConsumingFrame, frame->metadata(), + media::BindToCurrentLoop(base::BindOnce( + &VideoCaptureImpl::OnClientBufferFinished, weak_factory_.GetWeakPtr(), + buffer_id, std::move(buffer))))); frame->metadata()->MergeInternalValuesFrom(*info->metadata); @@ -350,9 +349,29 @@ void VideoCaptureImpl::OnClientBufferFinished( int buffer_id, - const scoped_refptr<ClientBuffer>& /* ignored_buffer */, + scoped_refptr<ClientBuffer> buffer, double consumer_resource_utilization) { DCHECK(io_thread_checker_.CalledOnValidThread()); + +// Subtle race note: It's important that the |buffer| argument be +// std::move()'ed to this method and never copied. This is so that the caller, +// DidFinishConsumingFrame(), does not implicitly retain a reference while it +// is running the trampoline callback on another thread. This is necessary to +// ensure the reference count on the ClientBuffer will be correct at the time +// OnBufferDestroyed() is called. http://crbug.com/797851 +#if DCHECK_IS_ON() + // The ClientBuffer should have exactly two references to it at this point, + // one is this method's second argument and the other is from + // |client_buffers_|. + DCHECK(!buffer->HasOneRef()); + ClientBuffer* const buffer_raw_ptr = buffer.get(); + buffer = nullptr; + // Now there should be only one reference, from |client_buffers_|. + DCHECK(buffer_raw_ptr->HasOneRef()); +#else + buffer = nullptr; +#endif + GetVideoCaptureHost()->ReleaseBuffer( device_id_, buffer_id, consumer_resource_utilization); } @@ -436,7 +455,7 @@ // static void VideoCaptureImpl::DidFinishConsumingFrame( const media::VideoFrameMetadata* metadata, - const BufferFinishedCallback& callback_to_io_thread) { + BufferFinishedCallback callback_to_io_thread) { // Note: This function may be called on any thread by the VideoFrame // destructor. |metadata| is still valid for read-access at this point. double consumer_resource_utilization = -1.0; @@ -444,7 +463,7 @@ &consumer_resource_utilization)) { consumer_resource_utilization = -1.0; } - callback_to_io_thread.Run(consumer_resource_utilization); + std::move(callback_to_io_thread).Run(consumer_resource_utilization); } } // namespace content
diff --git a/content/renderer/media/video_capture_impl.h b/content/renderer/media/video_capture_impl.h index 55e8b53..40ffb2d 100644 --- a/content/renderer/media/video_capture_impl.h +++ b/content/renderer/media/video_capture_impl.h
@@ -88,12 +88,12 @@ using ClientInfoMap = std::map<int, ClientInfo>; using BufferFinishedCallback = - base::Callback<void(double consumer_resource_utilization)>; + base::OnceCallback<void(double consumer_resource_utilization)>; // Sends an IPC message to browser process when all clients are done with the // buffer. void OnClientBufferFinished(int buffer_id, - const scoped_refptr<ClientBuffer>& buffer, + scoped_refptr<ClientBuffer> buffer, double consumer_resource_utilization); void StopDevice(); @@ -118,7 +118,7 @@ // callback, to trampoline back to the IO thread with the values. static void DidFinishConsumingFrame( const media::VideoFrameMetadata* metadata, - const BufferFinishedCallback& callback_to_io_thread); + BufferFinishedCallback callback_to_io_thread); // |device_id_| and |session_id_| are different concepts, but we reuse the // same numerical value, passed on construction.
diff --git a/content/renderer/mouse_lock_dispatcher.cc b/content/renderer/mouse_lock_dispatcher.cc index eba09d86..c4702c5 100644 --- a/content/renderer/mouse_lock_dispatcher.cc +++ b/content/renderer/mouse_lock_dispatcher.cc
@@ -44,6 +44,10 @@ } } +void MouseLockDispatcher::ClearLockTarget() { + OnLockTargetDestroyed(target_); +} + bool MouseLockDispatcher::IsMouseLockedTo(LockTarget* target) { return mouse_locked_ && target_ == target; }
diff --git a/content/renderer/mouse_lock_dispatcher.h b/content/renderer/mouse_lock_dispatcher.h index b3bb8f3..d5c3be8 100644 --- a/content/renderer/mouse_lock_dispatcher.h +++ b/content/renderer/mouse_lock_dispatcher.h
@@ -40,6 +40,8 @@ // Clears out the reference to the |target| because it has or is being // destroyed. Unlocks if locked. The pointer will not be accessed. void OnLockTargetDestroyed(LockTarget* target); + // Clears out any reference to a lock target. Unlocks if locked. + void ClearLockTarget(); bool IsMouseLockedTo(LockTarget* target); // Allow lock target to consumed a mouse event, if it does return true.
diff --git a/content/renderer/render_widget_fullscreen_pepper.cc b/content/renderer/render_widget_fullscreen_pepper.cc index e8bdb50..44ff027f 100644 --- a/content/renderer/render_widget_fullscreen_pepper.cc +++ b/content/renderer/render_widget_fullscreen_pepper.cc
@@ -303,6 +303,11 @@ } void RenderWidgetFullscreenPepper::Destroy() { + // The plugin instance is going away reset any lock target that is set + // on the dispatcher since this object can still live and receive IPC + // responses and may call a dangling lock_target. + mouse_lock_dispatcher_->ClearLockTarget(); + // This function is called by the plugin instance as it's going away, so reset // plugin_ to NULL to avoid calling into a dangling pointer e.g. on Close(). plugin_ = nullptr;
diff --git a/content/shell/android/shell_apk/src/org/chromium/content_shell_apk/ContentShellActivity.java b/content/shell/android/shell_apk/src/org/chromium/content_shell_apk/ContentShellActivity.java index 85e8964..1ce2777 100644 --- a/content/shell/android/shell_apk/src/org/chromium/content_shell_apk/ContentShellActivity.java +++ b/content/shell/android/shell_apk/src/org/chromium/content_shell_apk/ContentShellActivity.java
@@ -17,7 +17,6 @@ import org.chromium.base.library_loader.LibraryLoader; import org.chromium.base.library_loader.LibraryProcessType; import org.chromium.base.library_loader.ProcessInitException; -import org.chromium.content.app.ContentApplication; import org.chromium.content.browser.BrowserStartupController; import org.chromium.content.browser.ContentViewCore; import org.chromium.content.browser.DeviceUtils; @@ -50,7 +49,7 @@ // Initializing the command line must occur before loading the library. if (!CommandLine.isInitialized()) { - ContentApplication.initCommandLine(this); + ((ContentShellApplication) getApplication()).initCommandLine(); String[] commandLineParams = getCommandLineParamsFromIntent(getIntent()); if (commandLineParams != null) { CommandLine.getInstance().appendSwitchesAndArguments(commandLineParams);
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 5c84c28..9384f7b 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
@@ -29,7 +29,6 @@ ApplicationStatus.initialize(this); } - @Override public void initCommandLine() { if (!CommandLine.isInitialized()) { CommandLine.initFromFile(COMMAND_LINE_FILE);
diff --git a/content/test/BUILD.gn b/content/test/BUILD.gn index 8387597d..1733b98 100644 --- a/content/test/BUILD.gn +++ b/content/test/BUILD.gn
@@ -1513,7 +1513,6 @@ "../common/throttling_url_loader_unittest.cc", "../common/unique_name_helper_unittest.cc", "../common/webplugininfo_unittest.cc", - "../network/cookie_manager_unittest.cc", "../network/data_pipe_element_reader_unittest.cc", "../network/network_change_manager_unittest.cc", "../network/network_context_unittest.cc",
diff --git a/content/test/gpu/gpu_tests/pixel_test_pages.py b/content/test/gpu/gpu_tests/pixel_test_pages.py index 7100cbb..6aba7a00 100644 --- a/content/test/gpu/gpu_tests/pixel_test_pages.py +++ b/content/test/gpu/gpu_tests/pixel_test_pages.py
@@ -696,7 +696,7 @@ 'filter_effects.html', base_name + '_CSSFilterEffects_NoOverlays', test_rect=[0, 0, 300, 300], - revision=6, + revision=7, tolerance=10, browser_args=['--disable-mac-overlays']), ]
diff --git a/content/test/layouttest_support.cc b/content/test/layouttest_support.cc index 2269d75..ae2a8ae7 100644 --- a/content/test/layouttest_support.cc +++ b/content/test/layouttest_support.cc
@@ -331,6 +331,9 @@ renderer_settings.allow_antialiasing &= !cmd->HasSwitch(cc::switches::kDisableCompositedAntialiasing); renderer_settings.highp_threshold_min = 2048; + // Keep texture sizes exactly matching the bounds of the RenderPass to avoid + // floating point badness in texcoords. + renderer_settings.dont_round_texture_sizes_for_pixel_tests = true; constexpr bool disable_display_vsync = false; constexpr double refresh_rate = 60.0;
diff --git a/device/geolocation/BUILD.gn b/device/geolocation/BUILD.gn index 3da82acf..b3673ae2 100644 --- a/device/geolocation/BUILD.gn +++ b/device/geolocation/BUILD.gn
@@ -53,6 +53,7 @@ "wifi_data_provider_manager.h", "wifi_data_provider_win.cc", "wifi_data_provider_win.h", + "wifi_polling_policy.cc", "wifi_polling_policy.h", ]
diff --git a/device/geolocation/location_arbitrator.cc b/device/geolocation/location_arbitrator.cc index fa0ffb01..4b8e546 100644 --- a/device/geolocation/location_arbitrator.cc +++ b/device/geolocation/location_arbitrator.cc
@@ -14,6 +14,7 @@ #include "build/build_config.h" #include "device/geolocation/network_location_provider.h" #include "device/geolocation/public/cpp/geoposition.h" +#include "device/geolocation/wifi_polling_policy.h" namespace device { @@ -33,7 +34,12 @@ is_permission_granted_(false), is_running_(false) {} -LocationArbitrator::~LocationArbitrator() = default; +LocationArbitrator::~LocationArbitrator() { + // Destroy the global WifiPollingPolicy. The policy is created and used by the + // network location provider but should be retained across network provider + // restarts to ensure the time of the most recent WiFi scan is not lost. + WifiPollingPolicy::Shutdown(); +} bool LocationArbitrator::HasPermissionBeenGrantedForTest() const { return is_permission_granted_;
diff --git a/device/geolocation/wifi_data_provider_chromeos.cc b/device/geolocation/wifi_data_provider_chromeos.cc index b4b4f1a..b53d30ee 100644 --- a/device/geolocation/wifi_data_provider_chromeos.cc +++ b/device/geolocation/wifi_data_provider_chromeos.cc
@@ -36,20 +36,16 @@ void WifiDataProviderChromeOs::StartDataProvider() { DCHECK(CalledOnClientThread()); - DCHECK(polling_policy_ == nullptr); - polling_policy_.reset( - new GenericWifiPollingPolicy<kDefaultPollingIntervalMilliseconds, - kNoChangePollingIntervalMilliseconds, - kTwoNoChangePollingIntervalMilliseconds, - kNoWifiPollingIntervalMilliseconds>); + if (!WifiPollingPolicy::IsInitialized()) + WifiPollingPolicy::Initialize(CreatePollingPolicy()); + DCHECK(WifiPollingPolicy::IsInitialized()); - ScheduleStart(); + ScheduleStart(WifiPollingPolicy::Get()->PollingInterval()); } void WifiDataProviderChromeOs::StopDataProvider() { DCHECK(CalledOnClientThread()); - polling_policy_.reset(); ScheduleStop(); } @@ -83,7 +79,7 @@ // Schedule next scan if started (StopDataProvider could have been called // in between DoWifiScanTaskOnNetworkHandlerThread and this method). if (started_) - ScheduleNextScan(polling_policy_->NoWifiInterval()); + ScheduleNextScan(WifiPollingPolicy::Get()->NoWifiInterval()); } void WifiDataProviderChromeOs::DidWifiScanTask(const WifiData& new_data) { @@ -93,8 +89,8 @@ // Schedule next scan if started (StopDataProvider could have been called // in between DoWifiScanTaskOnNetworkHandlerThread and this method). if (started_) { - polling_policy_->UpdatePollingInterval(update_available); - ScheduleNextScan(polling_policy_->PollingInterval()); + WifiPollingPolicy::Get()->UpdatePollingInterval(update_available); + ScheduleNextScan(WifiPollingPolicy::Get()->PollingInterval()); } if (update_available || !is_first_scan_complete_) { @@ -124,7 +120,7 @@ started_ = false; } -void WifiDataProviderChromeOs::ScheduleStart() { +void WifiDataProviderChromeOs::ScheduleStart(int interval) { DCHECK(CalledOnClientThread()); DCHECK(!started_); if (!NetworkHandler::IsInitialized()) { @@ -132,13 +128,12 @@ return; } started_ = true; - // Perform first scan ASAP regardless of the polling policy. If this scan - // fails we'll retry at a rate in line with the polling policy. - NetworkHandler::Get()->task_runner()->PostTask( + NetworkHandler::Get()->task_runner()->PostDelayedTask( FROM_HERE, base::Bind( &WifiDataProviderChromeOs::DoWifiScanTaskOnNetworkHandlerThread, - this)); + this), + base::TimeDelta::FromMilliseconds(interval)); } bool WifiDataProviderChromeOs::GetAccessPointData( @@ -176,6 +171,14 @@ return true; } +std::unique_ptr<WifiPollingPolicy> +WifiDataProviderChromeOs::CreatePollingPolicy() { + return std::make_unique<GenericWifiPollingPolicy< + kDefaultPollingIntervalMilliseconds, kNoChangePollingIntervalMilliseconds, + kTwoNoChangePollingIntervalMilliseconds, + kNoWifiPollingIntervalMilliseconds>>(); +} + // static WifiDataProvider* WifiDataProviderManager::DefaultFactoryFunction() { return new WifiDataProviderChromeOs();
diff --git a/device/geolocation/wifi_data_provider_chromeos.h b/device/geolocation/wifi_data_provider_chromeos.h index f9630f6f..09fcff8 100644 --- a/device/geolocation/wifi_data_provider_chromeos.h +++ b/device/geolocation/wifi_data_provider_chromeos.h
@@ -39,7 +39,7 @@ void ScheduleNextScan(int interval); // Will schedule starting of the scanning process. - void ScheduleStart(); + void ScheduleStart(int interval); // Will schedule stopping of the scanning process. void ScheduleStop(); @@ -47,8 +47,8 @@ // Get access point data from chromeos. bool GetAccessPointData(WifiData::AccessPointDataSet* data); - // Controls the polling update interval. (client thread) - std::unique_ptr<WifiPollingPolicy> polling_policy_; + // Create the policy for controlling the polling update interval. + std::unique_ptr<WifiPollingPolicy> CreatePollingPolicy(); // The latest wifi data. (client thread) WifiData wifi_data_;
diff --git a/device/geolocation/wifi_data_provider_common.cc b/device/geolocation/wifi_data_provider_common.cc index 0084432..2343b65 100644 --- a/device/geolocation/wifi_data_provider_common.cc +++ b/device/geolocation/wifi_data_provider_common.cc
@@ -35,18 +35,15 @@ return; } - DCHECK(!polling_policy_); - polling_policy_ = CreatePollingPolicy(); - DCHECK(polling_policy_); + if (!WifiPollingPolicy::IsInitialized()) + WifiPollingPolicy::Initialize(CreatePollingPolicy()); + DCHECK(WifiPollingPolicy::IsInitialized()); - // Perform first scan ASAP regardless of the polling policy. If this scan - // fails we'll retry at a rate in line with the polling policy. - ScheduleNextScan(0); + ScheduleNextScan(WifiPollingPolicy::Get()->PollingInterval()); } void WifiDataProviderCommon::StopDataProvider() { wlan_api_.reset(); - polling_policy_.reset(); } bool WifiDataProviderCommon::GetData(WifiData* data) { @@ -60,12 +57,12 @@ bool update_available = false; WifiData new_data; if (!wlan_api_->GetAccessPointData(&new_data.access_point_data)) { - ScheduleNextScan(polling_policy_->NoWifiInterval()); + ScheduleNextScan(WifiPollingPolicy::Get()->NoWifiInterval()); } else { update_available = wifi_data_.DiffersSignificantly(new_data); wifi_data_ = new_data; - polling_policy_->UpdatePollingInterval(update_available); - ScheduleNextScan(polling_policy_->PollingInterval()); + WifiPollingPolicy::Get()->UpdatePollingInterval(update_available); + ScheduleNextScan(WifiPollingPolicy::Get()->PollingInterval()); } if (update_available || !is_first_scan_complete_) { is_first_scan_complete_ = true;
diff --git a/device/geolocation/wifi_data_provider_common.h b/device/geolocation/wifi_data_provider_common.h index 44a312c..ad39a54e 100644 --- a/device/geolocation/wifi_data_provider_common.h +++ b/device/geolocation/wifi_data_provider_common.h
@@ -72,9 +72,6 @@ // Underlying OS wifi API. std::unique_ptr<WlanApiInterface> wlan_api_; - // Controls the polling update interval. - std::unique_ptr<WifiPollingPolicy> polling_policy_; - // Holder for delayed tasks; takes care of cleanup. base::WeakPtrFactory<WifiDataProviderCommon> weak_factory_;
diff --git a/device/geolocation/wifi_data_provider_common_unittest.cc b/device/geolocation/wifi_data_provider_common_unittest.cc index ec20a12..7db568f 100644 --- a/device/geolocation/wifi_data_provider_common_unittest.cc +++ b/device/geolocation/wifi_data_provider_common_unittest.cc
@@ -14,6 +14,7 @@ #include "base/third_party/dynamic_annotations/dynamic_annotations.h" #include "base/threading/thread_task_runner_handle.h" #include "device/geolocation/wifi_data_provider_manager.h" +#include "device/geolocation/wifi_polling_policy.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" @@ -60,7 +61,8 @@ class WifiDataProviderCommonWithMock : public WifiDataProviderCommon { public: WifiDataProviderCommonWithMock() - : wlan_api_(new MockWlanApi), polling_policy_(new MockPollingPolicy) {} + : wlan_api_(new MockWlanApi), + polling_policy_(std::make_unique<MockPollingPolicy>()) {} // WifiDataProviderCommon std::unique_ptr<WlanApiInterface> CreateWlanApi() override { @@ -97,6 +99,7 @@ void TearDown() override { provider_->RemoveCallback(&wifi_data_callback_); provider_->StopDataProvider(); + WifiPollingPolicy::Shutdown(); } protected:
diff --git a/device/geolocation/wifi_polling_policy.cc b/device/geolocation/wifi_polling_policy.cc new file mode 100644 index 0000000..6cd52bbc --- /dev/null +++ b/device/geolocation/wifi_polling_policy.cc
@@ -0,0 +1,36 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "device/geolocation/wifi_polling_policy.h" + +namespace device { + +namespace { +WifiPollingPolicy* g_wifi_polling_policy; +} // namespace + +// static +void WifiPollingPolicy::Initialize(std::unique_ptr<WifiPollingPolicy> policy) { + g_wifi_polling_policy = policy.release(); +} + +// static +void WifiPollingPolicy::Shutdown() { + if (g_wifi_polling_policy) + delete g_wifi_polling_policy; + g_wifi_polling_policy = nullptr; +} + +// static +WifiPollingPolicy* WifiPollingPolicy::Get() { + DCHECK(g_wifi_polling_policy); + return g_wifi_polling_policy; +} + +// static +bool WifiPollingPolicy::IsInitialized() { + return g_wifi_polling_policy != nullptr; +} + +} // namespace device
diff --git a/device/geolocation/wifi_polling_policy.h b/device/geolocation/wifi_polling_policy.h index 0ac9203..226b3852 100644 --- a/device/geolocation/wifi_polling_policy.h +++ b/device/geolocation/wifi_polling_policy.h
@@ -5,21 +5,36 @@ #ifndef DEVICE_GEOLOCATION_WIFI_POLLING_POLICY_H_ #define DEVICE_GEOLOCATION_WIFI_POLLING_POLICY_H_ +#include <memory> + #include "base/macros.h" +#include "base/time/time.h" +#include "device/geolocation/geolocation_export.h" namespace device { // Allows sharing and mocking of the update polling policy function. -class WifiPollingPolicy { +class DEVICE_GEOLOCATION_EXPORT WifiPollingPolicy { public: - WifiPollingPolicy() {} - virtual ~WifiPollingPolicy() {} + virtual ~WifiPollingPolicy() = default; + + // Methods for managing the single instance of WifiPollingPolicy. The WiFi + // policy is global so it can outlive the WifiDataProvider instance, which is + // shut down and destroyed when no WiFi scanning is active. + static void Initialize(std::unique_ptr<WifiPollingPolicy>); + static void Shutdown(); + static WifiPollingPolicy* Get(); + static bool IsInitialized(); + // Calculates the new polling interval for wiFi scans, given the previous // interval and whether the last scan produced new results. virtual void UpdatePollingInterval(bool scan_results_differ) = 0; virtual int PollingInterval() = 0; virtual int NoWifiInterval() = 0; + protected: + WifiPollingPolicy() = default; + private: DISALLOW_COPY_AND_ASSIGN(WifiPollingPolicy); }; @@ -33,6 +48,7 @@ class GenericWifiPollingPolicy : public WifiPollingPolicy { public: GenericWifiPollingPolicy() : polling_interval_(DEFAULT_INTERVAL) {} + // WifiPollingPolicy void UpdatePollingInterval(bool scan_results_differ) override { if (scan_results_differ) { @@ -45,11 +61,37 @@ polling_interval_ = TWO_NO_CHANGE_INTERVAL; } } - int PollingInterval() override { return polling_interval_; } - int NoWifiInterval() override { return NO_WIFI_INTERVAL; } + int PollingInterval() override { return ComputeInterval(polling_interval_); } + int NoWifiInterval() override { return ComputeInterval(NO_WIFI_INTERVAL); } private: + int ComputeInterval(int polling_interval) { + base::Time now = base::Time::Now(); + + int64_t remaining_millis = 0; + if (!next_scan_.is_null()) { + // Compute the remaining duration of the current interval. If the interval + // is not yet complete, we will schedule a scan to occur once it is. + base::TimeDelta remaining = next_scan_ - now; + remaining_millis = remaining.InMilliseconds(); + } + + // If the current interval is complete (or if this is our first scan), scan + // now and schedule the next scan to occur at |polling_interval| + // milliseconds into the future. + if (remaining_millis <= 0) { + next_scan_ = now + base::TimeDelta::FromMilliseconds(polling_interval); + remaining_millis = 0; + } + + return remaining_millis; + } + int polling_interval_; + + // The scheduled time of the next scan, or a null value if no scan has + // occurred yet. + base::Time next_scan_; }; } // namespace device
diff --git a/device/u2f/BUILD.gn b/device/u2f/BUILD.gn index b8ed68e..6213b36 100644 --- a/device/u2f/BUILD.gn +++ b/device/u2f/BUILD.gn
@@ -136,6 +136,7 @@ "//base", "//mojo/public/cpp/bindings", "//services/device/public/interfaces", + "//testing/gmock", ] } }
diff --git a/device/u2f/fake_hid_impl_for_testing.cc b/device/u2f/fake_hid_impl_for_testing.cc index 08495a3d..4a7a15a 100644 --- a/device/u2f/fake_hid_impl_for_testing.cc +++ b/device/u2f/fake_hid_impl_for_testing.cc
@@ -4,8 +4,47 @@ #include "device/u2f/fake_hid_impl_for_testing.h" +#include <utility> + +#include "base/optional.h" + namespace device { +MockHidConnection::MockHidConnection( + device::mojom::HidDeviceInfoPtr device, + device::mojom::HidConnectionRequest request, + std::vector<uint8_t> connection_channel_id) + : binding_(this, std::move(request)), + device_(std::move(device)), + connection_channel_id_(connection_channel_id) {} + +MockHidConnection::~MockHidConnection() {} + +void MockHidConnection::Read(ReadCallback callback) { + return ReadPtr(&callback); +} + +void MockHidConnection::Write(uint8_t report_id, + const std::vector<uint8_t>& buffer, + WriteCallback callback) { + return WritePtr(report_id, buffer, &callback); +} + +void MockHidConnection::GetFeatureReport(uint8_t report_id, + GetFeatureReportCallback callback) { + NOTREACHED(); +} + +void MockHidConnection::SendFeatureReport(uint8_t report_id, + const std::vector<uint8_t>& buffer, + SendFeatureReportCallback callback) { + NOTREACHED(); +} + +void MockHidConnection::SetNonce(base::span<uint8_t const> nonce) { + nonce_ = std::vector<uint8_t>(nonce.begin(), nonce.end()); +} + bool FakeHidConnection::mock_connection_error_ = false; FakeHidConnection::FakeHidConnection(device::mojom::HidDeviceInfoPtr device) @@ -73,18 +112,14 @@ void FakeHidManager::Connect(const std::string& device_guid, ConnectCallback callback) { - auto it = devices_.find(device_guid); - if (it == devices_.end()) { + auto device_it = devices_.find(device_guid); + auto connection_it = connections_.find(device_guid); + if (device_it == devices_.end() || connection_it == connections_.end()) { std::move(callback).Run(nullptr); return; } - // Strongly binds an instance of FakeHidConnctionImpl. - device::mojom::HidConnectionPtr client; - mojo::MakeStrongBinding( - base::MakeUnique<FakeHidConnection>(it->second->Clone()), - mojo::MakeRequest(&client)); - std::move(callback).Run(std::move(client)); + std::move(callback).Run(std::move(connection_it->second)); } void FakeHidManager::AddDevice(device::mojom::HidDeviceInfoPtr device) { @@ -96,6 +131,13 @@ devices_[device->guid] = std::move(device); } +void FakeHidManager::AddDeviceAndSetConnection( + device::mojom::HidDeviceInfoPtr device, + device::mojom::HidConnectionPtr connection) { + connections_[device->guid] = std::move(connection); + AddDevice(std::move(device)); +} + void FakeHidManager::RemoveDevice(const std::string device_guid) { auto it = devices_.find(device_guid); if (it == devices_.end())
diff --git a/device/u2f/fake_hid_impl_for_testing.h b/device/u2f/fake_hid_impl_for_testing.h index 9aebb43..ac44ed1 100644 --- a/device/u2f/fake_hid_impl_for_testing.h +++ b/device/u2f/fake_hid_impl_for_testing.h
@@ -2,15 +2,62 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#ifndef DEVICE_U2F_FAKE_HID_IMPL_FOR_TESTING_H_ +#define DEVICE_U2F_FAKE_HID_IMPL_FOR_TESTING_H_ + +#include <map> +#include <string> +#include <vector> + #include "base/bind.h" +#include "base/containers/span.h" #include "base/memory/ptr_util.h" #include "mojo/public/cpp/bindings/binding_set.h" #include "mojo/public/cpp/bindings/interface_ptr_set.h" #include "mojo/public/cpp/bindings/strong_binding.h" #include "services/device/public/interfaces/hid.mojom.h" +#include "testing/gmock/include/gmock/gmock.h" namespace device { +class MockHidConnection : public device::mojom::HidConnection { + public: + explicit MockHidConnection(device::mojom::HidDeviceInfoPtr device, + device::mojom::HidConnectionRequest request, + std::vector<uint8_t> connection_channel_id); + + ~MockHidConnection() override; + MOCK_METHOD1(ReadPtr, void(ReadCallback* callback)); + MOCK_METHOD3(WritePtr, + void(uint8_t report_id, + const std::vector<uint8_t>& buffer, + WriteCallback* callback)); + + void Read(ReadCallback callback) override; + + void Write(uint8_t report_id, + const std::vector<uint8_t>& buffer, + WriteCallback callback) override; + + void GetFeatureReport(uint8_t report_id, + GetFeatureReportCallback callback) override; + void SendFeatureReport(uint8_t report_id, + const std::vector<uint8_t>& buffer, + SendFeatureReportCallback callback) override; + void SetNonce(base::span<uint8_t const> nonce); + + const std::vector<uint8_t>& connection_channel_id() const { + return connection_channel_id_; + } + const std::vector<uint8_t>& nonce() const { return nonce_; } + + private: + mojo::Binding<device::mojom::HidConnection> binding_; + device::mojom::HidDeviceInfoPtr device_; + std::vector<uint8_t> nonce_; + std::vector<uint8_t> connection_channel_id_; +}; + class FakeHidConnection : public device::mojom::HidConnection { public: explicit FakeHidConnection(device::mojom::HidDeviceInfoPtr device); @@ -49,12 +96,17 @@ void AddBinding(mojo::ScopedMessagePipeHandle handle); void AddBinding2(device::mojom::HidManagerRequest request); void AddDevice(device::mojom::HidDeviceInfoPtr device); + void AddDeviceAndSetConnection(device::mojom::HidDeviceInfoPtr device, + device::mojom::HidConnectionPtr connection); void RemoveDevice(const std::string device_guid); private: std::map<std::string, device::mojom::HidDeviceInfoPtr> devices_; + std::map<std::string, device::mojom::HidConnectionPtr> connections_; mojo::AssociatedInterfacePtrSet<device::mojom::HidManagerClient> clients_; mojo::BindingSet<device::mojom::HidManager> bindings_; }; } // namespace device + +#endif // DEVICE_U2F_FAKE_HID_IMPL_FOR_TESTING_H_
diff --git a/device/u2f/u2f_hid_device.cc b/device/u2f/u2f_hid_device.cc index 29d2397..9f5d526 100644 --- a/device/u2f/u2f_hid_device.cc +++ b/device/u2f/u2f_hid_device.cc
@@ -27,7 +27,9 @@ U2fHidDevice::U2fHidDevice(device::mojom::HidDeviceInfoPtr device_info, device::mojom::HidManager* hid_manager) - : hid_manager_(hid_manager), + : U2fDevice(), + state_(State::INIT), + hid_manager_(hid_manager), device_info_(std::move(device_info)), weak_factory_(this) {} @@ -77,6 +79,7 @@ default: base::WeakPtr<U2fHidDevice> self = weak_factory_.GetWeakPtr(); repeating_callback.Run(false, nullptr); + // Executing callbacks may free |this|. Check |self| first. while (self && !pending_transactions_.empty()) { // Respond to any pending requests @@ -138,6 +141,7 @@ Transition(nullptr, std::move(callback)); return; } + // Channel allocation response is defined as: // 0: 8 byte nonce // 8: 4 byte channel id @@ -152,12 +156,17 @@ Transition(nullptr, std::move(callback)); return; } + auto received_nonce = base::make_span(payload).first(8); + // Received a broadcast message for a different client. Disregard and continue + // reading. + if (base::make_span(nonce) != received_nonce) { + auto repeating_callback = + base::AdaptCallbackForRepeating(std::move(callback)); + ArmTimeout(repeating_callback); + ReadMessage(base::BindOnce(&U2fHidDevice::OnAllocateChannel, + weak_factory_.GetWeakPtr(), nonce, + std::move(command), repeating_callback)); - std::vector<uint8_t> received_nonce(std::begin(payload), - std::begin(payload) + 8); - if (nonce != received_nonce) { - state_ = State::DEVICE_ERROR; - Transition(nullptr, std::move(callback)); return; } @@ -167,7 +176,6 @@ channel_id_ |= payload[index++] << 8; channel_id_ |= payload[index++]; capabilities_ = payload[16]; - state_ = State::IDLE; Transition(std::move(command), std::move(callback)); } @@ -180,8 +188,9 @@ return; } + const auto& packet = message->PopNextPacket(); connection_->Write( - kReportId, message->PopNextPacket(), + kReportId, packet, base::BindOnce(&U2fHidDevice::PacketWritten, weak_factory_.GetWeakPtr(), std::move(message), true, std::move(callback))); } @@ -219,6 +228,7 @@ } DCHECK(buf); + std::unique_ptr<U2fMessage> read_message = U2fMessage::CreateFromSerializedData(*buf);
diff --git a/device/u2f/u2f_hid_device_unittest.cc b/device/u2f/u2f_hid_device_unittest.cc index 47fcde7..e006125 100644 --- a/device/u2f/u2f_hid_device_unittest.cc +++ b/device/u2f/u2f_hid_device_unittest.cc
@@ -5,20 +5,33 @@ #include <list> #include "base/bind.h" +#include "base/containers/span.h" #include "base/memory/ptr_util.h" #include "base/run_loop.h" +#include "base/strings/string_number_conversions.h" +#include "base/test/scoped_mock_time_message_loop_task_runner.h" #include "base/test/scoped_task_environment.h" #include "device/u2f/fake_hid_impl_for_testing.h" #include "device/u2f/u2f_apdu_command.h" #include "device/u2f/u2f_apdu_response.h" +#include "device/u2f/u2f_command_type.h" #include "device/u2f/u2f_hid_device.h" +#include "device/u2f/u2f_message.h" #include "device/u2f/u2f_packet.h" +#include "mojo/public/cpp/bindings/binding.h" #include "mojo/public/cpp/bindings/interface_request.h" #include "services/device/public/cpp/hid/hid_device_filter.h" #include "services/device/public/interfaces/hid.mojom.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" +namespace device { + +using ::testing::_; +using ::testing::Invoke; +using ::testing::WithArg; +using ::testing::WithArgs; + namespace { void ResponseCallback(std::unique_ptr<device::U2fApduResponse>* output, @@ -27,9 +40,58 @@ *output = std::move(response); } -} // namespace +std::string HexEncode(base::span<const uint8_t> in) { + return base::HexEncode(in.data(), in.size()); +} -namespace device { +std::vector<uint8_t> HexDecode(base::StringPiece in) { + std::vector<uint8_t> out; + bool result = base::HexStringToBytes(in.as_string(), &out); + DCHECK(result); + return out; +} + +// Converts hex encoded StringPiece to byte vector and pads zero to fit HID +// packet size. +std::vector<uint8_t> MakePacket(base::StringPiece hex) { + std::vector<uint8_t> out = HexDecode(hex); + out.resize(64); + return out; +} + +// Returns HID_INIT request to send to device with mock connection. +std::vector<uint8_t> CreateMockHidInitResponse( + std::vector<uint8_t> nonce, + std::vector<uint8_t> channel_id) { + // 4 bytes of broadcast channel identifier(ffffffff), followed by + // HID_INIT command(86) and 2 byte payload length(11) + return MakePacket("ffffffff860011" + HexEncode(nonce) + + HexEncode(channel_id)); +} + +// Returns "U2F_v2" as a mock response to version request with given channel id. +std::vector<uint8_t> CreateMockVersionResponse( + std::vector<uint8_t> channel_id) { + // HID_MSG command(83), followed by payload length(0008), followed by + // hex encoded "U2F_V2" and NO_ERROR response code(9000). + return MakePacket(HexEncode(channel_id) + "8300085532465f56329000"); +} + +device::mojom::HidDeviceInfoPtr TestHidDevice() { + auto c_info = device::mojom::HidCollectionInfo::New(); + c_info->usage = device::mojom::HidUsageAndPage::New(1, 0xf1d0); + auto hid_device = device::mojom::HidDeviceInfo::New(); + hid_device->guid = "A"; + hid_device->product_name = "Test Fido device"; + hid_device->serial_number = "123FIDO"; + hid_device->bus_type = device::mojom::HidBusType::kHIDBusTypeUSB; + hid_device->collections.push_back(std::move(c_info)); + hid_device->max_input_report_size = 64; + hid_device->max_output_report_size = 64; + return hid_device; +} + +} // namespace class U2fDeviceEnumerate { public: @@ -145,8 +207,6 @@ protected: device::mojom::HidManagerPtr hid_manager_; std::unique_ptr<FakeHidManager> fake_hid_manager_; - - private: base::test::ScopedTaskEnvironment scoped_task_environment_; }; @@ -192,19 +252,7 @@ TEST_F(U2fHidDeviceTest, TestConnectionFailure) { // Setup and enumerate mock device U2fDeviceEnumerate callback(hid_manager_.get()); - - auto c_info = device::mojom::HidCollectionInfo::New(); - c_info->usage = device::mojom::HidUsageAndPage::New(1, 0xf1d0); - - auto hid_device = device::mojom::HidDeviceInfo::New(); - hid_device->guid = "A"; - hid_device->product_name = "Test Fido device"; - hid_device->serial_number = "123FIDO"; - hid_device->bus_type = device::mojom::HidBusType::kHIDBusTypeUSB; - hid_device->collections.push_back(std::move(c_info)); - hid_device->max_input_report_size = 64; - hid_device->max_output_report_size = 64; - + auto hid_device = TestHidDevice(); fake_hid_manager_->AddDevice(std::move(hid_device)); hid_manager_->GetDevices(callback.callback()); @@ -244,17 +292,7 @@ // Setup and enumerate mock device U2fDeviceEnumerate callback(hid_manager_.get()); - auto c_info = device::mojom::HidCollectionInfo::New(); - c_info->usage = device::mojom::HidUsageAndPage::New(1, 0xf1d0); - - auto hid_device = device::mojom::HidDeviceInfo::New(); - hid_device->guid = "A"; - hid_device->product_name = "Test Fido device"; - hid_device->serial_number = "123FIDO"; - hid_device->bus_type = device::mojom::HidBusType::kHIDBusTypeUSB; - hid_device->collections.push_back(std::move(c_info)); - hid_device->max_input_report_size = 64; - hid_device->max_output_report_size = 64; + auto hid_device = TestHidDevice(); fake_hid_manager_->AddDevice(std::move(hid_device)); hid_manager_->GetDevices(callback.callback()); @@ -297,4 +335,76 @@ EXPECT_EQ(nullptr, response3); } +TEST_F(U2fHidDeviceTest, TestRetryChannelAllocation) { + const std::vector<uint8_t> kIncorrectNonce = {0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00}; + + const std::vector<uint8_t> kChannelId = {0x01, 0x02, 0x03, 0x04}; + + U2fDeviceEnumerate callback(hid_manager_.get()); + auto hid_device = TestHidDevice(); + + // Replace device HID connection with custom client connection bound to mock + // server-side mojo connection. + device::mojom::HidConnectionPtr connection_client; + MockHidConnection mock_connection( + hid_device.Clone(), mojo::MakeRequest(&connection_client), kChannelId); + + // Delegate custom functions to be invoked for mock hid connection + EXPECT_CALL(mock_connection, WritePtr(_, _, _)) + // HID_INIT request to authenticator for channel allocation. + .WillOnce(WithArgs<1, 2>( + Invoke([&](const std::vector<uint8_t>& buffer, + device::mojom::HidConnection::WriteCallback* cb) { + mock_connection.SetNonce(base::make_span(buffer).subspan(7, 8)); + std::move(*cb).Run(true); + }))) + + // HID_MSG request to authenticator for version request. + .WillOnce(WithArgs<2>( + Invoke([](device::mojom::HidConnection::WriteCallback* cb) { + std::move(*cb).Run(true); + }))); + + EXPECT_CALL(mock_connection, ReadPtr(_)) + // First response to HID_INIT request with incorrect nonce. + .WillOnce(WithArg<0>( + Invoke([kIncorrectNonce, &mock_connection]( + device::mojom::HidConnection::ReadCallback* cb) { + std::move(*cb).Run( + true, 0, + CreateMockHidInitResponse( + kIncorrectNonce, mock_connection.connection_channel_id())); + }))) + // Second response to HID_INIT request with correct nonce. + .WillOnce(WithArg<0>(Invoke( + [&mock_connection](device::mojom::HidConnection::ReadCallback* cb) { + std::move(*cb).Run(true, 0, + CreateMockHidInitResponse( + mock_connection.nonce(), + mock_connection.connection_channel_id())); + }))) + // Version response from the authenticator. + .WillOnce(WithArg<0>(Invoke( + [&mock_connection](device::mojom::HidConnection::ReadCallback* cb) { + std::move(*cb).Run(true, 0, + CreateMockVersionResponse( + mock_connection.connection_channel_id())); + }))); + + // Add device and set mock connection to fake hid manager + fake_hid_manager_->AddDeviceAndSetConnection(std::move(hid_device), + std::move(connection_client)); + + hid_manager_->GetDevices(callback.callback()); + std::list<std::unique_ptr<U2fHidDevice>>& u2f_devices = + callback.WaitForCallback(); + + ASSERT_EQ(1u, u2f_devices.size()); + auto& device = u2f_devices.front(); + TestVersionCallback vc; + device->Version(vc.callback()); + EXPECT_EQ(vc.WaitForCallback(), U2fDevice::ProtocolVersion::U2F_V2); +} + } // namespace device
diff --git a/docs/mac_build_instructions.md b/docs/mac_build_instructions.md index bf811b4..782319b5 100644 --- a/docs/mac_build_instructions.md +++ b/docs/mac_build_instructions.md
@@ -41,12 +41,19 @@ ## Get the code +Ensure that unicode filenames aren't mangled by HFS: + +```shell +$ git config --global core.precomposeUnicode true +``` + Create a `chromium` directory for the checkout and change to it (you can call this whatever you like and put it wherever you like, as long as the full path has no spaces): ```shell $ mkdir chromium && cd chromium +$ git config --global core.precomposeUnicode true ``` Run the `fetch` tool from `depot_tools` to check out the code and its
diff --git a/docs/speed/benchmark_harnesses/system_health.md b/docs/speed/benchmark_harnesses/system_health.md new file mode 100644 index 0000000..5ec3d68 --- /dev/null +++ b/docs/speed/benchmark_harnesses/system_health.md
@@ -0,0 +1,200 @@ +# System Health tests + +[TOC] + +## Overview + +The Chrome System Health benchmarking effort aims to create a common set of user +stories on the web that can be used for all Chrome speed projects. Our +benchmarks mimic average web users’ activities and cover all major web platform +APIs & browser features. + +The web is vast, the possible combination of user activities is endless. Hence, +to get a useful benchmarking tool for engineers to use for preventing +regressions, during launches and day to day work, we use data analysis and work +with teams within Chrome to create a limited set of stories that can fit a +budget of 90 minutes machine time. + +These are our key cover areas for the browser: +* Different user gestures: swipe, fling, text input, scroll & infinite scroll +* Video +* Audio +* Flash +* Graphics: css, svg, canvas, webGL +* Background tabs +* Multi-tab switching +* Back button +* Follow a link +* Restore tabs +* Reload a page +* ... ([Full tracking sheet](https://docs.google.com/spreadsheets/d/1t15Ya5ssYBeXAZhHm3RJqfwBRpgWsxoib8_kwQEHMwI/edit#gid=0)) + +Success to us means System Health benchmarks cast a wide enough net to +catch major regressions before they make it to the users. This also means +performance improvements to System Health benchmarks translate to actual wins +on the web, enabling teams to use these benchmarks for tracking progress with +the confidence that their improvement on the suite matters to real users. + +To achieve this goal, just simulating user’s activities on the web is not +enough. We also partner with +[chrome-speed-metrics](https://groups.google.com/a/chromium.org/forum/#!forum/progressive-web-metrics) +team to track key user metrics on our user stories. + + +## Where are the System Health stories? + +All the System Health stories are located in +[tools/perf/page_sets/system_health/](../../../tools/perf/page_sets/system_health/). + +There are few groups of stories: +1. [Accessibility stories](../../../tools/perf/page_sets/system_health/accessibility_stories.py) +2. [Background stories](../../../tools/perf/page_sets/system_health/background_stories.py) +3. [Browsing stories](../../../tools/perf/page_sets/system_health/browsing_stories.py) +4. [Chrome stories](../../../tools/perf/page_sets/system_health/chrome_stories.py) +5. [Loading stories](../../../tools/perf/page_sets/system_health/loading_stories.py) +6. [Multi-tab stories](../../../tools/perf/page_sets/system_health/multi_tab_stories.py) +7. [Media stories](../../../tools/perf/page_sets/system_health/media_stories.py) + +## What is the structure of a System Health story? +A System Health story is a subclass of +[SystemHealthStory](https://cs.chromium.org/chromium/src/tools/perf/page_sets/system_health/system_health_story.py?l=44&rcl=d5f1f0821489a8311dc437fc6b70ac0b0d72b28b), for example: +``` +class NewSystemHealthStory(SystemHealthStory): + NAME = 'case:group:page:2018' + URL = 'https://the.starting.url' + TAGS = [story_tags.JAVASCRIPT_HEAVY, story_tags.INFINITE_SCROLL] + SUPPORTED_PLATFORMS = platforms.ALL_PLATFORMS # Default. + # or platforms.DESKTOP_ONLY + # or platforms.MOBILE_ONLY + # or platforms.NO_PLATFORMS + + def _Login(self, action_runner): + # Optional. Called before the starting URL is loaded. + + def _DidLoadDocument(self, action_runner): + # Optional. Called after the starting URL is loaded + # (but before potentially measuring memory). +``` + +The name must have the following structure: +1. **Case** (load, browse, search, …). User action/journey that the story + simulates (verb). Stories for each case are currently kept in a separate + file. + Benchmarks using the System Health story set can specify which cases they want to + include (see + [SystemHealthStorySet](https://cs.chromium.org/chromium/src/tools/perf/page_sets/system_health/system_health_stories.py?l=16&rcl=e3eb21e24dbe0530356003fd9f9a8a94fb91d00b)). +2. **Group** (social, news, tools, …). General category to which the page + (item 3) belongs. +3. **Page** (google, facebook, nytimes, …). The name of the individual page. In + case there are multi pages, one can use the general grouping name like + "top_pages", or "typical_pages". +4. **Year** (2017, 2018, 2018_q3, ...). The year (and quarter if necessary for + disambiguating) when the page is added. Note: this rule was added later, + so the old System Health stories do not have this field. + +In addition, each story also has accompanied tags that define its important +characteristics. +[Tags](../../../tools/perf/page_sets/system_health/story_tags.py) are used as +the way to track coverage of System Health stories, so they should be as +detailed as needed to distinguish each System Health story from the others. + +## How are System Health stories executed? +Given a System Health story set with N stories, each story is executed sequentially as +follows: + +1. Launch the browser +2. Start tracing +3. Run `story._Login` (no-op by default) +4. Load `story.URL` +5. Run `story._DidLoadDocument` (no-op by default) +6. Measure memory (disabled by default) +7. Stop tracing +8. Tear down the browser + +All the benchmarks using System Health stories tear down the browser after single story. +This ensures that every story is completely independent and modifications to the +System Health story set won’t cause as many regressions/improvements on the perf dashboard. + +## Should I add new System Health stories and how? + +First, check this list of [System Health stories](https://docs.google.com/spreadsheets/d/1t15Ya5ssYBeXAZhHm3RJqfwBRpgWsxoib8_kwQEHMwI/edit#gid=0) +to see if your intended user stories are already covered by existing ones. + +If there is a good reason for your stories to be added, please make one CL for +each of the new stories so they can be landed (and reverted if needed) +individually. On each CL, make sure that the perf trybots all pass before +comitting. + +Once your patch makes it through the CQ, you’re done… unless your story starts +failing on some random platform, in which case the perf bot sheriff will very +likely revert your patch and assign a bug to you. It is then up to you to figure +out why the story fails, fix it and re-land the patch. + +Add new SystemHealthStory subclass(es) to either one of the existing files or a +new file in [tools/perf/page_sets/system_health/](../../tools/perf/page_sets/system_health). +The new class(es) will automatically be picked up and added to the story set. +To run the story through the memory benchmark against live sites, use the +following commands: + +``` +$ tools/perf/run_benchmark system_health.memory_desktop \ + --browser=reference --device=desktop \ + --story-filter=<NAME-OF-YOUR-STORY> \ + --use-live-sites +$ tools/perf/run_benchmark system_health.memory_mobile \ + --browser=reference --device=android \ + --story-filter=<NAME-OF-YOUR-STORY> \ + --also-run-disabled-tests --use-live-sites +``` + +Once you’re happy with the stories, record them: + +``` +$ tools/perf/record_wpr --story desktop_system_health_story_set \ + --browser=reference --device=desktop \ + --story-filter=<NAME-OF-YOUR-STORY> +$ tools/perf/record_wpr --story mobile_system_health_story_set \ + --browser=reference --device=android \ + --story-filter=<NAME-OF-YOUR-STORY> +``` + +You can now replay the stories from the recording by omitting the +`--use-live-sites` flag: + +``` +$ tools/perf/run_benchmark system_health.memory_desktop \ + --browser=reference --device=desktop \ + --story-filter=<NAME-OF-YOUR-STORY> \ + --also-run-disabled-tests +$ tools/perf/run_benchmark system_health.memory_mobile \ + --browser=reference --device=android \ + --story-filter=<NAME-OF-YOUR-STORY> \ + --also-run-disabled-tests +``` + +The recordings are stored in `system_health_desktop_MMM.wprgo` and +`system_health_mobile_NNN.wprgo` files in the +[tools/perf/page_sets/data](../../../tools/perf/page_sets/data) directory. +You can find the MMM and NNN values by inspecting the changes to +`system_health_desktop.json` and `system_health_mobile.json`: + +``` +$ git diff tools/perf/page_sets/data/system_health_desktop.json +$ git diff tools/perf/page_sets/data/system_health_mobile.json +``` + +Once you verified that the replay works as you expect, you can upload the .wprgo +files to the cloud and include the .wprgo.sha1 files in your patch: + +``` +$ upload_to_google_storage.py --bucket chrome-partner-telemetry \ + system_health_desktop_MMM.wprgo +$ upload_to_google_storage.py --bucket chrome-partner-telemetry \ + system_health_mobile_NNN.wprgo +$ git add tools/perf/page_sets/data/system_health_desktop_MMM.wprgo.sha1 +$ git add tools/perf/page_sets/data/system_health_mobile_NNN.wprgo.sha1 +``` + +If the stories work as they should (certain website features don’t work well +under WPR and need to be worked around), send them out for review in the patch +that is adding the new story.
diff --git a/extensions/browser/api/cast_channel/cast_channel_api.cc b/extensions/browser/api/cast_channel/cast_channel_api.cc index c5d40367..a200778 100644 --- a/extensions/browser/api/cast_channel/cast_channel_api.cc +++ b/extensions/browser/api/cast_channel/cast_channel_api.cc
@@ -393,6 +393,14 @@ return; } + if (socket->ready_state() == cast_channel::ReadyState::CLOSED || + !socket->transport()) { + SetResultFromError(params_->channel.channel_id, + api::cast_channel::CHANNEL_ERROR_CHANNEL_NOT_OPEN); + AsyncWorkCompleted(); + return; + } + CastMessage message_to_send; if (!MessageInfoToCastMessage(params_->message, &message_to_send)) { SetResultFromError(params_->channel.channel_id,
diff --git a/extensions/browser/api/cast_channel/cast_channel_apitest.cc b/extensions/browser/api/cast_channel/cast_channel_apitest.cc index f984eb2..66f8f4f4 100644 --- a/extensions/browser/api/cast_channel/cast_channel_apitest.cc +++ b/extensions/browser/api/cast_channel/cast_channel_apitest.cc
@@ -114,7 +114,7 @@ callback.Run(mock_cast_socket_); }))); EXPECT_CALL(*mock_cast_socket_, ready_state()) - .WillOnce(Return(ReadyState::OPEN)); + .WillRepeatedly(Return(ReadyState::OPEN)); EXPECT_CALL(*mock_cast_socket_->mock_transport(), SendMessage(A<const CastMessage&>(), _, _)) .WillOnce(InvokeCompletionCallback<1>(net::OK)); @@ -127,6 +127,28 @@ } } + void SetUpOpenErrorSend() { + SetUpMockCastSocket(); + mock_cast_socket_->SetErrorState(ChannelError::CONNECT_ERROR); + { + InSequence sequence; + + EXPECT_CALL(*mock_cast_socket_, ConnectInternal(_)) + .WillOnce(WithArgs<0>( + Invoke([&](const MockCastSocket::MockOnOpenCallback& callback) { + callback.Run(mock_cast_socket_); + }))); + EXPECT_CALL(*mock_cast_socket_, ready_state()) + .WillRepeatedly(Return(ReadyState::CLOSED)); + EXPECT_CALL(*mock_cast_socket_->mock_transport(), SendMessage(_, _, _)) + .Times(0); + EXPECT_CALL(*mock_cast_socket_, Close(_)) + .WillOnce(InvokeCompletionCallback<0>(net::OK)); + EXPECT_CALL(*mock_cast_socket_, ready_state()) + .WillOnce(Return(ReadyState::CLOSED)); + } + } + void SetUpOpenPingTimeout() { SetUpMockCastSocket(); mock_cast_socket_->SetErrorState(ChannelError::NONE); @@ -246,6 +268,22 @@ // TODO(kmarshall): Win Dbg has a workaround that makes RunExtensionSubtest // always return true without actually running the test. Remove when fixed. #if defined(OS_WIN) && !defined(NDEBUG) +#define MAYBE_TestOpenErrorSend DISABLED_TestOpenErrorSend +#else +#define MAYBE_TestOpenErrorSend TestOpenErrorSend +#endif +// Test loading extension, failing to open a channel with ConnectInfo, sending +// message on closed channel, and closing. +IN_PROC_BROWSER_TEST_F(CastChannelAPITest, MAYBE_TestOpenErrorSend) { + SetUpOpenErrorSend(); + + EXPECT_TRUE( + RunExtensionSubtest("cast_channel/api", "test_open_error_send.html")); +} + +// TODO(kmarshall): Win Dbg has a workaround that makes RunExtensionSubtest +// always return true without actually running the test. Remove when fixed. +#if defined(OS_WIN) && !defined(NDEBUG) #define MAYBE_TestPingTimeout DISABLED_TestPingTimeout #else #define MAYBE_TestPingTimeout TestPingTimeout
diff --git a/extensions/browser/content_verify_job.cc b/extensions/browser/content_verify_job.cc index f3c72b7..94a7127 100644 --- a/extensions/browser/content_verify_job.cc +++ b/extensions/browser/content_verify_job.cc
@@ -49,11 +49,7 @@ current_hash_byte_count_(0), hash_reader_(hash_reader), failure_callback_(std::move(failure_callback)), - failed_(false) { - // It's ok for this object to be constructed on a different thread from where - // it's used. - thread_checker_.DetachFromThread(); -} + failed_(false) {} ContentVerifyJob::~ContentVerifyJob() { UMA_HISTOGRAM_COUNTS("ExtensionContentVerifyJob.TimeSpentUS", @@ -61,7 +57,7 @@ } void ContentVerifyJob::Start() { - DCHECK(thread_checker_.CalledOnValidThread()); + base::AutoLock auto_lock(lock_); if (g_content_verify_job_test_observer) g_content_verify_job_test_observer->JobStarted( hash_reader_->extension_id(), hash_reader_->relative_path()); @@ -73,7 +69,7 @@ void ContentVerifyJob::BytesRead(int count, const char* data) { ScopedElapsedTimer timer(&time_spent_); - DCHECK(thread_checker_.CalledOnValidThread()); + base::AutoLock auto_lock(lock_); if (failed_) return; if (g_test_delegate) { @@ -120,7 +116,7 @@ void ContentVerifyJob::DoneReading() { ScopedElapsedTimer timer(&time_spent_); - DCHECK(thread_checker_.CalledOnValidThread()); + base::AutoLock auto_lock(lock_); if (failed_) return; if (g_test_delegate) {
diff --git a/extensions/browser/content_verify_job.h b/extensions/browser/content_verify_job.h index 9b72f807..b93e34fd5 100644 --- a/extensions/browser/content_verify_job.h +++ b/extensions/browser/content_verify_job.h
@@ -13,7 +13,7 @@ #include "base/callback.h" #include "base/macros.h" #include "base/memory/ref_counted.h" -#include "base/threading/thread_checker.h" +#include "base/synchronization/lock.h" namespace base { class FilePath; @@ -29,8 +29,7 @@ // Objects of this class are responsible for verifying that the actual content // read from an extension file matches an expected set of hashes. This class -// can be created on any thread but the rest of the methods should be called -// from only one thread. +// can be created and used on any thread. class ContentVerifyJob : public base::RefCountedThreadSafe<ContentVerifyJob> { public: enum FailureReason { @@ -146,8 +145,8 @@ // Set to true if we detected a mismatch and called the failure callback. bool failed_; - // For ensuring methods on called on the right thread. - base::ThreadChecker thread_checker_; + // Used to synchronize all public methods. + base::Lock lock_; DISALLOW_COPY_AND_ASSIGN(ContentVerifyJob); };
diff --git a/extensions/browser/extension_protocols.cc b/extensions/browser/extension_protocols.cc index 2d3c273..75bdf38 100644 --- a/extensions/browser/extension_protocols.cc +++ b/extensions/browser/extension_protocols.cc
@@ -10,6 +10,7 @@ #include <algorithm> #include <memory> #include <string> +#include <utility> #include <vector> #include "base/base64.h" @@ -37,6 +38,7 @@ #include "base/timer/elapsed_timer.h" #include "build/build_config.h" #include "content/public/browser/browser_context.h" +#include "content/public/browser/browser_thread.h" #include "content/public/browser/file_url_loader.h" #include "content/public/browser/navigation_ui_data.h" #include "content/public/browser/render_frame_host.h" @@ -50,6 +52,7 @@ #include "extensions/browser/content_verify_job.h" #include "extensions/browser/extension_navigation_ui_data.h" #include "extensions/browser/extension_registry.h" +#include "extensions/browser/extension_system.h" #include "extensions/browser/extension_util.h" #include "extensions/browser/extensions_browser_client.h" #include "extensions/browser/guest_view/web_view/web_view_guest.h" @@ -652,23 +655,130 @@ verify_job); } +class FileLoaderObserver : public content::FileURLLoaderObserver { + public: + explicit FileLoaderObserver(scoped_refptr<ContentVerifyJob> verify_job) + : verify_job_(std::move(verify_job)) {} + ~FileLoaderObserver() override { + base::AutoLock auto_lock(lock_); + UMA_HISTOGRAM_COUNTS("ExtensionUrlRequest.TotalKbRead", bytes_read_ / 1024); + UMA_HISTOGRAM_COUNTS("ExtensionUrlRequest.SeekPosition", seek_position_); + if (request_timer_.get()) + UMA_HISTOGRAM_TIMES("ExtensionUrlRequest.Latency", + request_timer_->Elapsed()); + } + + void OnStart() override { + base::AutoLock auto_lock(lock_); + request_timer_.reset(new base::ElapsedTimer()); + } + + void OnOpenComplete(int result) override { + if (result < 0) { + // This can happen when the file is unreadable (which can happen during + // corruption or third-party interaction). We need to be sure to inform + // the verification job that we've finished reading so that it can + // proceed; see crbug.com/703888. + if (verify_job_.get()) { + std::string tmp; + verify_job_->BytesRead(0, base::string_as_array(&tmp)); + verify_job_->DoneReading(); + } + } + } + + void OnSeekComplete(int64_t result) override { + DCHECK_EQ(seek_position_, 0); + base::AutoLock auto_lock(lock_); + seek_position_ = result; + // TODO(asargent) - we'll need to add proper support for range headers. + // crbug.com/369895. + if (result > 0 && verify_job_.get()) + verify_job_ = nullptr; + } + + void OnBytesRead(const void* data, + size_t num_bytes_read, + base::File::Error read_result) override { + if (read_result == base::File::FILE_OK) { + UMA_HISTOGRAM_COUNTS("ExtensionUrlRequest.OnReadCompleteResult", + read_result); + base::AutoLock auto_lock(lock_); + bytes_read_ += num_bytes_read; + if (verify_job_.get()) + verify_job_->BytesRead(num_bytes_read, static_cast<const char*>(data)); + } else { + net::Error net_error = net::FileErrorToNetError(read_result); + UMA_HISTOGRAM_SPARSE_SLOWLY("ExtensionUrlRequest.OnReadCompleteError", + net_error); + } + } + + void OnDoneReading() override { + base::AutoLock auto_lock(lock_); + if (verify_job_.get()) + verify_job_->DoneReading(); + } + + private: + int64_t bytes_read_ = 0; + int64_t seek_position_ = 0; + std::unique_ptr<base::ElapsedTimer> request_timer_; + scoped_refptr<ContentVerifyJob> verify_job_; + // To synchronize access to all members. + base::Lock lock_; + + DISALLOW_COPY_AND_ASSIGN(FileLoaderObserver); +}; + void LoadExtensionResourceFromFileOnBackgroundSequence( const content::ResourceRequest& request, const std::string& extension_id, const base::FilePath& directory_path, const base::FilePath& relative_path, content::mojom::URLLoaderRequest loader, - content::mojom::URLLoaderClientPtrInfo client_info) { + content::mojom::URLLoaderClientPtrInfo client_info, + scoped_refptr<ContentVerifyJob> verify_job) { // NOTE: ExtensionResource::GetFilePath() must be called on a sequence which // tolerates blocking operations. ExtensionResource resource(extension_id, directory_path, relative_path); content::mojom::URLLoaderClientPtr client; client.Bind(std::move(client_info)); + auto loader_observer = + std::make_unique<FileLoaderObserver>(std::move(verify_job)); + content::ResourceRequest file_request = request; file_request.url = net::FilePathToFileURL(resource.GetFilePath()); content::CreateFileURLLoader(file_request, std::move(loader), - std::move(client)); + std::move(client), std::move(loader_observer)); +} + +void CreateVerifierAndLoadFile( + const content::ResourceRequest& request, + const std::string& extension_id, + const base::FilePath& directory_path, + const base::FilePath& relative_path, + content::mojom::URLLoaderRequest loader, + content::mojom::URLLoaderClientPtr client, + scoped_refptr<extensions::InfoMap> extension_info_map) { + scoped_refptr<ContentVerifyJob> verify_job; + ContentVerifier* verifier = extension_info_map->content_verifier(); + if (verifier) { + verify_job = + verifier->CreateJobFor(extension_id, directory_path, relative_path); + if (verify_job) + verify_job->Start(); + } + + auto task_runner = base::CreateSequencedTaskRunnerWithTraits( + {base::MayBlock(), base::TaskPriority::BACKGROUND}); + task_runner->PostTask( + FROM_HERE, + base::BindOnce(&LoadExtensionResourceFromFileOnBackgroundSequence, + request, extension_id, directory_path, relative_path, + std::move(loader), client.PassInterface(), + std::move(verify_job))); } class ExtensionURLLoaderFactory : public content::mojom::URLLoaderFactory { @@ -679,7 +789,9 @@ // |frame_host|. explicit ExtensionURLLoaderFactory(content::RenderFrameHost* frame_host, const GURL& frame_url) - : frame_host_(frame_host), frame_url_(frame_url) {} + : frame_host_(frame_host), + frame_url_(frame_url), + extension_info_map_(nullptr) {} ~ExtensionURLLoaderFactory() override = default; // content::mojom::URLLoaderFactory: @@ -758,7 +870,7 @@ return; } - // TODO(crbug.com/782015): Support component extension resource loading from + // TODO(crbug.com/782025): Support component extension resource loading from // the embedder's resource files. This would be the right place to try to // resolve such resources, before we attempt to hit other files on disk. @@ -796,18 +908,16 @@ } } - // TODO(crbug.com/782015): Support content verification on extension - // resource requests. This is roughly the point at which we'd want to create - // a ContentVerifyJob and somehow hook it into the file URLLoader we set up - // below. + if (!extension_info_map_) { + extension_info_map_ = + extensions::ExtensionSystem::Get(browser_context)->info_map(); + } - auto task_runner = base::CreateSequencedTaskRunnerWithTraits( - {base::MayBlock(), base::TaskPriority::BACKGROUND}); - task_runner->PostTask( - FROM_HERE, - base::BindOnce(&LoadExtensionResourceFromFileOnBackgroundSequence, - request, extension_id, directory_path, relative_path, - std::move(loader), client.PassInterface())); + content::BrowserThread::PostTask( + content::BrowserThread::IO, FROM_HERE, + base::BindOnce(&CreateVerifierAndLoadFile, request, extension_id, + directory_path, relative_path, std::move(loader), + std::move(client), extension_info_map_)); } void Clone(content::mojom::URLLoaderFactoryRequest request) override { @@ -817,6 +927,7 @@ private: content::RenderFrameHost* const frame_host_; const GURL frame_url_; + scoped_refptr<extensions::InfoMap> extension_info_map_; mojo::BindingSet<content::mojom::URLLoaderFactory> bindings_;
diff --git a/gpu/ipc/service/image_transport_surface_fuchsia.cc b/gpu/ipc/service/image_transport_surface_fuchsia.cc index 65d3013c..cb967fb7 100644 --- a/gpu/ipc/service/image_transport_surface_fuchsia.cc +++ b/gpu/ipc/service/image_transport_surface_fuchsia.cc
@@ -5,6 +5,7 @@ #include "gpu/ipc/service/image_transport_surface.h" #include "base/logging.h" +#include "ui/gl/gl_surface_osmesa.h" #include "ui/gl/gl_surface_stub.h" namespace gpu { @@ -14,6 +15,10 @@ base::WeakPtr<ImageTransportSurfaceDelegate> delegate, SurfaceHandle surface_handle, gl::GLSurfaceFormat format) { + if (gl::GetGLImplementation() == gl::kGLImplementationOSMesaGL) { + return new gl::GLSurfaceOSMesa(format, gfx::Size(1, 1)); + } + DCHECK(gl::GetGLImplementation() == gl::kGLImplementationMockGL || gl::GetGLImplementation() == gl::kGLImplementationStubGL); return new gl::GLSurfaceStub;
diff --git a/ios/chrome/app/chrome_overlay_window.mm b/ios/chrome/app/chrome_overlay_window.mm index 869e50c..fcb4a8b 100644 --- a/ios/chrome/app/chrome_overlay_window.mm +++ b/ios/chrome/app/chrome_overlay_window.mm
@@ -63,10 +63,6 @@ self.traitCollection.horizontalSizeClass); } -- (void)dealloc { - [[NSNotificationCenter defaultCenter] removeObserver:self]; -} - #pragma mark - UITraitEnvironment - (void)traitCollectionDidChange:(UITraitCollection*)previousTraitCollection {
diff --git a/ios/chrome/app/main_controller.mm b/ios/chrome/app/main_controller.mm index 623e0d7..fc3d96a 100644 --- a/ios/chrome/app/main_controller.mm +++ b/ios/chrome/app/main_controller.mm
@@ -531,7 +531,6 @@ } - (void)dealloc { - [[NSNotificationCenter defaultCenter] removeObserver:self]; net::HTTPProtocolHandlerDelegate::SetInstance(nullptr); net::RequestTracker::SetRequestTrackerFactory(nullptr); [NSObject cancelPreviousPerformRequestsWithTarget:self];
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 a94bf30..142f31c9 100644 --- a/ios/chrome/browser/autofill/form_input_accessory_view_controller.mm +++ b/ios/chrome/browser/autofill/form_input_accessory_view_controller.mm
@@ -268,7 +268,6 @@ } - (void)dealloc { - [[NSNotificationCenter defaultCenter] removeObserver:self]; if (_webState) { _webState->RemoveObserver(_webStateObserverBridge.get()); _webStateObserverBridge.reset();
diff --git a/ios/chrome/browser/browser_state/chrome_browser_state_impl_io_data.mm b/ios/chrome/browser/browser_state/chrome_browser_state_impl_io_data.mm index 3f1317a..20311271 100644 --- a/ios/chrome/browser/browser_state/chrome_browser_state_impl_io_data.mm +++ b/ios/chrome/browser/browser_state/chrome_browser_state_impl_io_data.mm
@@ -351,6 +351,9 @@ DCHECK(transport_security_state()); // Completes synchronously. transport_security_state()->DeleteAllDynamicDataSince(time); - http_server_properties()->Clear(); - web::WebThread::PostTask(web::WebThread::UI, FROM_HERE, completion); + http_server_properties()->Clear(base::BindOnce( + [](const base::Closure& completion) { + web::WebThread::PostTask(web::WebThread::UI, FROM_HERE, completion); + }, + completion)); }
diff --git a/ios/chrome/browser/find_in_page/find_in_page_controller.mm b/ios/chrome/browser/find_in_page/find_in_page_controller.mm index 7efc159e..748deb8 100644 --- a/ios/chrome/browser/find_in_page/find_in_page_controller.mm +++ b/ios/chrome/browser/find_in_page/find_in_page_controller.mm
@@ -133,8 +133,6 @@ } - (void)dealloc { - [[NSNotificationCenter defaultCenter] removeObserver:self]; - if (_webState) { _webState->RemoveObserver(_webStateObserverBridge.get()); _webStateObserverBridge.reset();
diff --git a/ios/chrome/browser/geolocation/location_manager.mm b/ios/chrome/browser/geolocation/location_manager.mm index 10c5ce0..d793c97a 100644 --- a/ios/chrome/browser/geolocation/location_manager.mm +++ b/ios/chrome/browser/geolocation/location_manager.mm
@@ -77,10 +77,6 @@ return self; } -- (void)dealloc { - [[NSNotificationCenter defaultCenter] removeObserver:self]; -} - - (CLAuthorizationStatus)authorizationStatus { return [CLLocationManager authorizationStatus]; }
diff --git a/ios/chrome/browser/memory/memory_debugger.mm b/ios/chrome/browser/memory/memory_debugger.mm index f7ff214..8cac1d14 100644 --- a/ios/chrome/browser/memory/memory_debugger.mm +++ b/ios/chrome/browser/memory/memory_debugger.mm
@@ -75,10 +75,6 @@ [_memoryWarningTimer invalidate]; } -- (void)dealloc { - [[NSNotificationCenter defaultCenter] removeObserver:self]; -} - #pragma mark UIView methods - (CGSize)sizeThatFits:(CGSize)size {
diff --git a/ios/chrome/browser/net/http_server_properties_manager_factory.cc b/ios/chrome/browser/net/http_server_properties_manager_factory.cc index 032bedb..2e7ed4c 100644 --- a/ios/chrome/browser/net/http_server_properties_manager_factory.cc +++ b/ios/chrome/browser/net/http_server_properties_manager_factory.cc
@@ -8,6 +8,7 @@ #include "base/values.h" #include "components/pref_registry/pref_registry_syncable.h" +#include "components/prefs/json_pref_store.h" #include "ios/chrome/browser/pref_names.h" #include "ios/web/public/web_thread.h" #include "net/http/http_server_properties_manager.h" @@ -18,7 +19,7 @@ : public net::HttpServerPropertiesManager::PrefDelegate, public PrefStore::Observer { public: - explicit PrefServiceAdapter(scoped_refptr<WriteablePrefStore> pref_store) + explicit PrefServiceAdapter(scoped_refptr<JsonPrefStore> pref_store) : pref_store_(std::move(pref_store)), path_(prefs::kHttpServerProperties) { pref_store_->AddObserver(this); @@ -37,11 +38,15 @@ return nullptr; } - void SetServerProperties(const base::DictionaryValue& value) override { - return pref_store_->SetValue(path_, value.CreateDeepCopy(), - WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS); + void SetServerProperties(const base::DictionaryValue& value, + base::OnceClosure callback) override { + pref_store_->SetValue(path_, value.CreateDeepCopy(), + WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS); + if (callback) + pref_store_->CommitPendingWrite(std::move(callback)); } - void StartListeningForUpdates(const base::Closure& callback) override { + void StartListeningForUpdates( + const base::RepeatingClosure& callback) override { on_changed_callback_ = callback; } @@ -56,7 +61,7 @@ } private: - scoped_refptr<WriteablePrefStore> pref_store_; + scoped_refptr<JsonPrefStore> pref_store_; const std::string path_; base::Closure on_changed_callback_; @@ -69,7 +74,7 @@ // static std::unique_ptr<net::HttpServerPropertiesManager> HttpServerPropertiesManagerFactory::CreateManager( - scoped_refptr<WriteablePrefStore> pref_store, + scoped_refptr<JsonPrefStore> pref_store, net::NetLog* net_log) { DCHECK_CURRENTLY_ON(web::WebThread::IO); return std::make_unique<net::HttpServerPropertiesManager>(
diff --git a/ios/chrome/browser/net/http_server_properties_manager_factory.h b/ios/chrome/browser/net/http_server_properties_manager_factory.h index 8ae4f9b..6902ea1 100644 --- a/ios/chrome/browser/net/http_server_properties_manager_factory.h +++ b/ios/chrome/browser/net/http_server_properties_manager_factory.h
@@ -9,7 +9,8 @@ #include "base/macros.h" #include "base/memory/ref_counted.h" -#include "components/prefs/writeable_pref_store.h" + +class JsonPrefStore; namespace net { class HttpServerPropertiesManager; @@ -21,7 +22,7 @@ public: // Create an instance of HttpServerPropertiesManager. static std::unique_ptr<net::HttpServerPropertiesManager> CreateManager( - scoped_refptr<WriteablePrefStore> pref_store, + scoped_refptr<JsonPrefStore> pref_store, net::NetLog* net_log); private:
diff --git a/ios/chrome/browser/prerender/preload_controller.mm b/ios/chrome/browser/prerender/preload_controller.mm index a841343..07372d9a 100644 --- a/ios/chrome/browser/prerender/preload_controller.mm +++ b/ios/chrome/browser/prerender/preload_controller.mm
@@ -179,7 +179,6 @@ - (void)dealloc { UMA_HISTOGRAM_COUNTS(kPrerendersPerSessionCountHistogramName, successfulPrerendersPerSessionCount_); - [[NSNotificationCenter defaultCenter] removeObserver:self]; [self cancelPrerender]; }
diff --git a/ios/chrome/browser/resources/Settings.bundle/Experimental.plist b/ios/chrome/browser/resources/Settings.bundle/Experimental.plist index 9a91bb4..d691157cf 100644 --- a/ios/chrome/browser/resources/Settings.bundle/Experimental.plist +++ b/ios/chrome/browser/resources/Settings.bundle/Experimental.plist
@@ -66,28 +66,6 @@ <key>Type</key> <string>PSMultiValueSpecifier</string> <key>Title</key> - <string>Enable Signin Promo</string> - <key>Key</key> - <string>EnableSigninPromo</string> - <key>DefaultValue</key> - <string></string> - <key>Values</key> - <array> - <string></string> - <string>Enabled</string> - <string>Disabled</string> - </array> - <key>Titles</key> - <array> - <string>Default</string> - <string>Enabled</string> - <string>Disabled</string> - </array> - </dict> - <dict> - <key>Type</key> - <string>PSMultiValueSpecifier</string> - <key>Title</key> <string>Force What's New Promo</string> <key>Key</key> <string>WhatsNewPromoStatus</string>
diff --git a/ios/chrome/browser/tabs/tab_model_unittest.mm b/ios/chrome/browser/tabs/tab_model_unittest.mm index 8320df467..e04452d 100644 --- a/ios/chrome/browser/tabs/tab_model_unittest.mm +++ b/ios/chrome/browser/tabs/tab_model_unittest.mm
@@ -130,8 +130,7 @@ session_storage.lastCommittedItemIndex = -1; [sessions addObject:session_storage]; } - return base::scoped_nsobject<SessionWindowIOS>( - [[SessionWindowIOS alloc] initWithSessions:sessions selectedIndex:1]); + return [[SessionWindowIOS alloc] initWithSessions:sessions selectedIndex:1]; } web::TestWebThreadBundle thread_bundle_;
diff --git a/ios/chrome/browser/ui/authentication/chrome_signin_view_controller.mm b/ios/chrome/browser/ui/authentication/chrome_signin_view_controller.mm index c908a01..a22a790 100644 --- a/ios/chrome/browser/ui/authentication/chrome_signin_view_controller.mm +++ b/ios/chrome/browser/ui/authentication/chrome_signin_view_controller.mm
@@ -199,7 +199,6 @@ [_secondaryButton removeTarget:self action:@selector(onSecondaryButtonPressed:) forControlEvents:UIControlEventTouchDown]; - [[NSNotificationCenter defaultCenter] removeObserver:self]; } - (void)cancel {
diff --git a/ios/chrome/browser/ui/browser_view_controller.mm b/ios/chrome/browser/ui/browser_view_controller.mm index 81ba938..ecdbe3a 100644 --- a/ios/chrome/browser/ui/browser_view_controller.mm +++ b/ios/chrome/browser/ui/browser_view_controller.mm
@@ -122,6 +122,7 @@ #include "ios/chrome/browser/ui/bookmarks/bookmark_model_bridge_observer.h" #import "ios/chrome/browser/ui/browser_container_view.h" #import "ios/chrome/browser/ui/browser_view_controller_dependency_factory.h" +#import "ios/chrome/browser/ui/bubble/bubble_util.h" #import "ios/chrome/browser/ui/bubble/bubble_view_controller_presenter.h" #import "ios/chrome/browser/ui/chrome_web_view_factory.h" #import "ios/chrome/browser/ui/commands/application_commands.h" @@ -191,6 +192,7 @@ #import "ios/chrome/browser/ui/tabs/tab_strip_legacy_coordinator.h" #include "ios/chrome/browser/ui/toolbar/legacy_toolbar_coordinator.h" #import "ios/chrome/browser/ui/toolbar/legacy_toolbar_ui_updater.h" +#import "ios/chrome/browser/ui/toolbar/public/toolbar_controller_base_feature.h" #include "ios/chrome/browser/ui/toolbar/toolbar_model_delegate_ios.h" #include "ios/chrome/browser/ui/toolbar/toolbar_model_ios.h" #import "ios/chrome/browser/ui/toolbar/toolbar_snapshot_providing.h" @@ -1472,7 +1474,6 @@ _bookmarkModelBridge.reset(); [_model removeObserver:self]; [[UpgradeCenter sharedInstance] unregisterClient:self]; - [[NSNotificationCenter defaultCenter] removeObserver:self]; [_toolbarCoordinator setToolbarDelegate:nil]; if (_voiceSearchController) _voiceSearchController->SetDelegate(nil); @@ -2085,6 +2086,8 @@ AddNamedGuide(kOmniboxGuide, self.view); AddNamedGuide(kBackButtonGuide, self.view); AddNamedGuide(kForwardButtonGuide, self.view); + AddNamedGuide(kToolsMenuGuide, self.view); + AddNamedGuide(kTabSwitcherGuide, self.view); } minY += CGRectGetHeight(toolbarFrame); if (initialLayout) @@ -2428,10 +2431,19 @@ tabSwitcherAnchor = [self.tabStripCoordinator anchorPointForTabSwitcherButton:BubbleArrowDirectionUp]; } else { - DCHECK([_toolbarCoordinator - respondsToSelector:@selector(anchorPointForTabSwitcherButton:)]); - tabSwitcherAnchor = [_toolbarCoordinator - anchorPointForTabSwitcherButton:BubbleArrowDirectionUp]; + if (base::FeatureList::IsEnabled(kCleanToolbar)) { + UILayoutGuide* guide = FindNamedGuide(kTabSwitcherGuide, self.view); + CGPoint anchorPoint = + bubble_util::AnchorPoint(guide.layoutFrame, BubbleArrowDirectionUp); + tabSwitcherAnchor = + [guide.owningView convertPoint:anchorPoint + toView:guide.owningView.window]; + } else { + DCHECK([_toolbarCoordinator + respondsToSelector:@selector(anchorPointForTabSwitcherButton:)]); + tabSwitcherAnchor = [_toolbarCoordinator + anchorPointForTabSwitcherButton:BubbleArrowDirectionUp]; + } } // If the feature engagement tracker does not consider it valid to display @@ -2489,8 +2501,17 @@ NSString* text = l10n_util::GetNSStringWithFixup( IDS_IOS_NEW_INCOGNITO_TAB_IPH_PROMOTION_TEXT); - CGPoint toolsButtonAnchor = [_toolbarCoordinator - anchorPointForToolsMenuButton:BubbleArrowDirectionUp]; + CGPoint toolsButtonAnchor; + if (base::FeatureList::IsEnabled(kCleanToolbar)) { + UILayoutGuide* guide = FindNamedGuide(kToolsMenuGuide, self.view); + CGPoint anchorPoint = + bubble_util::AnchorPoint(guide.layoutFrame, BubbleArrowDirectionUp); + toolsButtonAnchor = [guide.owningView convertPoint:anchorPoint + toView:guide.owningView.window]; + } else { + toolsButtonAnchor = [_toolbarCoordinator + anchorPointForToolsMenuButton:BubbleArrowDirectionUp]; + } // If the feature engagement tracker does not consider it valid to display // the incognito tab tip, then end early to prevent the potential reassignment @@ -2680,8 +2701,8 @@ NSString* contentType = base::SysUTF8ToNSString(postData->first); NSData* data = [NSData dataWithBytes:(void*)postData->second.data() length:postData->second.length()]; - params.post_data.reset(data); - params.extra_headers.reset(@{ @"Content-Type" : contentType }); + params.post_data = data; + params.extra_headers = @{@"Content-Type" : contentType}; } if (tabAddedCompletion) {
diff --git a/ios/chrome/browser/ui/bubble/bubble_view_anchor_point_provider.h b/ios/chrome/browser/ui/bubble/bubble_view_anchor_point_provider.h index 31dd9b2a..17e338a3b 100644 --- a/ios/chrome/browser/ui/bubble/bubble_view_anchor_point_provider.h +++ b/ios/chrome/browser/ui/bubble/bubble_view_anchor_point_provider.h
@@ -14,10 +14,13 @@ @optional // Returns either the top-middle or bottom-middle of the tab switcher button // based on |direction|. Point is in window-coordinates. +// TODO(crbug.com/788705): This method can probably becomes required if it is +// the only one. It would allow to remove the DCHECK. - (CGPoint)anchorPointForTabSwitcherButton:(BubbleArrowDirection)direction; // Returns either the top-middle or bottom-middle of the tools menu button // based on |direction|. Point is in window-coordinates. +// TODO(crbug.com/788705): Remove this methods during old toolbar's cleanup. - (CGPoint)anchorPointForToolsMenuButton:(BubbleArrowDirection)direction; @end
diff --git a/ios/chrome/browser/ui/context_menu/context_menu_coordinator_unittest.mm b/ios/chrome/browser/ui/context_menu/context_menu_coordinator_unittest.mm index 2b58812..bd07942 100644 --- a/ios/chrome/browser/ui/context_menu/context_menu_coordinator_unittest.mm +++ b/ios/chrome/browser/ui/context_menu/context_menu_coordinator_unittest.mm
@@ -42,7 +42,7 @@ TEST_F(ContextMenuCoordinatorTest, ValidateIsVisible) { web::ContextMenuParams params; params.location = CGPointZero; - params.view.reset([view_controller_ view]); + params.view = [view_controller_ view]; menu_coordinator_ = [[ContextMenuCoordinator alloc] initWithBaseViewController:view_controller_ params:params]; @@ -55,7 +55,7 @@ TEST_F(ContextMenuCoordinatorTest, ValidateDismissalOnStop) { web::ContextMenuParams params; params.location = CGPointZero; - params.view.reset([view_controller_ view]); + params.view = [view_controller_ view]; menu_coordinator_ = [[ContextMenuCoordinator alloc] initWithBaseViewController:view_controller_ params:params]; @@ -70,7 +70,7 @@ TEST_F(ContextMenuCoordinatorTest, ValidateActions) { web::ContextMenuParams params; params.location = CGPointZero; - params.view.reset([view_controller_ view]); + params.view = [view_controller_ view]; menu_coordinator_ = [[ContextMenuCoordinator alloc] initWithBaseViewController:view_controller_ params:params]; @@ -105,7 +105,7 @@ TEST_F(ContextMenuCoordinatorTest, CancelButtonExists) { web::ContextMenuParams params; params.location = CGPointZero; - params.view.reset([view_controller_ view]); + params.view = [view_controller_ view]; menu_coordinator_ = [[ContextMenuCoordinator alloc] initWithBaseViewController:view_controller_ params:params]; @@ -130,8 +130,8 @@ web::ContextMenuParams params; params.location = location; - params.menu_title.reset(title); - params.view.reset([view_controller_ view]); + params.menu_title = title; + params.view = [view_controller_ view]; menu_coordinator_ = [[ContextMenuCoordinator alloc] initWithBaseViewController:view_controller_ params:params];
diff --git a/ios/chrome/browser/ui/fullscreen/legacy_fullscreen_controller.mm b/ios/chrome/browser/ui/fullscreen/legacy_fullscreen_controller.mm index 118a1345..44a6e37 100644 --- a/ios/chrome/browser/ui/fullscreen/legacy_fullscreen_controller.mm +++ b/ios/chrome/browser/ui/fullscreen/legacy_fullscreen_controller.mm
@@ -322,7 +322,6 @@ } - (void)dealloc { - [[NSNotificationCenter defaultCenter] removeObserver:self]; scopedObserver_.reset(); observerBridge_.reset(); }
diff --git a/ios/chrome/browser/ui/history/history_collection_view_controller.mm b/ios/chrome/browser/ui/history/history_collection_view_controller.mm index 7219ca8..30e489cf 100644 --- a/ios/chrome/browser/ui/history/history_collection_view_controller.mm +++ b/ios/chrome/browser/ui/history/history_collection_view_controller.mm
@@ -821,10 +821,10 @@ __weak HistoryCollectionViewController* weakSelf = self; web::ContextMenuParams params; params.location = touchLocation; - params.view.reset(self.collectionView); + params.view = self.collectionView; NSString* menuTitle = base::SysUTF16ToNSString(url_formatter::FormatUrl(entry.URL)); - params.menu_title.reset([menuTitle copy]); + params.menu_title = [menuTitle copy]; // Present sheet/popover using controller that is added to view hierarchy. // TODO(crbug.com/754642): Remove TopPresentedViewController().
diff --git a/ios/chrome/browser/ui/ntp/new_tab_page_controller.mm b/ios/chrome/browser/ui/ntp/new_tab_page_controller.mm index b2f9f7c..d2cee67 100644 --- a/ios/chrome/browser/ui/ntp/new_tab_page_controller.mm +++ b/ios/chrome/browser/ui/ntp/new_tab_page_controller.mm
@@ -340,7 +340,6 @@ [self.homePanel setDelegate:nil]; [_bookmarkController setDelegate:nil]; [_openTabsCoordinator setDelegate:nil]; - [[NSNotificationCenter defaultCenter] removeObserver:self]; } #pragma mark - CRWNativeContent
diff --git a/ios/chrome/browser/ui/ntp/recent_tabs/recent_tabs_table_view_controller.mm b/ios/chrome/browser/ui/ntp/recent_tabs/recent_tabs_table_view_controller.mm index 8f44bcb..0bcb1586 100644 --- a/ios/chrome/browser/ui/ntp/recent_tabs/recent_tabs_table_view_controller.mm +++ b/ios/chrome/browser/ui/ntp/recent_tabs/recent_tabs_table_view_controller.mm
@@ -632,7 +632,7 @@ // Get view coordinates in local space. CGPoint viewCoordinate = [longPressGesture locationInView:self.tableView]; params.location = viewCoordinate; - params.view.reset(self.tableView); + params.view = self.tableView; // Present sheet/popover using controller that is added to view hierarchy. // TODO(crbug.com/754642): Remove TopPresentedViewController().
diff --git a/ios/chrome/browser/ui/omnibox/omnibox_popup_view_controller.mm b/ios/chrome/browser/ui/omnibox/omnibox_popup_view_controller.mm index 508e0f0..0981f4d8 100644 --- a/ios/chrome/browser/ui/omnibox/omnibox_popup_view_controller.mm +++ b/ios/chrome/browser/ui/omnibox/omnibox_popup_view_controller.mm
@@ -86,7 +86,6 @@ - (void)dealloc { self.tableView.delegate = nil; - [[NSNotificationCenter defaultCenter] removeObserver:self]; } - (UIScrollView*)scrollView {
diff --git a/ios/chrome/browser/ui/settings/accounts_collection_view_controller.mm b/ios/chrome/browser/ui/settings/accounts_collection_view_controller.mm index 56ef9a8..2878937 100644 --- a/ios/chrome/browser/ui/settings/accounts_collection_view_controller.mm +++ b/ios/chrome/browser/ui/settings/accounts_collection_view_controller.mm
@@ -159,10 +159,6 @@ return self; } -- (void)dealloc { - [[NSNotificationCenter defaultCenter] removeObserver:self]; -} - - (void)stopBrowserStateServiceObservers { _tokenServiceObserver.reset(); _syncObserver.reset();
diff --git a/ios/chrome/browser/ui/settings/autofill_edit_collection_view_controller.mm b/ios/chrome/browser/ui/settings/autofill_edit_collection_view_controller.mm index 712dc97a..fb72c0d 100644 --- a/ios/chrome/browser/ui/settings/autofill_edit_collection_view_controller.mm +++ b/ios/chrome/browser/ui/settings/autofill_edit_collection_view_controller.mm
@@ -73,10 +73,6 @@ object:nil]; } -- (void)dealloc { - [[NSNotificationCenter defaultCenter] removeObserver:self]; -} - #pragma mark - SettingsRootCollectionViewController - (BOOL)shouldShowEditButton {
diff --git a/ios/chrome/browser/ui/settings/password_details_collection_view_controller.mm b/ios/chrome/browser/ui/settings/password_details_collection_view_controller.mm index 5ee7676..393ba663 100644 --- a/ios/chrome/browser/ui/settings/password_details_collection_view_controller.mm +++ b/ios/chrome/browser/ui/settings/password_details_collection_view_controller.mm
@@ -244,10 +244,6 @@ toSectionWithIdentifier:SectionIdentifierDelete]; } -- (void)dealloc { - [[NSNotificationCenter defaultCenter] removeObserver:self]; -} - #pragma mark - Items - (CollectionViewItem*)siteCopyButtonItem {
diff --git a/ios/chrome/browser/ui/toolbar/clean/BUILD.gn b/ios/chrome/browser/ui/toolbar/clean/BUILD.gn index 0e1bbe8..b539d5fd 100644 --- a/ios/chrome/browser/ui/toolbar/clean/BUILD.gn +++ b/ios/chrome/browser/ui/toolbar/clean/BUILD.gn
@@ -73,7 +73,6 @@ "//ios/chrome/app/theme", "//ios/chrome/browser/ui", "//ios/chrome/browser/ui/activity_services/requirements", - "//ios/chrome/browser/ui/bubble", "//ios/chrome/browser/ui/commands", "//ios/chrome/browser/ui/fullscreen:new_fullscreen_ui", "//ios/chrome/browser/ui/history_popup/requirements",
diff --git a/ios/chrome/browser/ui/toolbar/clean/toolbar_coordinator.h b/ios/chrome/browser/ui/toolbar/clean/toolbar_coordinator.h index 5a78180..b919e893 100644 --- a/ios/chrome/browser/ui/toolbar/clean/toolbar_coordinator.h +++ b/ios/chrome/browser/ui/toolbar/clean/toolbar_coordinator.h
@@ -14,7 +14,6 @@ @protocol ActivityServicePositioner; @protocol ApplicationCommands; -@protocol BubbleViewAnchorPointProvider; @protocol BrowserCommands; @class ToolbarButtonUpdater; @protocol ToolbarCoordinatorDelegate; @@ -50,8 +49,6 @@ // Returns the ActivityServicePositioner for this toolbar. - (id<ActivityServicePositioner>)activityServicePositioner; -// Returns the BubbleViewAnchorPointProvider for this toolbar. -- (id<BubbleViewAnchorPointProvider>)bubbleAnchorPointProvider; // Start this coordinator. - (void)start;
diff --git a/ios/chrome/browser/ui/toolbar/clean/toolbar_coordinator.mm b/ios/chrome/browser/ui/toolbar/clean/toolbar_coordinator.mm index 3c85536..b1e542e 100644 --- a/ios/chrome/browser/ui/toolbar/clean/toolbar_coordinator.mm +++ b/ios/chrome/browser/ui/toolbar/clean/toolbar_coordinator.mm
@@ -207,10 +207,6 @@ return self.toolbarViewController; } -- (id<BubbleViewAnchorPointProvider>)bubbleAnchorPointProvider { - return self.toolbarViewController; -} - - (void)updateOmniboxState { _locationBar->SetShouldShowHintText( [self.delegate toolbarModelIOS]->ShouldDisplayHintText());
diff --git a/ios/chrome/browser/ui/toolbar/clean/toolbar_view_controller.h b/ios/chrome/browser/ui/toolbar/clean/toolbar_view_controller.h index 5f4c0913..6590e24 100644 --- a/ios/chrome/browser/ui/toolbar/clean/toolbar_view_controller.h +++ b/ios/chrome/browser/ui/toolbar/clean/toolbar_view_controller.h
@@ -8,7 +8,6 @@ #import <UIKit/UIKit.h> #import "ios/chrome/browser/ui/activity_services/requirements/activity_service_positioner.h" -#import "ios/chrome/browser/ui/bubble/bubble_view_anchor_point_provider.h" #import "ios/chrome/browser/ui/fullscreen/fullscreen_ui_element.h" #import "ios/chrome/browser/ui/toolbar/clean/toolbar_consumer.h" @@ -23,7 +22,6 @@ // controls and/or labels. @interface ToolbarViewController : UIViewController<ActivityServicePositioner, - BubbleViewAnchorPointProvider, FullscreenUIElement, ToolbarConsumer>
diff --git a/ios/chrome/browser/ui/toolbar/clean/toolbar_view_controller.mm b/ios/chrome/browser/ui/toolbar/clean/toolbar_view_controller.mm index 78f9864..81e3d0a 100644 --- a/ios/chrome/browser/ui/toolbar/clean/toolbar_view_controller.mm +++ b/ios/chrome/browser/ui/toolbar/clean/toolbar_view_controller.mm
@@ -6,7 +6,6 @@ #import "base/mac/foundation_util.h" #include "base/metrics/user_metrics.h" -#import "ios/chrome/browser/ui/bubble/bubble_util.h" #import "ios/chrome/browser/ui/commands/application_commands.h" #import "ios/chrome/browser/ui/commands/browser_commands.h" #import "ios/chrome/browser/ui/commands/history_popup_commands.h" @@ -424,13 +423,15 @@ } - (void)didMoveToParentViewController:(UIViewController*)parent { - UILayoutGuide* omniboxPopupGuide = FindNamedGuide(kOmniboxGuide, self.view); - AddSameConstraints(self.view.locationBarContainer, omniboxPopupGuide); - UILayoutGuide* backButtonGuide = FindNamedGuide(kBackButtonGuide, self.view); - AddSameConstraints(self.view.backButton.imageView, backButtonGuide); - UILayoutGuide* forwardButtonGuide = - FindNamedGuide(kForwardButtonGuide, self.view); - AddSameConstraints(self.view.forwardButton.imageView, forwardButtonGuide); + ConstrainNamedGuideToView(kOmniboxGuide, self.view.locationBarContainer); + ConstrainNamedGuideToView(kBackButtonGuide, self.view.backButton.imageView); + ConstrainNamedGuideToView(kForwardButtonGuide, + self.view.forwardButton.imageView); + ConstrainNamedGuideToView(kToolsMenuGuide, self.view.toolsMenuButton); + if (!IsIPadIdiom()) { + ConstrainNamedGuideToView(kTabSwitcherGuide, + self.view.tabSwitchStripButton.imageView); + } } #pragma mark - Trait Collection Changes @@ -551,24 +552,6 @@ return self.view.shareButton; } -#pragma mark - BubbleViewAnchorPointProvider - -- (CGPoint)anchorPointForTabSwitcherButton:(BubbleArrowDirection)direction { - CGPoint anchorPoint = bubble_util::AnchorPoint( - self.view.tabSwitchStripButton.imageView.frame, direction); - return [self.view.tabSwitchStripButton.imageView.superview - convertPoint:anchorPoint - toView:self.view.tabSwitchStripButton.imageView.window]; -} - -- (CGPoint)anchorPointForToolsMenuButton:(BubbleArrowDirection)direction { - CGPoint anchorPoint = - bubble_util::AnchorPoint(self.view.toolsMenuButton.frame, direction); - return [self.view.toolsMenuButton.superview - convertPoint:anchorPoint - toView:self.view.toolsMenuButton.window]; -} - #pragma mark - FullscreenUIElement - (void)updateForFullscreenProgress:(CGFloat)progress {
diff --git a/ios/chrome/browser/ui/toolbar/toolbar_adapter.mm b/ios/chrome/browser/ui/toolbar/toolbar_adapter.mm index 4caa045..5af08ab 100644 --- a/ios/chrome/browser/ui/toolbar/toolbar_adapter.mm +++ b/ios/chrome/browser/ui/toolbar/toolbar_adapter.mm
@@ -56,7 +56,7 @@ #pragma mark - Abstract WebToolbar - (void)browserStateDestroyed { - return; + [self.toolbarCoordinator stop]; } - (void)updateToolbarState { @@ -174,13 +174,13 @@ #pragma mark - BubbleViewAnchorPointProvider - (CGPoint)anchorPointForTabSwitcherButton:(BubbleArrowDirection)direction { - return [[self.toolbarCoordinator bubbleAnchorPointProvider] - anchorPointForTabSwitcherButton:direction]; + // No-op. The Clean Toolbar uses named layout guides. + return CGPointZero; } - (CGPoint)anchorPointForToolsMenuButton:(BubbleArrowDirection)direction { - return [[self.toolbarCoordinator bubbleAnchorPointProvider] - anchorPointForToolsMenuButton:direction]; + // No-op. The Clean Toolbar uses named layout guides. + return CGPointZero; } #pragma mark - FullscreenUIElement
diff --git a/ios/chrome/browser/ui/toolbar/web_toolbar_controller.mm b/ios/chrome/browser/ui/toolbar/web_toolbar_controller.mm index f72d79a..f1011d4e 100644 --- a/ios/chrome/browser/ui/toolbar/web_toolbar_controller.mm +++ b/ios/chrome/browser/ui/toolbar/web_toolbar_controller.mm
@@ -568,10 +568,6 @@ return self; } -- (void)dealloc { - [[NSNotificationCenter defaultCenter] removeObserver:self]; -} - - (UIViewController*)viewController { return self; }
diff --git a/ios/chrome/browser/ui/util/BUILD.gn b/ios/chrome/browser/ui/util/BUILD.gn index 8b46d82d..b12b95b 100644 --- a/ios/chrome/browser/ui/util/BUILD.gn +++ b/ios/chrome/browser/ui/util/BUILD.gn
@@ -38,6 +38,7 @@ "unicode_util.mm", ] deps = [ + ":constraints_ui", "//base", "//base:i18n", "//ios/chrome/browser",
diff --git a/ios/chrome/browser/ui/util/named_guide.h b/ios/chrome/browser/ui/util/named_guide.h index 67316d9..e911e03 100644 --- a/ios/chrome/browser/ui/util/named_guide.h +++ b/ios/chrome/browser/ui/util/named_guide.h
@@ -19,6 +19,11 @@ extern GuideName* const kBackButtonGuide; // A guide that is constrained to match the frame of the forward button's image. extern GuideName* const kForwardButtonGuide; +// A guide that is constrained to match the frame of the TabSwitcher button's +// image. +extern GuideName* const kTabSwitcherGuide; +// A guide that is constrained to match the frame of the ToolsMenu button. +extern GuideName* const kToolsMenuGuide; // ////////////////////////////////////////// @@ -32,4 +37,8 @@ // with the same name as an existing guide. Returns the newly-created guide. UILayoutGuide* AddNamedGuide(GuideName* name, UIView* view); +// Adds constraints such as the layoutGuide with |guideName| matches the |view|. +// The layout guide has to be owned by |view| or one of its superview. +void ConstrainNamedGuideToView(GuideName* guideName, UIView* view); + #endif // IOS_CHROME_BROWSER_UI_UTIL_NAMED_GUIDE_H_
diff --git a/ios/chrome/browser/ui/util/named_guide.mm b/ios/chrome/browser/ui/util/named_guide.mm index 5a3107a..fab95be0 100644 --- a/ios/chrome/browser/ui/util/named_guide.mm +++ b/ios/chrome/browser/ui/util/named_guide.mm
@@ -5,6 +5,7 @@ #import "ios/chrome/browser/ui/util/named_guide.h" #include "base/logging.h" +#import "ios/chrome/browser/ui/util/constraints_ui_util.h" #if !defined(__has_feature) || !__has_feature(objc_arc) #error "This file requires ARC support." @@ -14,6 +15,8 @@ GuideName* const kOmniboxGuide = @"kOmniboxGuide"; GuideName* const kBackButtonGuide = @"kBackButtonGuide"; GuideName* const kForwardButtonGuide = @"kForwardButtonGuide"; +GuideName* const kTabSwitcherGuide = @"kTabSwitcherGuide"; +GuideName* const kToolsMenuGuide = @"kToolsMenuGuide"; UILayoutGuide* FindNamedGuide(GuideName* name, UIView* view) { while (view) { @@ -33,3 +36,8 @@ [view addLayoutGuide:guide]; return guide; } + +void ConstrainNamedGuideToView(GuideName* guideName, UIView* view) { + UILayoutGuide* layoutGuide = FindNamedGuide(guideName, view); + AddSameConstraints(view, layoutGuide); +}
diff --git a/ios/chrome/browser/ui/voice/text_to_speech_player.mm b/ios/chrome/browser/ui/voice/text_to_speech_player.mm index e4d23c1..1dc2544 100644 --- a/ios/chrome/browser/ui/voice/text_to_speech_player.mm +++ b/ios/chrome/browser/ui/voice/text_to_speech_player.mm
@@ -45,7 +45,6 @@ } - (void)dealloc { - [[NSNotificationCenter defaultCenter] removeObserver:self]; [self cancelPlayback]; }
diff --git a/ios/chrome/browser/ui/voice/text_to_speech_player_unittest.mm b/ios/chrome/browser/ui/voice/text_to_speech_player_unittest.mm index 8f6f203..9ee7cd25 100644 --- a/ios/chrome/browser/ui/voice/text_to_speech_player_unittest.mm +++ b/ios/chrome/browser/ui/voice/text_to_speech_player_unittest.mm
@@ -46,10 +46,6 @@ @synthesize willStartNotificationReceived = _willStartNotificationReceived; @synthesize didStopNotificationReceived = _didStopNotificationReceived; -- (void)dealloc { - [[NSNotificationCenter defaultCenter] removeObserver:self]; -} - - (void)setPlayer:(TextToSpeechPlayer*)player { NSNotificationCenter* defaultCenter = [NSNotificationCenter defaultCenter]; [defaultCenter removeObserver:self];
diff --git a/ios/web/navigation/navigation_item_impl.mm b/ios/web/navigation/navigation_item_impl.mm index e273e3da..73a7256 100644 --- a/ios/web/navigation/navigation_item_impl.mm +++ b/ios/web/navigation/navigation_item_impl.mm
@@ -66,7 +66,7 @@ ssl_(item.ssl_), timestamp_(item.timestamp_), user_agent_type_(item.user_agent_type_), - http_request_headers_([item.http_request_headers_ copy]), + http_request_headers_([item.http_request_headers_ mutableCopy]), serialized_state_object_([item.serialized_state_object_ copy]), is_created_from_push_state_(item.is_created_from_push_state_), has_state_been_replaced_(item.has_state_been_replaced_),
diff --git a/ios/web/navigation/navigation_item_impl_unittest.mm b/ios/web/navigation/navigation_item_impl_unittest.mm index 401f8cd..7f9964fe 100644 --- a/ios/web/navigation/navigation_item_impl_unittest.mm +++ b/ios/web/navigation/navigation_item_impl_unittest.mm
@@ -90,6 +90,9 @@ EXPECT_NSEQ([postData0 dataUsingEncoding:NSUTF8StringEncoding], copy.GetPostData()); EXPECT_NSEQ(state0, copy.GetSerializedStateObject()); + + // Ensure that HTTP headers are still mutable after the copying. + copy.AddHttpRequestHeaders(@{}); } // Tests whether |NavigationItem::AddHttpRequestHeaders()| adds the passed
diff --git a/ios/web/navigation/navigation_manager_impl.mm b/ios/web/navigation/navigation_manager_impl.mm index 53c7124..8b0eafa7 100644 --- a/ios/web/navigation/navigation_manager_impl.mm +++ b/ios/web/navigation/navigation_manager_impl.mm
@@ -40,8 +40,8 @@ is_renderer_initiated = other.is_renderer_initiated; transition_type = other.transition_type; user_agent_override_option = other.user_agent_override_option; - extra_headers.reset([other.extra_headers copy]); - post_data.reset([other.post_data copy]); + extra_headers = [other.extra_headers copy]; + post_data = [other.post_data copy]; return *this; }
diff --git a/ios/web/navigation/navigation_manager_impl_unittest.mm b/ios/web/navigation/navigation_manager_impl_unittest.mm index c7d39974..a13af61b 100644 --- a/ios/web/navigation/navigation_manager_impl_unittest.mm +++ b/ios/web/navigation/navigation_manager_impl_unittest.mm
@@ -2121,8 +2121,8 @@ TEST_P(NavigationManagerTest, LoadURLWithParamsWithExtraHeadersAndPostData) { NavigationManager::WebLoadParams params(GURL("http://www.url.com/0")); params.transition_type = ui::PAGE_TRANSITION_TYPED; - params.extra_headers.reset(@{@"Content-Type" : @"text/plain"}); - params.post_data.reset([NSData data]); + params.extra_headers = @{@"Content-Type" : @"text/plain"}; + params.post_data = [NSData data]; EXPECT_CALL(navigation_manager_delegate(), RecordPageStateInNavigationItem()) .Times(1);
diff --git a/ios/web/public/navigation_manager.h b/ios/web/public/navigation_manager.h index 73dc66f0..af301944 100644 --- a/ios/web/public/navigation_manager.h +++ b/ios/web/public/navigation_manager.h
@@ -7,7 +7,6 @@ #include <stddef.h> -#import "base/mac/scoped_nsobject.h" #include "ios/web/public/browser_url_rewriter.h" #include "ios/web/public/navigation_item_list.h" #include "ios/web/public/referrer.h" @@ -65,11 +64,11 @@ bool is_renderer_initiated; // Any extra HTTP headers to add to the load. - base::scoped_nsobject<NSDictionary> extra_headers; + NSDictionary* extra_headers; // Any post data to send with the load. When setting this, you should // generally set a Content-Type header as well. - base::scoped_nsobject<NSData> post_data; + NSData* post_data; // Create a new WebLoadParams with the given URL and defaults for all other // parameters.
diff --git a/ios/web/public/test/web_js_test.h b/ios/web/public/test/web_js_test.h index 72e023a..481c320 100644 --- a/ios/web/public/test/web_js_test.h +++ b/ios/web/public/test/web_js_test.h
@@ -8,7 +8,6 @@ #import <Foundation/Foundation.h> #import "base/mac/bundle_locations.h" -#import "base/mac/scoped_nsobject.h" #import "testing/gtest_mac.h" namespace web { @@ -53,7 +52,7 @@ // Injects JavaScript at |java_script_paths_|. void Inject(); - base::scoped_nsobject<NSArray> java_script_paths_; + NSArray* java_script_paths_; }; template <class WebTestT> @@ -61,7 +60,7 @@ // Main web injection should have occurred. ASSERT_NSEQ(@"object", WebTestT::ExecuteJavaScript(@"typeof __gCrWeb")); - for (NSString* java_script_path in java_script_paths_.get()) { + for (NSString* java_script_path in java_script_paths_) { NSString* path = [base::mac::FrameworkBundle() pathForResource:java_script_path ofType:@"js"]; @@ -76,8 +75,8 @@ id WebJsTest<WebTestT>::ExecuteJavaScriptWithFormat(NSString* format, ...) { va_list args; va_start(args, format); - base::scoped_nsobject<NSString> java_script( - [[NSString alloc] initWithFormat:format arguments:args]); + NSString* java_script = + [[NSString alloc] initWithFormat:format arguments:args]; va_end(args); return WebTestT::ExecuteJavaScript(java_script);
diff --git a/ios/web/public/web_state/context_menu_params.h b/ios/web/public/web_state/context_menu_params.h index 925fa300..79e6e59 100644 --- a/ios/web/public/web_state/context_menu_params.h +++ b/ios/web/public/web_state/context_menu_params.h
@@ -6,7 +6,6 @@ #import <UIKit/UIKit.h> -#import "base/mac/scoped_nsobject.h" #include "base/strings/string16.h" #include "ios/web/public/referrer.h" #include "url/gurl.h" @@ -21,7 +20,7 @@ ~ContextMenuParams(); // The title of the menu. - base::scoped_nsobject<NSString> menu_title; + NSString* menu_title; // The URL of the link that encloses the node the context menu was invoked on. GURL link_url; @@ -34,14 +33,14 @@ web::ReferrerPolicy referrer_policy; // The view in which to present the menu. - base::scoped_nsobject<UIView> view; + UIView* view; // The location in |view| to present the menu. CGPoint location; // The text associated with the link. It is either nil or nonempty (it can not // be empty). - base::scoped_nsobject<NSString> link_text; + NSString* link_text; }; } // namespace web
diff --git a/ios/web/web_state/context_menu_params_utils.mm b/ios/web/web_state/context_menu_params_utils.mm index 2e3074b7..de1eff3 100644 --- a/ios/web/web_state/context_menu_params_utils.mm +++ b/ios/web/web_state/context_menu_params_utils.mm
@@ -41,7 +41,7 @@ if (titleAttribute) title = titleAttribute; if (title) { - params.menu_title.reset([title copy]); + params.menu_title = [title copy]; } NSString* referrerPolicy = element[kContextMenuElementReferrerPolicy]; if (referrerPolicy) { @@ -50,7 +50,7 @@ } NSString* innerText = element[kContextMenuElementInnerText]; if ([innerText length] > 0) { - params.link_text.reset([innerText copy]); + params.link_text = [innerText copy]; } return params; }
diff --git a/ios/web/web_state/context_menu_params_utils_unittest.mm b/ios/web/web_state/context_menu_params_utils_unittest.mm index fefd076..dcfeb95 100644 --- a/ios/web/web_state/context_menu_params_utils_unittest.mm +++ b/ios/web/web_state/context_menu_params_utils_unittest.mm
@@ -37,13 +37,13 @@ // Tests the empty contructor. TEST_F(ContextMenuParamsUtilsTest, EmptyParams) { web::ContextMenuParams params; - EXPECT_EQ(params.menu_title.get(), nil); + EXPECT_EQ(params.menu_title, nil); EXPECT_FALSE(params.link_url.is_valid()); EXPECT_FALSE(params.src_url.is_valid()); EXPECT_EQ(params.referrer_policy, web::ReferrerPolicyDefault); - EXPECT_EQ(params.view.get(), nil); + EXPECT_EQ(params.view, nil); EXPECT_TRUE(CGPointEqualToPoint(params.location, CGPointZero)); - EXPECT_EQ(params.link_text.get(), nil); + EXPECT_EQ(params.link_text, nil); } // Tests the the parsing of the element NSDictionary. @@ -56,14 +56,14 @@ kContextMenuElementInnerText : @(kLinkText), }); - EXPECT_NSEQ(params.menu_title.get(), @(kTitle)); + EXPECT_NSEQ(params.menu_title, @(kTitle)); EXPECT_EQ(params.link_url, GURL(kLinkUrl)); EXPECT_EQ(params.src_url, GURL(kSrcUrl)); - EXPECT_NSEQ(params.link_text.get(), @(kLinkText)); + EXPECT_NSEQ(params.link_text, @(kLinkText)); EXPECT_EQ(params.referrer_policy, web::ReferrerPolicyFromString(kReferrerPolicy)); - EXPECT_EQ(params.view.get(), nil); + EXPECT_EQ(params.view, nil); EXPECT_TRUE(CGPointEqualToPoint(params.location, CGPointZero)); } @@ -75,7 +75,7 @@ base::string16 urlText = url_formatter::FormatUrl(GURL(kLinkUrl)); NSString* title = base::SysUTF16ToNSString(urlText); - EXPECT_NSEQ(params.menu_title.get(), title); + EXPECT_NSEQ(params.menu_title, title); } // Tests title is set to "JavaScript" if there is no title and "href" links to @@ -84,7 +84,7 @@ web::ContextMenuParams params = web::ContextMenuParamsFromElementDictionary(@{ kContextMenuElementHyperlink : @(kJavaScriptLinkUrl), }); - EXPECT_NSEQ(params.menu_title.get(), @"JavaScript"); + EXPECT_NSEQ(params.menu_title, @"JavaScript"); } // Tests title is set to |src_url| if there is no title. @@ -93,7 +93,7 @@ kContextMenuElementSource : @(kSrcUrl), }); EXPECT_EQ(params.src_url, GURL(kSrcUrl)); - EXPECT_NSEQ(params.menu_title.get(), @(kSrcUrl)); + EXPECT_NSEQ(params.menu_title, @(kSrcUrl)); } // Tests title is set to nil if there is no title and src is a data URL. @@ -102,7 +102,7 @@ kContextMenuElementSource : @(kDataUrl), }); EXPECT_EQ(params.src_url, GURL(kDataUrl)); - EXPECT_NSEQ(params.menu_title.get(), nil); + EXPECT_NSEQ(params.menu_title, nil); } } // namespace web
diff --git a/ios/web/web_state/navigation_and_load_callbacks_inttest.mm b/ios/web/web_state/navigation_and_load_callbacks_inttest.mm index 59cd9a2..a2ff79c6 100644 --- a/ios/web/web_state/navigation_and_load_callbacks_inttest.mm +++ b/ios/web/web_state/navigation_and_load_callbacks_inttest.mm
@@ -727,8 +727,8 @@ // Load request using POST HTTP method. web::NavigationManager::WebLoadParams params(url); - params.post_data.reset([@"foo" dataUsingEncoding:NSUTF8StringEncoding]); - params.extra_headers.reset(@{@"Content-Type" : @"text/html"}); + params.post_data = [@"foo" dataUsingEncoding:NSUTF8StringEncoding]; + params.extra_headers = @{@"Content-Type" : @"text/html"}; LoadWithParams(params); ASSERT_TRUE(WaitForWebViewContainingText(web_state(), kTestPageText)); }
diff --git a/ios/web/web_state/ui/crw_context_menu_controller.mm b/ios/web/web_state/ui/crw_context_menu_controller.mm index a41b263..4f95ead5 100644 --- a/ios/web/web_state/ui/crw_context_menu_controller.mm +++ b/ios/web/web_state/ui/crw_context_menu_controller.mm
@@ -255,7 +255,7 @@ - (void)showContextMenu { web::ContextMenuParams params = web::ContextMenuParamsFromElementDictionary(_DOMElementForLastTouch); - params.view.reset(_webView); + params.view = _webView; params.location = _locationForLastTouch; [_delegate webView:_webView handleContextMenu:params]; }
diff --git a/ios/web/web_state/ui/crw_web_controller.mm b/ios/web/web_state/ui/crw_web_controller.mm index 77f3962..88a5c1a 100644 --- a/ios/web/web_state/ui/crw_web_controller.mm +++ b/ios/web/web_state/ui/crw_web_controller.mm
@@ -1870,8 +1870,8 @@ // the transient item's URL (as on other platforms). NavigationManager::WebLoadParams reloadParams(transientItem->GetURL()); reloadParams.transition_type = ui::PAGE_TRANSITION_RELOAD; - reloadParams.extra_headers.reset( - [transientItem->GetHttpRequestHeaders() copy]); + reloadParams.extra_headers = + [transientItem->GetHttpRequestHeaders() copy]; self.webState->GetNavigationManager()->LoadURLWithParams(reloadParams); } else { self.currentNavItem->SetTransitionType(
diff --git a/ios/web/web_state/web_state_delegate_bridge_unittest.mm b/ios/web/web_state/web_state_delegate_bridge_unittest.mm index 79745387..43338bd 100644 --- a/ios/web/web_state/web_state_delegate_bridge_unittest.mm +++ b/ios/web/web_state/web_state_delegate_bridge_unittest.mm
@@ -110,11 +110,11 @@ TEST_F(WebStateDelegateBridgeTest, HandleContextMenu) { EXPECT_EQ(nil, [delegate_ contextMenuParams]); web::ContextMenuParams context_menu_params; - context_menu_params.menu_title.reset([@"Menu title" copy]); + context_menu_params.menu_title = [@"Menu title" copy]; context_menu_params.link_url = GURL("http://www.url.com"); context_menu_params.src_url = GURL("http://www.url.com/image.jpeg"); context_menu_params.referrer_policy = web::ReferrerPolicyOrigin; - context_menu_params.view.reset([[UIView alloc] init]); + context_menu_params.view = [[UIView alloc] init]; context_menu_params.location = CGPointMake(5.0, 5.0); bridge_->HandleContextMenu(nullptr, context_menu_params); web::ContextMenuParams* result_params = [delegate_ contextMenuParams];
diff --git a/ios/web/web_state/web_state_impl.h b/ios/web/web_state/web_state_impl.h index ee4e098e..25a5085 100644 --- a/ios/web/web_state/web_state_impl.h +++ b/ios/web/web_state/web_state_impl.h
@@ -324,7 +324,7 @@ bool is_being_destroyed_; // The CRWWebController that backs this object. - base::scoped_nsobject<CRWWebController> web_controller_; + CRWWebController* web_controller_; // The NavigationManagerImpl that stores session info for this WebStateImpl. std::unique_ptr<NavigationManagerImpl> navigation_manager_; @@ -373,7 +373,7 @@ // Cached session history when web usage is disabled. It is used to restore // history into WKWebView when web usage is re-enabled. - base::scoped_nsobject<CRWSessionStorage> cached_session_storage_; + CRWSessionStorage* cached_session_storage_; // Favicons URLs received in OnFaviconUrlUpdated. // WebStateObserver:FaviconUrlUpdated must be called for same-document
diff --git a/ios/web/web_state/web_state_impl.mm b/ios/web/web_state/web_state_impl.mm index 3e1a0f7..58d02ce8 100644 --- a/ios/web/web_state/web_state_impl.mm +++ b/ios/web/web_state/web_state_impl.mm
@@ -89,7 +89,7 @@ navigation_manager_->SetBrowserState(params.browser_state); // Send creation event and create the web controller. GlobalWebStateEventTracker::GetInstance()->OnWebStateCreated(this); - web_controller_.reset([[CRWWebController alloc] initWithWebState:this]); + web_controller_ = [[CRWWebController alloc] initWithWebState:this]; // Restore session history last because WKBasedNavigationManagerImpl relies on // CRWWebController to restore history into the web view. @@ -170,7 +170,7 @@ void WebStateImpl::SetWebController(CRWWebController* web_controller) { [web_controller_ close]; - web_controller_.reset(web_controller); + web_controller_ = web_controller; } void WebStateImpl::OnTitleChanged() { @@ -550,11 +550,11 @@ if (web::GetWebClient()->IsSlimNavigationManagerEnabled()) { if (enabled) { if (cached_session_storage_) { - RestoreSessionStorage(cached_session_storage_.get()); + RestoreSessionStorage(cached_session_storage_); } - cached_session_storage_.reset(); + cached_session_storage_ = nil; } else { - cached_session_storage_.reset(BuildSessionStorage()); + cached_session_storage_ = BuildSessionStorage(); } }
diff --git a/ios/web_view/internal/cwv_web_view.mm b/ios/web_view/internal/cwv_web_view.mm index 7d7b2c7..85ac1593 100644 --- a/ios/web_view/internal/cwv_web_view.mm +++ b/ios/web_view/internal/cwv_web_view.mm
@@ -183,8 +183,8 @@ web::NavigationManager::WebLoadParams params(net::GURLWithNSURL(request.URL)); params.transition_type = ui::PAGE_TRANSITION_TYPED; - params.extra_headers.reset([request.allHTTPHeaderFields copy]); - params.post_data.reset([request.HTTPBody copy]); + params.extra_headers = [request.allHTTPHeaderFields copy]; + params.post_data = [request.HTTPBody copy]; _webState->GetNavigationManager()->LoadURLWithParams(params); [self updateCurrentURLs]; }
diff --git a/media/cdm/ppapi/ppapi_cdm_adapter.gni b/media/cdm/ppapi/ppapi_cdm_adapter.gni index 002c9801..63e0ddec 100644 --- a/media/cdm/ppapi/ppapi_cdm_adapter.gni +++ b/media/cdm/ppapi/ppapi_cdm_adapter.gni
@@ -2,6 +2,8 @@ # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. +import("//build/config/compiler/compiler.gni") + # This template defines a CDM adapter target. Just use this as you would a # normal target and everything should work correctly. template("ppapi_cdm_adapter") { @@ -61,6 +63,11 @@ if (is_linux) { # CDM adapter depends on a CDM in component and non-component builds. configs += [ "//build/config/gcc:rpath_for_built_shared_libraries" ] + + if (use_lld) { + # TODO(crbug.com/795158) LLD warns about libwidevinecdm.so + configs -= [ "//build/config/compiler:default_fatal_linker_warnings" ] + } } # TODO(jschuh) crbug.com/167187
diff --git a/media/gpu/windows/d3d11_h264_accelerator.cc b/media/gpu/windows/d3d11_h264_accelerator.cc index 6211104..e0d97acf 100644 --- a/media/gpu/windows/d3d11_h264_accelerator.cc +++ b/media/gpu/windows/d3d11_h264_accelerator.cc
@@ -25,19 +25,22 @@ class D3D11H264Picture : public H264Picture { public: - D3D11H264Picture(D3D11PictureBuffer* picture, size_t input_buffer_id) - : picture(picture), - level_(picture->level()), - input_buffer_id_(input_buffer_id) {} + D3D11H264Picture(D3D11PictureBuffer* picture) + : picture(picture), level_(picture->level()) { + picture->set_in_picture_use(true); + } D3D11PictureBuffer* picture; size_t level_; - size_t input_buffer_id_; protected: ~D3D11H264Picture() override; }; +D3D11H264Picture::~D3D11H264Picture() { + picture->set_in_picture_use(false); +} + D3D11H264Accelerator::D3D11H264Accelerator( D3D11VideoDecoderClient* client, Microsoft::WRL::ComPtr<ID3D11VideoDecoder> video_decoder, @@ -55,9 +58,7 @@ if (!picture) { return nullptr; } - picture->set_in_picture_use(true); - return base::MakeRefCounted<D3D11H264Picture>(picture, - client_->input_buffer_id()); + return base::MakeRefCounted<D3D11H264Picture>(picture); } bool D3D11H264Accelerator::SubmitFrameMetadata( @@ -80,8 +81,10 @@ // Hardware is busy. We should make the call again. // TODO(liberato): For now, just busy wait. ; + } else if (!SUCCEEDED(hr)) { + LOG(ERROR) << "DecoderBeginFrame failed"; + return false; } else { - CHECK(SUCCEEDED(hr)); break; } } @@ -120,20 +123,27 @@ i++; } slice_info_.clear(); - RetrieveBitstreamBuffer(); - return true; + return RetrieveBitstreamBuffer(); } -void D3D11H264Accelerator::RetrieveBitstreamBuffer() { +bool D3D11H264Accelerator::RetrieveBitstreamBuffer() { + DCHECK(!bitstream_buffer_bytes_); + DCHECK(!bitstream_buffer_size_); + current_offset_ = 0; void* buffer; UINT buffer_size; HRESULT hr = video_context_->GetDecoderBuffer( video_decoder_.Get(), D3D11_VIDEO_DECODER_BUFFER_BITSTREAM, &buffer_size, &buffer); + if (!SUCCEEDED(hr)) { + LOG(ERROR) << "GetDecoderBuffer (Bitstream) failed"; + return false; + } bitstream_buffer_bytes_ = (uint8_t*)buffer; bitstream_buffer_size_ = buffer_size; - CHECK(SUCCEEDED(hr)); + + return true; } bool D3D11H264Accelerator::SubmitSlice(const H264PPS* pps, @@ -235,12 +245,18 @@ HRESULT hr = video_context_->GetDecoderBuffer( video_decoder_.Get(), D3D11_VIDEO_DECODER_BUFFER_PICTURE_PARAMETERS, &buffer_size, &buffer); - CHECK(SUCCEEDED(hr)); + if (!SUCCEEDED(hr)) { + LOG(ERROR) << "ReleaseDecoderBuffer (PictureParams) failed"; + return false; + } memcpy(buffer, &pic_param, sizeof(pic_param)); hr = video_context_->ReleaseDecoderBuffer( video_decoder_.Get(), D3D11_VIDEO_DECODER_BUFFER_PICTURE_PARAMETERS); - CHECK(SUCCEEDED(hr)); + if (!SUCCEEDED(hr)) { + LOG(ERROR) << "ReleaseDecoderBuffer (PictureParams) failed"; + return false; + } DXVA_Qmatrix_H264 iq_matrix_buf = {}; @@ -269,11 +285,18 @@ video_decoder_.Get(), D3D11_VIDEO_DECODER_BUFFER_INVERSE_QUANTIZATION_MATRIX, &buffer_size, &buffer); - CHECK(SUCCEEDED(hr)); + if (!SUCCEEDED(hr)) { + LOG(ERROR) << "GetDecoderBuffer (QuantMatrix) failed"; + return false; + } memcpy(buffer, &iq_matrix_buf, sizeof(iq_matrix_buf)); hr = video_context_->ReleaseDecoderBuffer( video_decoder_.Get(), D3D11_VIDEO_DECODER_BUFFER_INVERSE_QUANTIZATION_MATRIX); + if (!SUCCEEDED(hr)) { + LOG(ERROR) << "ReleaseDecoderBuffer (QuantMatrix) failed"; + return false; + } // Ideally all slices in a frame are put in the same bitstream buffer. // However the bitstream buffer may not fit all the data, so split on the @@ -287,8 +310,14 @@ while (remaining_bitstream > 0) { if (bitstream_buffer_size_ < remaining_bitstream && slice_info_.size() > 0) { - SubmitSliceData(); - RetrieveBitstreamBuffer(); + if (!SubmitSliceData()) { + LOG(ERROR) << "SubmitSliceData failed"; + return false; + } + if (!RetrieveBitstreamBuffer()) { + LOG(ERROR) << "RetrieveBitstreamBuffer failed"; + return false; + } } size_t bytes_to_copy = remaining_bitstream; @@ -331,21 +360,37 @@ return true; } -void D3D11H264Accelerator::SubmitSliceData() { +bool D3D11H264Accelerator::SubmitSliceData() { CHECK(slice_info_.size() > 0); UINT buffer_size; void* buffer; + + // TODO(liberato): Should we release the other buffers on failure? + HRESULT hr = video_context_->GetDecoderBuffer( video_decoder_.Get(), D3D11_VIDEO_DECODER_BUFFER_SLICE_CONTROL, &buffer_size, &buffer); - CHECK(SUCCEEDED(hr)); + if (!SUCCEEDED(hr)) { + LOG(ERROR) << "GetDecoderBuffer (SliceControl) failed"; + return false; + } + CHECK_LE(sizeof(slice_info_[0]) * slice_info_.size(), buffer_size); memcpy(buffer, &slice_info_[0], sizeof(slice_info_[0]) * slice_info_.size()); hr = video_context_->ReleaseDecoderBuffer( video_decoder_.Get(), D3D11_VIDEO_DECODER_BUFFER_SLICE_CONTROL); + if (!SUCCEEDED(hr)) { + LOG(ERROR) << "ReleaseDecoderBuffer (SliceControl) failed"; + return false; + } hr = video_context_->ReleaseDecoderBuffer( video_decoder_.Get(), D3D11_VIDEO_DECODER_BUFFER_BITSTREAM); + if (!SUCCEEDED(hr)) { + LOG(ERROR) << "ReleaseDecoderBuffer (BitStream) failed"; + return false; + } + D3D11_VIDEO_DECODER_BUFFER_DESC buffers[4] = {}; buffers[0].BufferType = D3D11_VIDEO_DECODER_BUFFER_PICTURE_PARAMETERS; buffers[0].DataOffset = 0; @@ -366,39 +411,48 @@ slice_info_.clear(); bitstream_buffer_bytes_ = nullptr; bitstream_buffer_size_ = 0; + if (!SUCCEEDED(hr)) { + LOG(ERROR) << "SubmitDecoderBuffers failed"; + return false; + } + + return true; } bool D3D11H264Accelerator::SubmitDecode(const scoped_refptr<H264Picture>& pic) { - SubmitSliceData(); + if (!SubmitSliceData()) { + LOG(ERROR) << "SubmitSliceData failed"; + return false; + } HRESULT hr = video_context_->DecoderEndFrame(video_decoder_.Get()); - CHECK(SUCCEEDED(hr)); + if (!SUCCEEDED(hr)) { + LOG(ERROR) << "DecoderEndFrame failed"; + return false; + } return true; } void D3D11H264Accelerator::Reset() { - if (bitstream_buffer_bytes_) { - HRESULT hr = video_context_->ReleaseDecoderBuffer( - video_decoder_.Get(), D3D11_VIDEO_DECODER_BUFFER_BITSTREAM); + if (!bitstream_buffer_bytes_) + return; - bitstream_buffer_bytes_ = nullptr; - bitstream_buffer_size_ = 0; - current_offset_ = 0; - CHECK(SUCCEEDED(hr)); - } + HRESULT hr = video_context_->ReleaseDecoderBuffer( + video_decoder_.Get(), D3D11_VIDEO_DECODER_BUFFER_BITSTREAM); + + bitstream_buffer_bytes_ = nullptr; + bitstream_buffer_size_ = 0; + current_offset_ = 0; + CHECK(SUCCEEDED(hr)); } bool D3D11H264Accelerator::OutputPicture( const scoped_refptr<H264Picture>& pic) { scoped_refptr<D3D11H264Picture> our_pic( static_cast<D3D11H264Picture*>(pic.get())); - client_->OutputResult(our_pic->picture, our_pic->input_buffer_id_); + client_->OutputResult(our_pic->picture); return true; } -D3D11H264Picture::~D3D11H264Picture() { - picture->set_in_picture_use(false); -} - } // namespace media
diff --git a/media/gpu/windows/d3d11_h264_accelerator.h b/media/gpu/windows/d3d11_h264_accelerator.h index b5e664d..173ff43 100644 --- a/media/gpu/windows/d3d11_h264_accelerator.h +++ b/media/gpu/windows/d3d11_h264_accelerator.h
@@ -28,10 +28,8 @@ class D3D11VideoDecoderClient { public: - virtual size_t input_buffer_id() const = 0; virtual D3D11PictureBuffer* GetPicture() = 0; - virtual void OutputResult(D3D11PictureBuffer* picture, - size_t input_buffer_id) = 0; + virtual void OutputResult(D3D11PictureBuffer* picture) = 0; }; class D3D11H264Accelerator : public H264Decoder::H264Accelerator { @@ -64,8 +62,8 @@ bool OutputPicture(const scoped_refptr<H264Picture>& pic) override; private: - void SubmitSliceData(); - void RetrieveBitstreamBuffer(); + bool SubmitSliceData(); + bool RetrieveBitstreamBuffer(); D3D11VideoDecoderClient* client_;
diff --git a/media/gpu/windows/d3d11_video_decoder.cc b/media/gpu/windows/d3d11_video_decoder.cc index 696dda0..5245254 100644 --- a/media/gpu/windows/d3d11_video_decoder.cc +++ b/media/gpu/windows/d3d11_video_decoder.cc
@@ -11,6 +11,7 @@ #include "media/base/video_codecs.h" #include "media/base/video_decoder_config.h" #include "media/base/video_frame.h" +#include "media/gpu/windows/d3d11_video_decoder_impl.h" namespace { @@ -46,17 +47,13 @@ D3D11VideoDecoder::D3D11VideoDecoder( scoped_refptr<base::SingleThreadTaskRunner> gpu_task_runner, - base::RepeatingCallback<gpu::CommandBufferStub*()> get_stub_cb, - deprecated::OutputWithReleaseMailboxCB output_cb) + base::RepeatingCallback<gpu::CommandBufferStub*()> get_stub_cb) : impl_task_runner_(std::move(gpu_task_runner)), weak_factory_(this) { // We create |impl_| on the wrong thread, but we never use it here. // Note that the output callback will hop to our thread, post the video // frame, and along with a callback that will hop back to the impl thread // when it's released. - impl_ = base::MakeUnique<D3D11VideoDecoderImpl>( - get_stub_cb, media::BindToCurrentLoop(base::Bind( - &D3D11VideoDecoder::OutputWithThreadHoppingRelease, - weak_factory_.GetWeakPtr(), std::move(output_cb)))); + impl_ = base::MakeUnique<D3D11VideoDecoderImpl>(get_stub_cb); impl_weak_ = impl_->GetWeakPtr(); } @@ -124,23 +121,4 @@ return impl_->GetMaxDecodeRequests(); } -void D3D11VideoDecoder::OutputWithThreadHoppingRelease( - deprecated::OutputWithReleaseMailboxCB output_cb, - deprecated::ReleaseMailboxCB impl_thread_cb, - const scoped_refptr<VideoFrame>& video_frame) { - // Called on our thread to output a video frame. Modify the release cb so - // that it jumps back to the impl thread. - output_cb.Run( - base::BindOnce(&D3D11VideoDecoder::OnMailboxReleased, - weak_factory_.GetWeakPtr(), std::move(impl_thread_cb)), - video_frame); -} - -void D3D11VideoDecoder::OnMailboxReleased( - deprecated::ReleaseMailboxCB impl_thread_cb, - const gpu::SyncToken& token) { - impl_task_runner_->PostTask(FROM_HERE, - base::BindOnce(std::move(impl_thread_cb), token)); -} - } // namespace media
diff --git a/media/gpu/windows/d3d11_video_decoder.h b/media/gpu/windows/d3d11_video_decoder.h index 6a68a09..1b6cbdb 100644 --- a/media/gpu/windows/d3d11_video_decoder.h +++ b/media/gpu/windows/d3d11_video_decoder.h
@@ -5,8 +5,6 @@ #ifndef MEDIA_GPU_D3D11_VIDEO_DECODER_H_ #define MEDIA_GPU_D3D11_VIDEO_DECODER_H_ -#include <d3d11.h> - #include <string> #include "base/memory/ptr_util.h" @@ -16,11 +14,11 @@ #include "gpu/ipc/service/command_buffer_stub.h" #include "media/base/video_decoder.h" #include "media/gpu/media_gpu_export.h" -#include "media/gpu/windows/d3d11_video_decoder_impl.h" -#include "media/gpu/windows/output_with_release_mailbox_cb.h" namespace media { +class D3D11VideoDecoderImpl; + // Thread-hopping implementation of D3D11VideoDecoder. It's meant to run on // a random thread, and hop to the gpu main thread. It does this so that it // can use the D3D context etc. What should really happen is that we should @@ -31,8 +29,7 @@ public: D3D11VideoDecoder( scoped_refptr<base::SingleThreadTaskRunner> gpu_task_runner, - base::RepeatingCallback<gpu::CommandBufferStub*()> get_stub_cb, - deprecated::OutputWithReleaseMailboxCB output_cb); + base::RepeatingCallback<gpu::CommandBufferStub*()> get_stub_cb); ~D3D11VideoDecoder() override; // VideoDecoder implementation: @@ -50,17 +47,6 @@ int GetMaxDecodeRequests() const override; private: - // Call |output_cb| with a release cb that will hop back to the impl thread - // to run |impl_thread_cb| when |video_frame| is released. - void OutputWithThreadHoppingRelease( - deprecated::OutputWithReleaseMailboxCB output_cb, - deprecated::ReleaseMailboxCB impl_thread_cb, - const scoped_refptr<VideoFrame>& video_frame); - - // ReleaseCB that's run on our thread, but posts it to the impl thread. - void OnMailboxReleased(deprecated::ReleaseMailboxCB impl_thread_cb, - const gpu::SyncToken& token); - // The implementation, which we trampoline to the impl thread. // This must be freed on the impl thread. std::unique_ptr<D3D11VideoDecoderImpl> impl_; @@ -71,8 +57,6 @@ // Task runner for |impl_|. This must be the GPU main thread. scoped_refptr<base::SequencedTaskRunner> impl_task_runner_; - deprecated::OutputWithReleaseMailboxCB output_cb_; - base::WeakPtrFactory<D3D11VideoDecoder> weak_factory_; DISALLOW_COPY_AND_ASSIGN(D3D11VideoDecoder);
diff --git a/media/gpu/windows/d3d11_video_decoder_impl.cc b/media/gpu/windows/d3d11_video_decoder_impl.cc index d06a4b7..7f027069 100644 --- a/media/gpu/windows/d3d11_video_decoder_impl.cc +++ b/media/gpu/windows/d3d11_video_decoder_impl.cc
@@ -9,6 +9,7 @@ #include "base/threading/sequenced_task_runner_handle.h" #include "gpu/command_buffer/service/mailbox_manager.h" #include "gpu/command_buffer/service/texture_manager.h" +#include "media/base/bind_to_current_loop.h" #include "media/base/decoder_buffer.h" #include "media/base/video_decoder_config.h" #include "media/base/video_frame.h" @@ -27,11 +28,8 @@ } // namespace D3D11VideoDecoderImpl::D3D11VideoDecoderImpl( - base::Callback<gpu::CommandBufferStub*()> get_stub_cb, - deprecated::OutputWithReleaseMailboxCB output_cb) - : get_stub_cb_(get_stub_cb), - output_cb_(std::move(output_cb)), - weak_factory_(this) {} + base::RepeatingCallback<gpu::CommandBufferStub*()> get_stub_cb) + : get_stub_cb_(get_stub_cb), weak_factory_(this) {} D3D11VideoDecoderImpl::~D3D11VideoDecoderImpl() { // TODO(liberato): be sure to clear |picture_buffers_| on the main thread. @@ -47,7 +45,7 @@ bool low_delay, CdmContext* cdm_context, const InitCB& init_cb, - const OutputCB& /* output_cb */) { + const OutputCB& output_cb) { stub_ = get_stub_cb_.Run(); if (!MakeContextCurrent(stub_)) { init_cb.Run(false); @@ -57,6 +55,8 @@ // stub_->AddDestructionObserver(this); decoder_helper_ = GLES2DecoderHelper::Create(stub_->decoder()); + output_cb_ = output_cb; + // The device is threadsafe. Does GetImmediateContext create a new object? // If so, then we can just use it on the MCVD thread. All we need to do is // to share the Texture object, somehow, which is likely trivial. We'd have @@ -361,14 +361,7 @@ return nullptr; } -size_t D3D11VideoDecoderImpl::input_buffer_id() const { - // NOTE: nobody uses this for anything. it just gets returned to us with - // OutputResult. It can be removed once we replace the VDA. - return 0; -} - -void D3D11VideoDecoderImpl::OutputResult(D3D11PictureBuffer* buffer, - size_t input_buffer_id) { +void D3D11VideoDecoderImpl::OutputResult(D3D11PictureBuffer* buffer) { buffer->set_in_client_use(true); // Note: The pixel format doesn't matter. @@ -380,12 +373,10 @@ VideoFrame::ReleaseMailboxCB(), buffer->picture_buffer().size(), visible_rect, natural_size, timestamp); - // TODO(liberato): The VideoFrame release callback will not be called after - // MojoVideoDecoderService is destructed. See VideoFrameFactoryImpl. - // NOTE: i think that we drop the picture buffers, which might work okay. - output_cb_.Run(base::Bind(&D3D11VideoDecoderImpl::OnMailboxReleased, - weak_factory_.GetWeakPtr(), buffer), - frame); + frame->SetReleaseMailboxCB(media::BindToCurrentLoop( + base::BindOnce(&D3D11VideoDecoderImpl::OnMailboxReleased, + weak_factory_.GetWeakPtr(), buffer))); + output_cb_.Run(frame); } void D3D11VideoDecoderImpl::OnMailboxReleased(
diff --git a/media/gpu/windows/d3d11_video_decoder_impl.h b/media/gpu/windows/d3d11_video_decoder_impl.h index ed47044..45fe5fe0 100644 --- a/media/gpu/windows/d3d11_video_decoder_impl.h +++ b/media/gpu/windows/d3d11_video_decoder_impl.h
@@ -27,8 +27,8 @@ class MEDIA_GPU_EXPORT D3D11VideoDecoderImpl : public VideoDecoder, public D3D11VideoDecoderClient { public: - D3D11VideoDecoderImpl(base::Callback<gpu::CommandBufferStub*()> get_stub_cb, - deprecated::OutputWithReleaseMailboxCB output_cb); + D3D11VideoDecoderImpl( + base::RepeatingCallback<gpu::CommandBufferStub*()> get_stub_cb); ~D3D11VideoDecoderImpl() override; // VideoDecoder implementation: @@ -47,9 +47,7 @@ // D3D11VideoDecoderClient implementation. D3D11PictureBuffer* GetPicture() override; - void OutputResult(D3D11PictureBuffer* buffer, - size_t input_buffer_id) override; - size_t input_buffer_id() const override; + void OutputResult(D3D11PictureBuffer* buffer) override; // Return a weak ptr, since D3D11VideoDecoder constructs callbacks for us. base::WeakPtr<D3D11VideoDecoderImpl> GetWeakPtr(); @@ -61,7 +59,7 @@ void OnMailboxReleased(D3D11PictureBuffer* buffer, const gpu::SyncToken& sync_token); - base::Callback<gpu::CommandBufferStub*()> get_stub_cb_; + base::RepeatingCallback<gpu::CommandBufferStub*()> get_stub_cb_; gpu::CommandBufferStub* stub_ = nullptr; // A helper for creating textures. Only valid while |stub_| is valid. std::unique_ptr<GLES2DecoderHelper> decoder_helper_; @@ -84,7 +82,7 @@ std::vector<std::unique_ptr<D3D11PictureBuffer>> picture_buffers_; - deprecated::OutputWithReleaseMailboxCB output_cb_; + VideoDecoder::OutputCB output_cb_; base::WeakPtrFactory<D3D11VideoDecoderImpl> weak_factory_;
diff --git a/media/mojo/services/gpu_mojo_media_client.cc b/media/mojo/services/gpu_mojo_media_client.cc index 224f3026..d41c1dc 100644 --- a/media/mojo/services/gpu_mojo_media_client.cc +++ b/media/mojo/services/gpu_mojo_media_client.cc
@@ -30,9 +30,10 @@ #include "services/service_manager/public/cpp/connect.h" #endif // defined(OS_ANDROID) -#if defined(OS_WIN) +// OS_WIN guards are needed for cross-compiling on linux. +#if defined(OS_WIN) && BUILDFLAG(ENABLE_D3D11_VIDEO_DECODER) #include "media/gpu/windows/d3d11_video_decoder.h" -#endif // defined(OS_WIN) +#endif // BUILDFLAG(ENABLE_D3D11_VIDEO_DECODER) #if BUILDFLAG(ENABLE_LIBRARY_CDMS) #include "media/cdm/cdm_proxy.h" @@ -64,7 +65,8 @@ } #endif // defined(OS_ANDROID) -#if defined(OS_ANDROID) || BUILDFLAG(ENABLE_D3D11_VIDEO_DECODER) +#if defined(OS_ANDROID) || \ + (defined(OS_WIN) && BUILDFLAG(ENABLE_D3D11_VIDEO_DECODER)) gpu::CommandBufferStub* GetCommandBufferStub( base::WeakPtr<MediaGpuChannelManager> media_gpu_channel_manager, base::UnguessableToken channel_token, @@ -123,7 +125,7 @@ android_overlay_factory_cb_, std::move(request_overlay_info_cb), base::MakeUnique<VideoFrameFactoryImpl>(gpu_task_runner_, std::move(get_stub_cb))); -#elif BUILDFLAG(ENABLE_D3D11_VIDEO_DECODER) +#elif defined(OS_WIN) && BUILDFLAG(ENABLE_D3D11_VIDEO_DECODER) return base::MakeUnique<D3D11VideoDecoder>( gpu_task_runner_, base::BindRepeating(&GetCommandBufferStub, media_gpu_channel_manager_,
diff --git a/mojo/public/cpp/system/file_data_pipe_producer.cc b/mojo/public/cpp/system/file_data_pipe_producer.cc index 7dfdf256..020b3db4 100644 --- a/mojo/public/cpp/system/file_data_pipe_producer.cc +++ b/mojo/public/cpp/system/file_data_pipe_producer.cc
@@ -7,6 +7,7 @@ #include <algorithm> #include <limits> #include <memory> +#include <utility> #include "base/bind.h" #include "base/callback.h" @@ -60,12 +61,14 @@ ScopedDataPipeProducerHandle producer_handle, scoped_refptr<base::SequencedTaskRunner> file_task_runner, CompletionCallback callback, - scoped_refptr<base::SequencedTaskRunner> callback_task_runner) + scoped_refptr<base::SequencedTaskRunner> callback_task_runner, + std::unique_ptr<Observer> observer) : base::RefCountedDeleteOnSequence<FileSequenceState>(file_task_runner), file_task_runner_(std::move(file_task_runner)), callback_task_runner_(std::move(callback_task_runner)), producer_handle_(std::move(producer_handle)), - callback_(std::move(callback)) {} + callback_(std::move(callback)), + observer_(std::move(observer)) {} void Cancel() { base::AutoLock lock(lock_); @@ -165,8 +168,14 @@ if (read_size < 0) { read_error = base::File::GetLastFileError(); DCHECK_NE(base::File::FILE_OK, read_error); + if (observer_) + observer_->OnBytesRead(pipe_buffer, 0u, read_error); } else { read_error = base::File::FILE_OK; + if (observer_) { + observer_->OnBytesRead(pipe_buffer, static_cast<size_t>(read_size), + base::File::FILE_OK); + } } producer_handle_->EndWriteData( read_size >= 0 ? static_cast<uint32_t>(read_size) : 0); @@ -195,6 +204,10 @@ } void Finish(MojoResult result) { + if (observer_) { + observer_->OnDoneReading(); + observer_ = nullptr; + } watcher_.reset(); callback_task_runner_->PostTask( FROM_HERE, base::BindOnce(std::move(callback_), @@ -215,13 +228,17 @@ // Guards |is_cancelled_|. base::Lock lock_; bool is_cancelled_ = false; + std::unique_ptr<Observer> observer_; DISALLOW_COPY_AND_ASSIGN(FileSequenceState); }; FileDataPipeProducer::FileDataPipeProducer( - ScopedDataPipeProducerHandle producer) - : producer_(std::move(producer)), weak_factory_(this) {} + ScopedDataPipeProducerHandle producer, + std::unique_ptr<Observer> observer) + : producer_(std::move(producer)), + observer_(std::move(observer)), + weak_factory_(this) {} FileDataPipeProducer::~FileDataPipeProducer() { if (file_sequence_state_) @@ -255,7 +272,7 @@ std::move(producer_), file_task_runner, base::BindOnce(&FileDataPipeProducer::OnWriteComplete, weak_factory_.GetWeakPtr(), std::move(callback)), - base::SequencedTaskRunnerHandle::Get()); + base::SequencedTaskRunnerHandle::Get(), std::move(observer_)); } void FileDataPipeProducer::OnWriteComplete(
diff --git a/mojo/public/cpp/system/file_data_pipe_producer.h b/mojo/public/cpp/system/file_data_pipe_producer.h index a8e4393..c3479f7 100644 --- a/mojo/public/cpp/system/file_data_pipe_producer.h +++ b/mojo/public/cpp/system/file_data_pipe_producer.h
@@ -5,6 +5,8 @@ #ifndef MOJO_PUBLIC_CPP_SYSTEM_FILE_DATA_PIPE_PRODUCER_H_ #define MOJO_PUBLIC_CPP_SYSTEM_FILE_DATA_PIPE_PRODUCER_H_ +#include <memory> + #include "base/callback_forward.h" #include "base/files/file.h" #include "base/files/file_path.h" @@ -29,8 +31,32 @@ public: using CompletionCallback = base::OnceCallback<void(MojoResult result)>; + // Interface definition of an optional object that may be supplied to the + // FileDataPipeProducer so that the data being read from the consumer can be + // observed. + class Observer { + public: + virtual ~Observer() {} + + // Called once per read attempt. |data| contains the read data (if any). + // |num_bytes_read| is the number of read bytes, 0 indicates EOF. Both + // parameters may only be used when |read_result| is base::File::FILE_OK. + // Can be called on any sequence. + virtual void OnBytesRead(const void* data, + size_t num_bytes_read, + base::File::Error read_result) = 0; + + // Called when the FileDataPipeProducer has finished reading all data. Will + // be called even if there was an error opening the file or reading the + // data. Can be called on any sequence. + virtual void OnDoneReading() = 0; + }; + // Constructs a new FileDataPipeProducer which will write data to |producer|. - explicit FileDataPipeProducer(ScopedDataPipeProducerHandle producer); + // Caller may supply an optional |observer| if observation of the read file + // data is desired. + FileDataPipeProducer(ScopedDataPipeProducerHandle producer, + std::unique_ptr<Observer> observer); ~FileDataPipeProducer(); // Attempts to eventually write all of |file|'s contents to the pipe. Invokes @@ -77,6 +103,7 @@ ScopedDataPipeProducerHandle producer_; scoped_refptr<FileSequenceState> file_sequence_state_; + std::unique_ptr<Observer> observer_; base::WeakPtrFactory<FileDataPipeProducer> weak_factory_; DISALLOW_COPY_AND_ASSIGN(FileDataPipeProducer);
diff --git a/mojo/public/cpp/system/tests/file_data_pipe_producer_unittest.cc b/mojo/public/cpp/system/tests/file_data_pipe_producer_unittest.cc index 0361542a..bd96c3f 100644 --- a/mojo/public/cpp/system/tests/file_data_pipe_producer_unittest.cc +++ b/mojo/public/cpp/system/tests/file_data_pipe_producer_unittest.cc
@@ -138,6 +138,40 @@ DISALLOW_COPY_AND_ASSIGN(FileDataPipeProducerTest); }; +struct DataPipeObserverData { + int num_read_errors = 0; + size_t bytes_read = 0; + int done_called = 0; +}; + +class TestObserver : public FileDataPipeProducer::Observer { + public: + explicit TestObserver(DataPipeObserverData* observer_data) + : observer_data_(observer_data) {} + + void OnBytesRead(const void* data, + size_t num_bytes_read, + base::File::Error read_result) override { + base::AutoLock auto_lock(lock_); + if (read_result == base::File::FILE_OK) + observer_data_->bytes_read += num_bytes_read; + else + observer_data_->num_read_errors++; + } + + void OnDoneReading() override { + base::AutoLock auto_lock(lock_); + observer_data_->done_called++; + } + + private: + DataPipeObserverData* observer_data_; + // Observer may be called on any sequence. + base::Lock lock_; + + DISALLOW_COPY_AND_ASSIGN(TestObserver); +}; + TEST_F(FileDataPipeProducerTest, WriteFromFile) { const std::string kTestStringFragment = "Hello, world!"; constexpr size_t kNumRepetitions = 1000; @@ -153,12 +187,18 @@ loop.QuitClosure()); base::File file(path, base::File::FLAG_OPEN | base::File::FLAG_READ); + DataPipeObserverData observer_data; + auto observer = std::make_unique<TestObserver>(&observer_data); WriteFromFileThenCloseWriter( - std::make_unique<FileDataPipeProducer>(std::move(pipe.producer_handle)), + std::make_unique<FileDataPipeProducer>(std::move(pipe.producer_handle), + std::move(observer)), std::move(file)); loop.Run(); EXPECT_EQ(test_string, reader.data()); + EXPECT_EQ(0, observer_data.num_read_errors); + EXPECT_EQ(test_string.size(), observer_data.bytes_read); + EXPECT_EQ(1, observer_data.done_called); } TEST_F(FileDataPipeProducerTest, WriteFromFilePartial) { @@ -172,12 +212,18 @@ loop.QuitClosure()); base::File file(path, base::File::FLAG_OPEN | base::File::FLAG_READ); + DataPipeObserverData observer_data; + auto observer = std::make_unique<TestObserver>(&observer_data); WriteFromFileThenCloseWriter( - std::make_unique<FileDataPipeProducer>(std::move(pipe.producer_handle)), + std::make_unique<FileDataPipeProducer>(std::move(pipe.producer_handle), + std::move(observer)), std::move(file), kBytesToWrite); loop.Run(); EXPECT_EQ(kTestString.substr(0, kBytesToWrite), reader.data()); + EXPECT_EQ(0, observer_data.num_read_errors); + EXPECT_EQ(kBytesToWrite, observer_data.bytes_read); + EXPECT_EQ(1, observer_data.done_called); } TEST_F(FileDataPipeProducerTest, WriteFromInvalidFile) { @@ -186,16 +232,22 @@ base::RunLoop loop; DataPipe pipe(kBytesToWrite); + DataPipeObserverData observer_data; + auto observer = std::make_unique<TestObserver>(&observer_data); DataPipeReader reader(std::move(pipe.consumer_handle), kBytesToWrite, loop.QuitClosure()); base::File file(path, base::File::FLAG_OPEN | base::File::FLAG_READ); WriteFromFileThenCloseWriter( - std::make_unique<FileDataPipeProducer>(std::move(pipe.producer_handle)), + std::make_unique<FileDataPipeProducer>(std::move(pipe.producer_handle), + std::move(observer)), std::move(file), kBytesToWrite); loop.Run(); EXPECT_EQ(0UL, reader.data().size()); + EXPECT_EQ(0, observer_data.num_read_errors); + EXPECT_EQ(0UL, observer_data.bytes_read); + EXPECT_EQ(1, observer_data.done_called); } TEST_F(FileDataPipeProducerTest, WriteFromPath) { @@ -212,12 +264,18 @@ DataPipeReader reader(std::move(pipe.consumer_handle), 16, loop.QuitClosure()); + DataPipeObserverData observer_data; + auto observer = std::make_unique<TestObserver>(&observer_data); WriteFromPathThenCloseWriter( - std::make_unique<FileDataPipeProducer>(std::move(pipe.producer_handle)), + std::make_unique<FileDataPipeProducer>(std::move(pipe.producer_handle), + std::move(observer)), path); loop.Run(); EXPECT_EQ(test_string, reader.data()); + EXPECT_EQ(0, observer_data.num_read_errors); + EXPECT_EQ(test_string.size(), observer_data.bytes_read); + EXPECT_EQ(1, observer_data.done_called); } TEST_F(FileDataPipeProducerTest, TinyFile) { @@ -227,12 +285,18 @@ DataPipe pipe(16); DataPipeReader reader(std::move(pipe.consumer_handle), 16, loop.QuitClosure()); + DataPipeObserverData observer_data; + auto observer = std::make_unique<TestObserver>(&observer_data); WriteFromPathThenCloseWriter( - std::make_unique<FileDataPipeProducer>(std::move(pipe.producer_handle)), + std::make_unique<FileDataPipeProducer>(std::move(pipe.producer_handle), + std::move(observer)), path); loop.Run(); EXPECT_EQ(kTestString, reader.data()); + EXPECT_EQ(0, observer_data.num_read_errors); + EXPECT_EQ(kTestString.size(), observer_data.bytes_read); + EXPECT_EQ(1, observer_data.done_called); } TEST_F(FileDataPipeProducerTest, HugeFile) { @@ -254,12 +318,18 @@ DataPipeReader reader(std::move(pipe.consumer_handle), kDataPipeSize, loop.QuitClosure()); + DataPipeObserverData observer_data; + auto observer = std::make_unique<TestObserver>(&observer_data); WriteFromPathThenCloseWriter( - std::make_unique<FileDataPipeProducer>(std::move(pipe.producer_handle)), + std::make_unique<FileDataPipeProducer>(std::move(pipe.producer_handle), + std::move(observer)), path); loop.Run(); EXPECT_EQ(test_string, reader.data()); + EXPECT_EQ(0, observer_data.num_read_errors); + EXPECT_EQ(kHugeFileSize, observer_data.bytes_read); + EXPECT_EQ(1, observer_data.done_called); } } // namespace
diff --git a/net/base/hex_utils.cc b/net/base/hex_utils.cc index 62cdb637..f6efcbe 100644 --- a/net/base/hex_utils.cc +++ b/net/base/hex_utils.cc
@@ -16,7 +16,7 @@ std::string HexDecode(base::StringPiece input) { std::vector<uint8_t> output; std::string result; - if (base::HexStringToBytes(input.as_string(), &output)) + if (base::HexStringToBytes(input, &output)) result.assign(reinterpret_cast<const char*>(&output[0]), output.size()); return result; }
diff --git a/net/base/net_error_list.h b/net/base/net_error_list.h index 8b7e5b4b..38c6ea2a3 100644 --- a/net/base/net_error_list.h +++ b/net/base/net_error_list.h
@@ -729,6 +729,9 @@ // SpdyStream layer. NET_ERROR(SPDY_RST_STREAM_NO_ERROR_RECEIVED, -372) +// The pushed stream claimed by the request is no longer available. +NET_ERROR(SPDY_PUSHED_STREAM_NOT_AVAILABLE, -373) + // The cache does not have the requested entry. NET_ERROR(CACHE_MISS, -400)
diff --git a/net/base/proxy_delegate.h b/net/base/proxy_delegate.h index 8767728..356717b3 100644 --- a/net/base/proxy_delegate.h +++ b/net/base/proxy_delegate.h
@@ -15,12 +15,8 @@ namespace net { -class HttpRequestHeaders; -class HttpResponseHeaders; -class HostPortPair; class ProxyInfo; class ProxyServer; -class ProxyService; // Delegate for setting up a connection. class NET_EXPORT ProxyDelegate { @@ -48,25 +44,9 @@ virtual void OnFallback(const ProxyServer& bad_proxy, int net_error) = 0; - // Called immediately before a proxy tunnel request is sent. - // Provides the embedder an opportunity to add extra request headers. - virtual void OnBeforeTunnelRequest(const HostPortPair& proxy_server, - HttpRequestHeaders* extra_headers) = 0; - - // Called when the connect attempt to a CONNECT proxy has completed. - virtual void OnTunnelConnectCompleted(const HostPortPair& endpoint, - const HostPortPair& proxy_server, - int net_error) = 0; - - // Called after the response headers for the tunnel request are received. - virtual void OnTunnelHeadersReceived( - const HostPortPair& origin, - const HostPortPair& proxy_server, - const HttpResponseHeaders& response_headers) = 0; - // Returns true if |proxy_server| is a trusted SPDY/HTTP2 proxy that is // allowed to push cross-origin resources. - virtual bool IsTrustedSpdyProxy(const net::ProxyServer& proxy_server) = 0; + virtual bool IsTrustedSpdyProxy(const ProxyServer& proxy_server) = 0; // Notifies the ProxyDelegate that |alternative_proxy_server| is broken. virtual void OnAlternativeProxyBroken(
diff --git a/net/base/test_proxy_delegate.cc b/net/base/test_proxy_delegate.cc index cb69981..66e98cb 100644 --- a/net/base/test_proxy_delegate.cc +++ b/net/base/test_proxy_delegate.cc
@@ -4,8 +4,6 @@ #include "net/base/test_proxy_delegate.h" -#include "net/http/http_request_headers.h" -#include "net/http/http_response_headers.h" #include "net/proxy/proxy_info.h" #include "testing/gtest/include/gtest/gtest.h" @@ -15,28 +13,6 @@ TestProxyDelegate::~TestProxyDelegate() = default; -void TestProxyDelegate::VerifyOnTunnelRequestCompleted( - const std::string& endpoint, - const std::string& proxy_server) const { - EXPECT_TRUE(on_tunnel_request_completed_called_); - EXPECT_TRUE(HostPortPair::FromString(endpoint).Equals( - on_tunnel_request_completed_endpoint_)); - EXPECT_TRUE(HostPortPair::FromString(proxy_server) - .Equals(on_tunnel_request_completed_proxy_server_)); -} - -void TestProxyDelegate::VerifyOnTunnelHeadersReceived( - const std::string& origin, - const std::string& proxy_server, - const std::string& status_line) const { - EXPECT_TRUE(on_tunnel_headers_received_called_); - EXPECT_TRUE(HostPortPair::FromString(origin).Equals( - on_tunnel_headers_received_origin_)); - EXPECT_TRUE(HostPortPair::FromString(proxy_server) - .Equals(on_tunnel_headers_received_proxy_server_)); - EXPECT_EQ(status_line, on_tunnel_headers_received_status_line_); -} - void TestProxyDelegate::OnResolveProxy( const GURL& url, const std::string& method, @@ -45,38 +21,10 @@ result->SetAlternativeProxy(alternative_proxy_server_); } -void TestProxyDelegate::OnTunnelConnectCompleted( - const HostPortPair& endpoint, - const HostPortPair& proxy_server, - int net_error) { - on_tunnel_request_completed_called_ = true; - on_tunnel_request_completed_endpoint_ = endpoint; - on_tunnel_request_completed_proxy_server_ = proxy_server; -} - void TestProxyDelegate::OnFallback(const ProxyServer& bad_proxy, int net_error) {} -void TestProxyDelegate::OnBeforeTunnelRequest( - const HostPortPair& proxy_server, - HttpRequestHeaders* extra_headers) { - on_before_tunnel_request_called_ = true; - if (extra_headers) - extra_headers->SetHeader("Foo", proxy_server.ToString()); -} - -void TestProxyDelegate::OnTunnelHeadersReceived( - const HostPortPair& origin, - const HostPortPair& proxy_server, - const HttpResponseHeaders& response_headers) { - on_tunnel_headers_received_called_ = true; - on_tunnel_headers_received_origin_ = origin; - on_tunnel_headers_received_proxy_server_ = proxy_server; - on_tunnel_headers_received_status_line_ = response_headers.GetStatusLine(); -} - -bool TestProxyDelegate::IsTrustedSpdyProxy( - const net::ProxyServer& proxy_server) { +bool TestProxyDelegate::IsTrustedSpdyProxy(const ProxyServer& proxy_server) { return proxy_server.is_valid() && trusted_spdy_proxy_ == proxy_server; }
diff --git a/net/base/test_proxy_delegate.h b/net/base/test_proxy_delegate.h index 3056e923..073e4da 100644 --- a/net/base/test_proxy_delegate.h +++ b/net/base/test_proxy_delegate.h
@@ -7,7 +7,6 @@ #include <string> -#include "net/base/host_port_pair.h" #include "net/base/proxy_delegate.h" #include "net/proxy/proxy_server.h" @@ -15,8 +14,6 @@ namespace net { -class HttpRequestHeaders; -class HttpResponseHeaders; class ProxyInfo; class TestProxyDelegate : public ProxyDelegate { @@ -24,45 +21,17 @@ TestProxyDelegate(); ~TestProxyDelegate() override; - bool on_before_tunnel_request_called() const { - return on_before_tunnel_request_called_; - } - - bool on_tunnel_request_completed_called() const { - return on_tunnel_request_completed_called_; - } - - bool on_tunnel_headers_received_called() const { - return on_tunnel_headers_received_called_; - } - - void set_trusted_spdy_proxy(const net::ProxyServer& proxy_server) { + void set_trusted_spdy_proxy(const ProxyServer& proxy_server) { trusted_spdy_proxy_ = proxy_server; } - void VerifyOnTunnelRequestCompleted(const std::string& endpoint, - const std::string& proxy_server) const; - - void VerifyOnTunnelHeadersReceived(const std::string& origin, - const std::string& proxy_server, - const std::string& status_line) const; - // ProxyDelegate implementation: void OnResolveProxy(const GURL& url, const std::string& method, const ProxyRetryInfoMap& proxy_retry_info, ProxyInfo* result) override; - void OnTunnelConnectCompleted(const HostPortPair& endpoint, - const HostPortPair& proxy_server, - int net_error) override; void OnFallback(const ProxyServer& bad_proxy, int net_error) override; - void OnBeforeTunnelRequest(const HostPortPair& proxy_server, - HttpRequestHeaders* extra_headers) override; - void OnTunnelHeadersReceived( - const HostPortPair& origin, - const HostPortPair& proxy_server, - const HttpResponseHeaders& response_headers) override; - bool IsTrustedSpdyProxy(const net::ProxyServer& proxy_server) override; + bool IsTrustedSpdyProxy(const ProxyServer& proxy_server) override; void OnAlternativeProxyBroken( const ProxyServer& alternative_proxy_server) override; @@ -75,15 +44,7 @@ } private: - bool on_before_tunnel_request_called_ = false; - bool on_tunnel_request_completed_called_ = false; - bool on_tunnel_headers_received_called_ = false; - net::ProxyServer trusted_spdy_proxy_; - HostPortPair on_tunnel_request_completed_endpoint_; - HostPortPair on_tunnel_request_completed_proxy_server_; - HostPortPair on_tunnel_headers_received_origin_; - HostPortPair on_tunnel_headers_received_proxy_server_; - std::string on_tunnel_headers_received_status_line_; + ProxyServer trusted_spdy_proxy_; ProxyServer alternative_proxy_server_; };
diff --git a/net/dns/dns_config_service.h b/net/dns/dns_config_service.h index 603fb4cc..6ccd52f3 100644 --- a/net/dns/dns_config_service.h +++ b/net/dns/dns_config_service.h
@@ -34,7 +34,7 @@ struct NET_EXPORT_PRIVATE DnsConfig { DnsConfig(); DnsConfig(const DnsConfig& other); - virtual ~DnsConfig(); + ~DnsConfig(); bool Equals(const DnsConfig& d) const;
diff --git a/net/http/http_proxy_client_socket.cc b/net/http/http_proxy_client_socket.cc index aef9b55..ea58dc82 100644 --- a/net/http/http_proxy_client_socket.cc +++ b/net/http/http_proxy_client_socket.cc
@@ -11,7 +11,6 @@ #include "net/base/auth.h" #include "net/base/host_port_pair.h" #include "net/base/io_buffer.h" -#include "net/base/proxy_delegate.h" #include "net/http/http_basic_stream.h" #include "net/http/http_network_session.h" #include "net/http/http_request_info.h" @@ -30,12 +29,10 @@ std::unique_ptr<ClientSocketHandle> transport_socket, const std::string& user_agent, const HostPortPair& endpoint, - const HostPortPair& proxy_server, HttpAuthController* http_auth_controller, bool tunnel, bool using_spdy, NextProto negotiated_protocol, - ProxyDelegate* proxy_delegate, bool is_https_proxy) : io_callback_(base::Bind(&HttpProxyClientSocket::OnIOComplete, base::Unretained(this))), @@ -48,8 +45,6 @@ negotiated_protocol_(negotiated_protocol), is_https_proxy_(is_https_proxy), redirect_has_load_timing_info_(false), - proxy_server_(proxy_server), - proxy_delegate_(proxy_delegate), net_log_(transport_->socket()->NetLog()) { // Synthesize the bits of a request that we actually use. request_.url = GURL("https://" + endpoint.ToString()); @@ -405,10 +400,6 @@ HttpRequestHeaders authorization_headers; if (auth_->HaveAuth()) auth_->AddAuthorizationHeader(&authorization_headers); - if (proxy_delegate_) { - proxy_delegate_->OnBeforeTunnelRequest(proxy_server_, - &authorization_headers); - } std::string user_agent; if (!request_.extra_headers.GetHeader(HttpRequestHeaders::kUserAgent, &user_agent)) { @@ -455,13 +446,6 @@ NetLogEventType::HTTP_TRANSACTION_READ_TUNNEL_RESPONSE_HEADERS, base::Bind(&HttpResponseHeaders::NetLogCallback, response_.headers)); - if (proxy_delegate_) { - proxy_delegate_->OnTunnelHeadersReceived( - HostPortPair::FromURL(request_.url), - proxy_server_, - *response_.headers); - } - switch (response_.headers->response_code()) { case 200: // OK if (http_stream_parser_->IsMoreDataBuffered())
diff --git a/net/http/http_proxy_client_socket.h b/net/http/http_proxy_client_socket.h index 184773933..8444be2 100644 --- a/net/http/http_proxy_client_socket.h +++ b/net/http/http_proxy_client_socket.h
@@ -32,7 +32,6 @@ class HttpStream; class HttpStreamParser; class IOBuffer; -class ProxyDelegate; class NET_EXPORT_PRIVATE HttpProxyClientSocket : public ProxyClientSocket { public: @@ -42,12 +41,10 @@ HttpProxyClientSocket(std::unique_ptr<ClientSocketHandle> transport_socket, const std::string& user_agent, const HostPortPair& endpoint, - const HostPortPair& proxy_server, HttpAuthController* http_auth_controller, bool tunnel, bool using_spdy, NextProto negotiated_protocol, - ProxyDelegate* proxy_delegate, bool is_https_proxy); // On destruction Disconnect() is called. @@ -164,11 +161,6 @@ bool redirect_has_load_timing_info_; LoadTimingInfo redirect_load_timing_info_; - const HostPortPair proxy_server_; - - // This delegate must outlive this proxy client socket. - ProxyDelegate* proxy_delegate_; - const NetLogWithSource net_log_; DISALLOW_COPY_AND_ASSIGN(HttpProxyClientSocket);
diff --git a/net/http/http_proxy_client_socket_fuzzer.cc b/net/http/http_proxy_client_socket_fuzzer.cc index c5b7879..ac9702a 100644 --- a/net/http/http_proxy_client_socket_fuzzer.cc +++ b/net/http/http_proxy_client_socket_fuzzer.cc
@@ -65,9 +65,8 @@ bool is_https_proxy = data_provider.ConsumeBool(); net::HttpProxyClientSocket socket( std::move(socket_handle), "Bond/007", net::HostPortPair("foo", 80), - net::HostPortPair("proxy", 42), auth_controller.get(), true /* tunnel */, - false /* using_spdy */, net::kProtoUnknown, nullptr /* proxy_delegate */, - is_https_proxy); + auth_controller.get(), true /* tunnel */, false /* using_spdy */, + net::kProtoUnknown, is_https_proxy); int result = socket.Connect(callback.callback()); result = callback.GetResult(result);
diff --git a/net/http/http_proxy_client_socket_pool.cc b/net/http/http_proxy_client_socket_pool.cc index ab7bbb3..b7769a4 100644 --- a/net/http/http_proxy_client_socket_pool.cc +++ b/net/http/http_proxy_client_socket_pool.cc
@@ -18,7 +18,6 @@ #include "base/values.h" #include "net/base/load_flags.h" #include "net/base/net_errors.h" -#include "net/base/proxy_delegate.h" #include "net/http/http_network_session.h" #include "net/http/http_proxy_client_socket_wrapper.h" #include "net/log/net_log_source_type.h" @@ -85,8 +84,7 @@ HttpAuthHandlerFactory* http_auth_handler_factory, SpdySessionPool* spdy_session_pool, QuicStreamFactory* quic_stream_factory, - bool tunnel, - ProxyDelegate* proxy_delegate) + bool tunnel) : transport_params_(transport_params), ssl_params_(ssl_params), quic_version_(quic_version), @@ -96,8 +94,7 @@ endpoint_(endpoint), http_auth_cache_(tunnel ? http_auth_cache : NULL), http_auth_handler_factory_(tunnel ? http_auth_handler_factory : NULL), - tunnel_(tunnel), - proxy_delegate_(proxy_delegate) { + tunnel_(tunnel) { // If doing a QUIC proxy, |quic_version| must not be QUIC_VERSION_UNSUPPORTED, // and |ssl_params| must be valid while |transport_params| is null. // Otherwise, |quic_version| must be QUIC_VERSION_UNSUPPORTED, and exactly @@ -153,7 +150,6 @@ params->spdy_session_pool(), params->quic_stream_factory(), params->tunnel(), - params->proxy_delegate(), this->net_log())) {} HttpProxyConnectJob::~HttpProxyConnectJob() = default;
diff --git a/net/http/http_proxy_client_socket_pool.h b/net/http/http_proxy_client_socket_pool.h index 0df5e47f3..c41198b 100644 --- a/net/http/http_proxy_client_socket_pool.h +++ b/net/http/http_proxy_client_socket_pool.h
@@ -31,7 +31,6 @@ class HttpProxyClientSocketWrapper; class NetLog; class NetworkQualityProvider; -class ProxyDelegate; class QuicStreamFactory; class SSLClientSocketPool; class SSLSocketParams; @@ -57,8 +56,7 @@ HttpAuthHandlerFactory* http_auth_handler_factory, SpdySessionPool* spdy_session_pool, QuicStreamFactory* quic_stream_factory, - bool tunnel, - ProxyDelegate* proxy_delegate); + bool tunnel); const scoped_refptr<TransportSocketParams>& transport_params() const { return transport_params_; @@ -82,10 +80,6 @@ const HostResolver::RequestInfo& destination() const; bool tunnel() const { return tunnel_; } - ProxyDelegate* proxy_delegate() const { - return proxy_delegate_; - } - private: friend class base::RefCounted<HttpProxySocketParams>; ~HttpProxySocketParams(); @@ -100,7 +94,6 @@ HttpAuthCache* const http_auth_cache_; HttpAuthHandlerFactory* const http_auth_handler_factory_; const bool tunnel_; - ProxyDelegate* proxy_delegate_; DISALLOW_COPY_AND_ASSIGN(HttpProxySocketParams); };
diff --git a/net/http/http_proxy_client_socket_pool_unittest.cc b/net/http/http_proxy_client_socket_pool_unittest.cc index 2cf01c15..bf74077d 100644 --- a/net/http/http_proxy_client_socket_pool_unittest.cc +++ b/net/http/http_proxy_client_socket_pool_unittest.cc
@@ -18,9 +18,7 @@ #include "base/strings/utf_string_conversions.h" #include "base/test/histogram_tester.h" #include "net/base/net_errors.h" -#include "net/base/proxy_delegate.h" #include "net/base/test_completion_callback.h" -#include "net/base/test_proxy_delegate.h" #include "net/http/http_network_session.h" #include "net/http/http_proxy_client_socket.h" #include "net/http/http_response_headers.h" @@ -169,26 +167,21 @@ // Returns the a correctly constructed HttpProxyParms // for the HTTP or HTTPS proxy. - scoped_refptr<HttpProxySocketParams> CreateParams( - bool tunnel, - ProxyDelegate* proxy_delegate) { - return scoped_refptr<HttpProxySocketParams>(new HttpProxySocketParams( + scoped_refptr<HttpProxySocketParams> CreateParams(bool tunnel) { + return base::MakeRefCounted<HttpProxySocketParams>( CreateHttpProxyParams(), CreateHttpsProxyParams(), QUIC_VERSION_UNSUPPORTED, std::string(), HostPortPair("www.google.com", tunnel ? 443 : 80), session_->http_auth_cache(), session_->http_auth_handler_factory(), - session_->spdy_session_pool(), session_->quic_stream_factory(), tunnel, - proxy_delegate)); + session_->spdy_session_pool(), session_->quic_stream_factory(), tunnel); } - scoped_refptr<HttpProxySocketParams> CreateTunnelParams( - ProxyDelegate* proxy_delegate) { - return CreateParams(true, proxy_delegate); + scoped_refptr<HttpProxySocketParams> CreateTunnelParams() { + return CreateParams(true); } - scoped_refptr<HttpProxySocketParams> CreateNoTunnelParams( - ProxyDelegate* proxy_delegate) { - return CreateParams(false, proxy_delegate); + scoped_refptr<HttpProxySocketParams> CreateNoTunnelParams() { + return CreateParams(false); } MockClientSocketFactory* socket_factory() { @@ -268,17 +261,13 @@ TEST_P(HttpProxyClientSocketPoolTest, NoTunnel) { Initialize(NULL, 0, NULL, 0, NULL, 0, NULL, 0); - std::unique_ptr<TestProxyDelegate> proxy_delegate(new TestProxyDelegate()); - int rv = handle_.Init("a", CreateNoTunnelParams(proxy_delegate.get()), LOW, + int rv = handle_.Init("a", CreateNoTunnelParams(), LOW, ClientSocketPool::RespectLimits::ENABLED, CompletionCallback(), pool_.get(), NetLogWithSource()); EXPECT_THAT(rv, IsOk()); EXPECT_TRUE(handle_.is_initialized()); ASSERT_TRUE(handle_.socket()); EXPECT_TRUE(handle_.socket()->IsConnected()); - EXPECT_FALSE(proxy_delegate->on_before_tunnel_request_called()); - EXPECT_FALSE(proxy_delegate->on_tunnel_headers_received_called()); - EXPECT_TRUE(proxy_delegate->on_tunnel_request_completed_called()); bool is_secure_proxy = GetParam() == HTTPS || GetParam() == SPDY; histogram_tester().ExpectTotalCount( @@ -292,7 +281,7 @@ TEST_P(HttpProxyClientSocketPoolTest, SetSocketRequestPriorityOnInit) { Initialize(NULL, 0, NULL, 0, NULL, 0, NULL, 0); EXPECT_EQ( - OK, handle_.Init("a", CreateNoTunnelParams(NULL), HIGHEST, + OK, handle_.Init("a", CreateNoTunnelParams(), HIGHEST, ClientSocketPool::RespectLimits::ENABLED, CompletionCallback(), pool_.get(), NetLogWithSource())); EXPECT_EQ(HIGHEST, GetLastTransportRequestPriority()); @@ -332,7 +321,7 @@ spdy_reads, arraysize(spdy_reads), spdy_writes, arraysize(spdy_writes)); - int rv = handle_.Init("a", CreateTunnelParams(NULL), LOW, + int rv = handle_.Init("a", CreateTunnelParams(), LOW, ClientSocketPool::RespectLimits::ENABLED, callback_.callback(), pool_.get(), NetLogWithSource()); EXPECT_THAT(rv, IsError(ERR_IO_PENDING)); @@ -366,9 +355,7 @@ "CONNECT www.google.com:443 HTTP/1.1\r\n" "Host: www.google.com:443\r\n" "Proxy-Connection: keep-alive\r\n" - "Proxy-Authorization: Basic Zm9vOmJhcg==\r\n" - "Foo: " + - proxy_host_port + "\r\n\r\n"; + "Proxy-Authorization: Basic Zm9vOmJhcg==\r\n\r\n"; MockWrite writes[] = { MockWrite(SYNCHRONOUS, 0, request.c_str()), }; @@ -380,21 +367,13 @@ NULL, 0); AddAuthToCache(); - std::unique_ptr<TestProxyDelegate> proxy_delegate(new TestProxyDelegate()); - int rv = handle_.Init("a", CreateTunnelParams(proxy_delegate.get()), LOW, + int rv = handle_.Init("a", CreateTunnelParams(), LOW, ClientSocketPool::RespectLimits::ENABLED, callback_.callback(), pool_.get(), NetLogWithSource()); EXPECT_THAT(rv, IsOk()); EXPECT_TRUE(handle_.is_initialized()); ASSERT_TRUE(handle_.socket()); EXPECT_TRUE(handle_.socket()->IsConnected()); - proxy_delegate->VerifyOnTunnelHeadersReceived( - "www.google.com:443", - proxy_host_port.c_str(), - "HTTP/1.1 200 Connection Established"); - proxy_delegate->VerifyOnTunnelRequestCompleted( - "www.google.com:443", - proxy_host_port.c_str()); } TEST_P(HttpProxyClientSocketPoolTest, AsyncHaveAuth) { @@ -405,9 +384,7 @@ "CONNECT www.google.com:443 HTTP/1.1\r\n" "Host: www.google.com:443\r\n" "Proxy-Connection: keep-alive\r\n" - "Proxy-Authorization: Basic Zm9vOmJhcg==\r\n" - "Foo: " + - proxy_host_port + "\r\n\r\n"; + "Proxy-Authorization: Basic Zm9vOmJhcg==\r\n\r\n"; MockWrite writes[] = { MockWrite(ASYNC, 0, request.c_str()), }; @@ -431,8 +408,7 @@ arraysize(spdy_writes)); AddAuthToCache(); - std::unique_ptr<TestProxyDelegate> proxy_delegate(new TestProxyDelegate()); - int rv = handle_.Init("a", CreateTunnelParams(proxy_delegate.get()), LOW, + int rv = handle_.Init("a", CreateTunnelParams(), LOW, ClientSocketPool::RespectLimits::ENABLED, callback_.callback(), pool_.get(), NetLogWithSource()); EXPECT_THAT(rv, IsError(ERR_IO_PENDING)); @@ -443,9 +419,6 @@ EXPECT_TRUE(handle_.is_initialized()); ASSERT_TRUE(handle_.socket()); EXPECT_TRUE(handle_.socket()->IsConnected()); - proxy_delegate->VerifyOnTunnelRequestCompleted( - "www.google.com:443", - proxy_host_port.c_str()); } // Make sure that HttpProxyConnectJob passes on its priority to its @@ -470,7 +443,7 @@ EXPECT_EQ( ERR_IO_PENDING, - handle_.Init("a", CreateTunnelParams(NULL), MEDIUM, + handle_.Init("a", CreateTunnelParams(), MEDIUM, ClientSocketPool::RespectLimits::ENABLED, callback_.callback(), pool_.get(), NetLogWithSource())); EXPECT_EQ(MEDIUM, GetLastTransportRequestPriority()); @@ -486,7 +459,7 @@ socket_factory()->AddSocketDataProvider(data_.get()); - int rv = handle_.Init("a", CreateTunnelParams(NULL), LOW, + int rv = handle_.Init("a", CreateTunnelParams(), LOW, ClientSocketPool::RespectLimits::ENABLED, callback_.callback(), pool_.get(), NetLogWithSource()); EXPECT_THAT(rv, IsError(ERR_IO_PENDING)); @@ -519,7 +492,7 @@ } socket_factory()->AddSSLSocketDataProvider(ssl_data_.get()); - int rv = handle_.Init("a", CreateTunnelParams(NULL), LOW, + int rv = handle_.Init("a", CreateTunnelParams(), LOW, ClientSocketPool::RespectLimits::ENABLED, callback_.callback(), pool_.get(), NetLogWithSource()); EXPECT_THAT(rv, IsError(ERR_IO_PENDING)); @@ -551,7 +524,7 @@ } socket_factory()->AddSSLSocketDataProvider(ssl_data_.get()); - int rv = handle_.Init("a", CreateTunnelParams(NULL), LOW, + int rv = handle_.Init("a", CreateTunnelParams(), LOW, ClientSocketPool::RespectLimits::ENABLED, callback_.callback(), pool_.get(), NetLogWithSource()); EXPECT_THAT(rv, IsError(ERR_IO_PENDING)); @@ -594,7 +567,7 @@ arraysize(spdy_writes)); AddAuthToCache(); - int rv = handle_.Init("a", CreateTunnelParams(NULL), LOW, + int rv = handle_.Init("a", CreateTunnelParams(), LOW, ClientSocketPool::RespectLimits::ENABLED, callback_.callback(), pool_.get(), NetLogWithSource()); EXPECT_THAT(rv, IsError(ERR_IO_PENDING)); @@ -634,7 +607,7 @@ Initialize(reads, arraysize(reads), writes, arraysize(writes), NULL, 0, NULL, 0); - int rv = handle_.Init("a", CreateTunnelParams(NULL), LOW, + int rv = handle_.Init("a", CreateTunnelParams(), LOW, ClientSocketPool::RespectLimits::ENABLED, callback_.callback(), pool_.get(), NetLogWithSource()); EXPECT_THAT(rv, IsError(ERR_IO_PENDING)); @@ -673,7 +646,7 @@ arraysize(spdy_writes)); AddAuthToCache(); - int rv = handle_.Init("a", CreateTunnelParams(NULL), LOW, + int rv = handle_.Init("a", CreateTunnelParams(), LOW, ClientSocketPool::RespectLimits::ENABLED, callback_.callback(), pool_.get(), NetLogWithSource()); EXPECT_THAT(rv, IsError(ERR_IO_PENDING)); @@ -730,7 +703,7 @@ arraysize(spdy_writes)); AddAuthToCache(); - int rv = handle_.Init("a", CreateTunnelParams(NULL), LOW, + int rv = handle_.Init("a", CreateTunnelParams(), LOW, ClientSocketPool::RespectLimits::ENABLED, callback_.callback(), pool_.get(), NetLogWithSource()); EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
diff --git a/net/http/http_proxy_client_socket_unittest.cc b/net/http/http_proxy_client_socket_unittest.cc index d26e900..dd35006c 100644 --- a/net/http/http_proxy_client_socket_unittest.cc +++ b/net/http/http_proxy_client_socket_unittest.cc
@@ -29,8 +29,7 @@ // non-owning pointer to it. connection->SetSocket(std::unique_ptr<StreamSocket>(tagging_sock)); HttpProxyClientSocket socket(std::move(connection), "", HostPortPair(), - HostPortPair(), nullptr, false, false, - NextProto(), nullptr, false); + nullptr, false, false, NextProto(), false); EXPECT_EQ(tagging_sock->tag(), SocketTag()); #if defined(OS_ANDROID)
diff --git a/net/http/http_proxy_client_socket_wrapper.cc b/net/http/http_proxy_client_socket_wrapper.cc index f5ffa45..5bbf4df 100644 --- a/net/http/http_proxy_client_socket_wrapper.cc +++ b/net/http/http_proxy_client_socket_wrapper.cc
@@ -12,7 +12,6 @@ #include "base/memory/weak_ptr.h" #include "base/metrics/histogram_macros.h" #include "base/values.h" -#include "net/base/proxy_delegate.h" #include "net/http/http_proxy_client_socket.h" #include "net/http/http_response_info.h" #include "net/log/net_log_event_type.h" @@ -49,7 +48,6 @@ SpdySessionPool* spdy_session_pool, QuicStreamFactory* quic_stream_factory, bool tunnel, - ProxyDelegate* proxy_delegate, const NetLogWithSource& net_log) : next_state_(STATE_NONE), group_name_(group_name), @@ -67,7 +65,6 @@ spdy_session_pool_(spdy_session_pool), has_restarted_(false), tunnel_(tunnel), - proxy_delegate_(proxy_delegate), using_spdy_(false), quic_stream_request_(quic_stream_factory), http_auth_controller_( @@ -188,7 +185,6 @@ connect_callback_ = callback; } else { connect_timer_.Stop(); - NotifyProxyDelegateOfCompletion(rv); } return rv; @@ -360,7 +356,6 @@ int rv = DoLoop(result); if (rv != ERR_IO_PENDING) { connect_timer_.Stop(); - NotifyProxyDelegateOfCompletion(rv); // May delete |this|. base::ResetAndReturn(&connect_callback_).Run(rv); } @@ -572,8 +567,7 @@ // Add a HttpProxy connection on top of the tcp socket. transport_socket_.reset(new HttpProxyClientSocket( std::move(transport_socket_handle_), user_agent_, endpoint_, - GetDestination().host_port_pair(), http_auth_controller_.get(), tunnel_, - using_spdy_, negotiated_protocol_, proxy_delegate_, + http_auth_controller_.get(), tunnel_, using_spdy_, negotiated_protocol_, ssl_params_.get() != nullptr)); return transport_socket_->Connect(base::Bind( &HttpProxyClientSocketWrapper::OnIOComplete, base::Unretained(this))); @@ -726,14 +720,6 @@ return result; } -void HttpProxyClientSocketWrapper::NotifyProxyDelegateOfCompletion(int result) { - if (!proxy_delegate_) - return; - - const HostPortPair& proxy_server = GetDestination().host_port_pair(); - proxy_delegate_->OnTunnelConnectCompleted(endpoint_, proxy_server, result); -} - void HttpProxyClientSocketWrapper::SetConnectTimer(base::TimeDelta delay) { connect_timer_.Stop(); connect_timer_.Start(FROM_HERE, delay, this, @@ -757,8 +743,6 @@ } } - NotifyProxyDelegateOfCompletion(ERR_CONNECTION_TIMED_OUT); - CompletionCallback callback = connect_callback_; Disconnect(); callback.Run(ERR_CONNECTION_TIMED_OUT);
diff --git a/net/http/http_proxy_client_socket_wrapper.h b/net/http/http_proxy_client_socket_wrapper.h index aa5b230bf..5ee406fa 100644 --- a/net/http/http_proxy_client_socket_wrapper.h +++ b/net/http/http_proxy_client_socket_wrapper.h
@@ -36,7 +36,6 @@ class HttpResponseInfo; class HttpStream; class IOBuffer; -class ProxyDelegate; class SpdySessionPool; class SSLClientSocketPool; class TransportClientSocketPool; @@ -73,7 +72,6 @@ SpdySessionPool* spdy_session_pool, QuicStreamFactory* quic_stream_factory, bool tunnel, - ProxyDelegate* proxy_delegate, const NetLogWithSource& net_log); // On destruction Disconnect() is called. @@ -172,8 +170,6 @@ int DoRestartWithAuth(); int DoRestartWithAuthComplete(int result); - void NotifyProxyDelegateOfCompletion(int result); - void SetConnectTimer(base::TimeDelta duration); void ConnectTimeout(); @@ -200,7 +196,6 @@ bool has_restarted_; const bool tunnel_; - ProxyDelegate* const proxy_delegate_; bool using_spdy_; NextProto negotiated_protocol_;
diff --git a/net/http/http_proxy_client_socket_wrapper_unittest.cc b/net/http/http_proxy_client_socket_wrapper_unittest.cc index 514a7bb0..b5178f5c 100644 --- a/net/http/http_proxy_client_socket_wrapper_unittest.cc +++ b/net/http/http_proxy_client_socket_wrapper_unittest.cc
@@ -269,7 +269,7 @@ /*transport_params=*/nullptr, ssl_params, quic_version_, kUserAgent, endpoint_host_port_, &http_auth_cache_, http_auth_handler_factory_.get(), /*spdy_session_pool=*/nullptr, quic_stream_factory_.get(), - /*tunnel=*/true, /*proxy_delegate=*/nullptr, net_log_)); + /*tunnel=*/true, net_log_)); TestCompletionCallback callback; client_socket_wrapper_->Connect(callback.callback());
diff --git a/net/http/http_server_properties.h b/net/http/http_server_properties.h index b8efe93..22f0a5d 100644 --- a/net/http/http_server_properties.h +++ b/net/http/http_server_properties.h
@@ -13,6 +13,7 @@ #include <tuple> #include <vector> +#include "base/callback.h" #include "base/containers/mru_cache.h" #include "base/macros.h" #include "base/time/time.h" @@ -313,8 +314,10 @@ HttpServerProperties() {} virtual ~HttpServerProperties() {} - // Deletes all data. - virtual void Clear() = 0; + // Deletes all data. If |callback| is non-null, flushes data to disk + // and invokes the callback asynchronously once changes have been written to + // disk. + virtual void Clear(base::OnceClosure callback) = 0; // Returns true if |server| supports a network protocol which honors // request prioritization.
diff --git a/net/http/http_server_properties_impl.cc b/net/http/http_server_properties_impl.cc index a17489c8..ccd60cb 100644 --- a/net/http/http_server_properties_impl.cc +++ b/net/http/http_server_properties_impl.cc
@@ -177,7 +177,7 @@ return broken_alternative_services_.recently_broken_alternative_services(); } -void HttpServerPropertiesImpl::Clear() { +void HttpServerPropertiesImpl::Clear(base::OnceClosure callback) { DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); spdy_servers_map_.Clear(); alternative_service_map_.Clear(); @@ -187,6 +187,11 @@ server_network_stats_map_.Clear(); quic_server_info_map_.Clear(); canonical_server_info_map_.clear(); + + if (!callback.is_null()) { + base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, + std::move(callback)); + } } bool HttpServerPropertiesImpl::SupportsRequestPriority(
diff --git a/net/http/http_server_properties_impl.h b/net/http/http_server_properties_impl.h index d523f32..7967e86 100644 --- a/net/http/http_server_properties_impl.h +++ b/net/http/http_server_properties_impl.h
@@ -13,6 +13,7 @@ #include <string> #include <vector> +#include "base/callback.h" #include "base/macros.h" #include "base/memory/weak_ptr.h" #include "base/threading/thread_checker.h" @@ -86,7 +87,7 @@ // HttpServerProperties methods: // ----------------------------- - void Clear() override; + void Clear(base::OnceClosure callback) override; bool SupportsRequestPriority(const url::SchemeHostPort& server) override; bool GetSupportsSpdy(const url::SchemeHostPort& server) override; void SetSupportsSpdy(const url::SchemeHostPort& server,
diff --git a/net/http/http_server_properties_impl_unittest.cc b/net/http/http_server_properties_impl_unittest.cc index 32f80acf..c3b04f60 100644 --- a/net/http/http_server_properties_impl_unittest.cc +++ b/net/http/http_server_properties_impl_unittest.cc
@@ -280,9 +280,21 @@ EXPECT_TRUE(impl_.SupportsRequestPriority(spdy_server_google)); EXPECT_TRUE(impl_.SupportsRequestPriority(spdy_server_mail)); - impl_.Clear(); + base::RunLoop run_loop; + bool callback_invoked_ = false; + impl_.Clear(base::BindOnce( + [](bool* callback_invoked, base::OnceClosure quit_closure) { + *callback_invoked = true; + std::move(quit_closure).Run(); + }, + &callback_invoked_, run_loop.QuitClosure())); EXPECT_FALSE(impl_.SupportsRequestPriority(spdy_server_google)); EXPECT_FALSE(impl_.SupportsRequestPriority(spdy_server_mail)); + + // Callback should be run asynchronously. + EXPECT_FALSE(callback_invoked_); + run_loop.Run(); + EXPECT_TRUE(callback_invoked_); } TEST_F(SpdyServerPropertiesTest, MRUOfSpdyServersMap) { @@ -329,7 +341,7 @@ EXPECT_EQ(alternative_service, alternative_service_info_vector[0].alternative_service()); - impl_.Clear(); + impl_.Clear(base::OnceClosure()); EXPECT_FALSE(HasAlternativeService(test_server)); } @@ -933,7 +945,7 @@ "bar.c.youtube.com", 1234); SetAlternativeService(canonical_server, canonical_alternative_service); - impl_.Clear(); + impl_.Clear(base::OnceClosure()); EXPECT_FALSE(HasAlternativeService(test_server)); } @@ -1093,7 +1105,7 @@ EXPECT_TRUE(impl_.GetSupportsQuic(&address)); EXPECT_EQ(actual_address, address); - impl_.Clear(); + impl_.Clear(base::OnceClosure()); EXPECT_FALSE(impl_.GetSupportsQuic(&address)); } @@ -1186,7 +1198,7 @@ // Https server should have nothing set for server network stats. EXPECT_EQ(NULL, impl_.GetServerNetworkStats(foo_https_server)); - impl_.Clear(); + impl_.Clear(base::OnceClosure()); EXPECT_EQ(NULL, impl_.GetServerNetworkStats(foo_http_server)); EXPECT_EQ(NULL, impl_.GetServerNetworkStats(foo_https_server)); } @@ -1305,7 +1317,7 @@ EXPECT_EQ(1u, impl_.quic_server_info_map().size()); EXPECT_EQ(quic_server_info1, *(impl_.GetQuicServerInfo(quic_server_id))); - impl_.Clear(); + impl_.Clear(base::OnceClosure()); EXPECT_EQ(0u, impl_.quic_server_info_map().size()); EXPECT_EQ(nullptr, impl_.GetQuicServerInfo(quic_server_id)); }
diff --git a/net/http/http_server_properties_manager.cc b/net/http/http_server_properties_manager.cc index 4a4dabb..5dc49e2e 100644 --- a/net/http/http_server_properties_manager.cc +++ b/net/http/http_server_properties_manager.cc
@@ -116,9 +116,9 @@ DCHECK(pref_delegate_); DCHECK(clock_); - pref_delegate_->StartListeningForUpdates( - base::Bind(&HttpServerPropertiesManager::OnHttpServerPropertiesChanged, - base::Unretained(this))); + pref_delegate_->StartListeningForUpdates(base::BindRepeating( + &HttpServerPropertiesManager::OnHttpServerPropertiesChanged, + base::Unretained(this))); net_log_.BeginEvent(NetLogEventType::HTTP_SERVER_PROPERTIES_INITIALIZATION); http_server_properties_impl_.reset(new HttpServerPropertiesImpl(clock_)); @@ -127,7 +127,7 @@ HttpServerPropertiesManager::~HttpServerPropertiesManager() { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); // Flush settings on destruction. - UpdatePrefsFromCache(); + UpdatePrefsFromCache(base::OnceClosure()); } // static @@ -141,11 +141,11 @@ http_server_properties_dict->SetInteger(kVersionKey, version_number); } -void HttpServerPropertiesManager::Clear() { +void HttpServerPropertiesManager::Clear(base::OnceClosure callback) { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - http_server_properties_impl_->Clear(); - UpdatePrefsFromCache(); + http_server_properties_impl_->Clear(base::OnceClosure()); + UpdatePrefsFromCache(std::move(callback)); } bool HttpServerPropertiesManager::SupportsRequestPriority( @@ -978,15 +978,17 @@ return; network_prefs_update_timer_.Start( - FROM_HERE, kUpdatePrefsDelay, this, - &HttpServerPropertiesManager::UpdatePrefsFromCache); + FROM_HERE, kUpdatePrefsDelay, + base::Bind(&HttpServerPropertiesManager::UpdatePrefsFromCache, + base::Unretained(this), base::Passed(base::OnceClosure()))); // TODO(rtenneti): Delete the following histogram after collecting some data. UMA_HISTOGRAM_ENUMERATION("Net.HttpServerProperties.UpdatePrefs", location, HttpServerPropertiesManager::NUM_LOCATIONS); } -void HttpServerPropertiesManager::UpdatePrefsFromCache() { +void HttpServerPropertiesManager::UpdatePrefsFromCache( + base::OnceClosure callback) { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); typedef base::MRUCache<url::SchemeHostPort, ServerPref> ServerPrefMap; @@ -1114,7 +1116,8 @@ &http_server_properties_dict); setting_prefs_ = true; - pref_delegate_->SetServerProperties(http_server_properties_dict); + pref_delegate_->SetServerProperties(http_server_properties_dict, + std::move(callback)); setting_prefs_ = false; net_log_.AddEvent(NetLogEventType::HTTP_SERVER_PROPERTIES_UPDATE_PREFS,
diff --git a/net/http/http_server_properties_manager.h b/net/http/http_server_properties_manager.h index c1ee36a..5f346262 100644 --- a/net/http/http_server_properties_manager.h +++ b/net/http/http_server_properties_manager.h
@@ -11,6 +11,7 @@ #include <string> #include <vector> +#include "base/callback.h" #include "base/compiler_specific.h" #include "base/gtest_prod_util.h" #include "base/macros.h" @@ -51,13 +52,17 @@ // Returns nullptr if the pref system has no data for the server properties. virtual const base::DictionaryValue* GetServerProperties() const = 0; - // Sets the server properties to the given value. - virtual void SetServerProperties(const base::DictionaryValue& value) = 0; + // Sets the server properties to the given value. If |callback| is + // non-empty, flushes data to persistent storage and invokes |callback| + // asynchronously when complete. + virtual void SetServerProperties(const base::DictionaryValue& value, + base::OnceClosure callback) = 0; // Starts listening for external storage changes. There will only be one // callback active at a time. The first time the |callback| is invoked is // expected to mean the initial pref store values have been loaded. - virtual void StartListeningForUpdates(const base::Closure& callback) = 0; + virtual void StartListeningForUpdates( + const base::RepeatingClosure& callback) = 0; }; // Create an instance of the HttpServerPropertiesManager. @@ -83,7 +88,7 @@ // HttpServerProperties methods: // ---------------------------------- - void Clear() override; + void Clear(base::OnceClosure callback) override; bool SupportsRequestPriority(const url::SchemeHostPort& server) override; bool GetSupportsSpdy(const url::SchemeHostPort& server) override; void SetSupportsSpdy(const url::SchemeHostPort& server, @@ -182,8 +187,9 @@ void ScheduleUpdatePrefs(Location location); // Update prefs::kHttpServerProperties in preferences with the cached data - // from |http_server_properties_impl_|. - void UpdatePrefsFromCache(); + // from |http_server_properties_impl_|. Invokes |callback| when changes have + // been committed, if non-null. + void UpdatePrefsFromCache(base::OnceClosure callback); private: FRIEND_TEST_ALL_PREFIXES(HttpServerPropertiesManagerTest,
diff --git a/net/http/http_server_properties_manager_unittest.cc b/net/http/http_server_properties_manager_unittest.cc index ecdb1c3..20e835cf0 100644 --- a/net/http/http_server_properties_manager_unittest.cc +++ b/net/http/http_server_properties_manager_unittest.cc
@@ -46,7 +46,8 @@ const base::DictionaryValue* GetServerProperties() const override { return &prefs_; } - void SetServerProperties(const base::DictionaryValue& value) override { + void SetServerProperties(const base::DictionaryValue& value, + base::OnceClosure callback) override { prefs_.Clear(); prefs_.MergeDictionary(&value); ++num_pref_updates_; @@ -54,6 +55,7 @@ prefs_changed_callback_.Run(); if (!extra_prefs_changed_callback_.is_null()) extra_prefs_changed_callback_.Run(); + set_properties_callback_ = std::move(callback); } void StartListeningForUpdates(const base::Closure& callback) override { CHECK(prefs_changed_callback_.is_null()); @@ -80,12 +82,20 @@ extra_prefs_changed_callback_ = callback; } + // Returns the base::OnceCallback, if any, passed to the last call to + // SetServerProperties(). + base::OnceClosure GetSetPropertiesCallback() { + return std::move(set_properties_callback_); + } + private: base::DictionaryValue prefs_; base::Closure prefs_changed_callback_; base::Closure extra_prefs_changed_callback_; int num_pref_updates_ = 0; + base::OnceClosure set_properties_callback_; + DISALLOW_COPY_AND_ASSIGN(MockPrefDelegate); }; @@ -807,8 +817,14 @@ // Clear http server data, which should instantly update prefs. EXPECT_EQ(0, pref_delegate_->GetAndClearNumPrefUpdates()); - http_server_props_manager_->Clear(); + bool callback_invoked_ = false; + http_server_props_manager_->Clear( + base::BindOnce([](bool* callback_invoked) { *callback_invoked = true; }, + &callback_invoked_)); EXPECT_EQ(1, pref_delegate_->GetAndClearNumPrefUpdates()); + EXPECT_FALSE(callback_invoked_); + std::move(pref_delegate_->GetSetPropertiesCallback()).Run(); + EXPECT_TRUE(callback_invoked_); EXPECT_FALSE(http_server_props_manager_->IsAlternativeServiceBroken( broken_alternative_service));
diff --git a/net/http/http_stream_factory_impl_job.cc b/net/http/http_stream_factory_impl_job.cc index 2820679..1057041 100644 --- a/net/http/http_stream_factory_impl_job.cc +++ b/net/http/http_stream_factory_impl_job.cc
@@ -201,6 +201,7 @@ was_alpn_negotiated_(false), negotiated_protocol_(kProtoUnknown), num_streams_(0), + pushed_stream_id_(kNoPushedStreamFound), spdy_session_direct_( !(proxy_info.is_https() && origin_url_.SchemeIs(url::kHttpScheme))), spdy_session_key_(using_quic_ @@ -931,10 +932,9 @@ // connection this request can pool to. If so, then go straight to using // that. if (CanUseExistingSpdySession()) { - // TODO(bnc): Use outparam. https://crbug.com/776415. - SpdyStreamId unused; - session_->spdy_session_pool()->push_promise_index()->FindSession( - spdy_session_key_, origin_url_, &existing_spdy_session_, &unused); + session_->spdy_session_pool()->push_promise_index()->ClaimPushedStream( + spdy_session_key_, origin_url_, &existing_spdy_session_, + &pushed_stream_id_); if (!existing_spdy_session_) { existing_spdy_session_ = session_->spdy_session_pool()->FindAvailableSession( @@ -1172,8 +1172,8 @@ bool use_relative_url = direct || request_info_.url.SchemeIs(url::kHttpsScheme); - stream_ = std::make_unique<SpdyHttpStream>(session, use_relative_url, - net_log_.source()); + stream_ = std::make_unique<SpdyHttpStream>( + session, pushed_stream_id_, use_relative_url, net_log_.source()); return OK; } @@ -1215,10 +1215,9 @@ // It is possible that a pushed stream has been opened by a server since last // time Job checked above. if (!existing_spdy_session_) { - // TODO(bnc): Use outparam. https://crbug.com/776415. - SpdyStreamId unused; - session_->spdy_session_pool()->push_promise_index()->FindSession( - spdy_session_key_, origin_url_, &existing_spdy_session_, &unused); + session_->spdy_session_pool()->push_promise_index()->ClaimPushedStream( + spdy_session_key_, origin_url_, &existing_spdy_session_, + &pushed_stream_id_); // It is also possible that an HTTP/2 connection has been established since // last time Job checked above. if (!existing_spdy_session_) {
diff --git a/net/http/http_stream_factory_impl_job.h b/net/http/http_stream_factory_impl_job.h index 2a4885e..e02ca44 100644 --- a/net/http/http_stream_factory_impl_job.h +++ b/net/http/http_stream_factory_impl_job.h
@@ -500,6 +500,12 @@ // Initialized when we have an existing SpdySession. base::WeakPtr<SpdySession> existing_spdy_session_; + // Once Job claims a pushed stream on a SpdySession, |pushed_stream_id_| is + // the ID of the claimed stream, and |existing_spdy_session_| points to that + // SpdySession. Otherwise |pushed_stream_id_| is set to kNoPushedStreamFound + // (but |existing_spdy_session_| can still be non-null). + SpdyStreamId pushed_stream_id_; + // True if not connecting to an Https proxy for an Http url. const bool spdy_session_direct_;
diff --git a/net/nqe/observation_buffer_unittest.cc b/net/nqe/observation_buffer_unittest.cc index 1f15b79..187e1c5 100644 --- a/net/nqe/observation_buffer_unittest.cc +++ b/net/nqe/observation_buffer_unittest.cc
@@ -45,10 +45,6 @@ } } -// Test disabled on OS_WIN to avoid linking errors when calling -// SetTickClockForTesting. -// TODO(tbansal): crbug.com/651963. Pass the clock through NQE's constructor. -#if !defined(OS_WIN) // Verify that the percentiles are monotonically non-decreasing when a weight is // applied. TEST(NetworkQualityObservationBufferTest, GetPercentileWithWeights) { @@ -90,7 +86,6 @@ } EXPECT_LT(result_lowest, result_highest); } -#endif // Verifies that the percentiles are correctly computed. All observations have // the same timestamp.
diff --git a/net/proxy/proxy_service_unittest.cc b/net/proxy/proxy_service_unittest.cc index 58a4440f..65ed64e 100644 --- a/net/proxy/proxy_service_unittest.cc +++ b/net/proxy/proxy_service_unittest.cc
@@ -214,16 +214,7 @@ return proxy_retry_info_; } - void OnTunnelConnectCompleted(const HostPortPair& endpoint, - const HostPortPair& proxy_server, - int net_error) override {} void OnFallback(const ProxyServer& bad_proxy, int net_error) override {} - void OnBeforeTunnelRequest(const HostPortPair& proxy_server, - HttpRequestHeaders* extra_headers) override {} - void OnTunnelHeadersReceived( - const HostPortPair& origin, - const HostPortPair& proxy_server, - const HttpResponseHeaders& response_headers) override {} bool IsTrustedSpdyProxy(const net::ProxyServer& proxy_server) override { return true; } @@ -249,20 +240,11 @@ const std::string& method, const ProxyRetryInfoMap& proxy_retry_info, ProxyInfo* result) override {} - void OnTunnelConnectCompleted(const HostPortPair& endpoint, - const HostPortPair& proxy_server, - int net_error) override {} void OnFallback(const ProxyServer& bad_proxy, int net_error) override { proxy_server_ = bad_proxy; proxy_fallback_net_error_ = net_error; on_proxy_fallback_called_ = true; } - void OnBeforeTunnelRequest(const HostPortPair& proxy_server, - HttpRequestHeaders* extra_headers) override {} - void OnTunnelHeadersReceived( - const HostPortPair& origin, - const HostPortPair& proxy_server, - const HttpResponseHeaders& response_headers) override {} bool IsTrustedSpdyProxy(const net::ProxyServer& proxy_server) override { return true; }
diff --git a/net/socket/client_socket_pool_manager.cc b/net/socket/client_socket_pool_manager.cc index ffec16f..85d614e3 100644 --- a/net/socket/client_socket_pool_manager.cc +++ b/net/socket/client_socket_pool_manager.cc
@@ -177,8 +177,7 @@ proxy_tcp_params, ssl_params, QUIC_VERSION_UNSUPPORTED, user_agent, origin_host_port, session->http_auth_cache(), session->http_auth_handler_factory(), session->spdy_session_pool(), - session->quic_stream_factory(), force_tunnel || using_ssl, - session->context().proxy_delegate); + session->quic_stream_factory(), force_tunnel || using_ssl); } else { DCHECK(proxy_info.is_socks()); char socks_version;
diff --git a/net/socket/ssl_client_socket_pool_unittest.cc b/net/socket/ssl_client_socket_pool_unittest.cc index 2715d394..f102be2e 100644 --- a/net/socket/ssl_client_socket_pool_unittest.cc +++ b/net/socket/ssl_client_socket_pool_unittest.cc
@@ -123,8 +123,7 @@ session_->http_auth_handler_factory(), session_->spdy_session_pool(), session_->quic_stream_factory(), - true, - NULL)), + true)), http_proxy_socket_pool_(kMaxSockets, kMaxSocketsPerGroup, &transport_socket_pool_,
diff --git a/net/spdy/chromium/http2_push_promise_index.cc b/net/spdy/chromium/http2_push_promise_index.cc index 48362a4..467207f8 100644 --- a/net/spdy/chromium/http2_push_promise_index.cc +++ b/net/spdy/chromium/http2_push_promise_index.cc
@@ -84,10 +84,11 @@ return it->stream_id; } -void Http2PushPromiseIndex::FindSession(const SpdySessionKey& key, - const GURL& url, - base::WeakPtr<SpdySession>* session, - SpdyStreamId* stream_id) const { +void Http2PushPromiseIndex::ClaimPushedStream( + const SpdySessionKey& key, + const GURL& url, + base::WeakPtr<SpdySession>* session, + SpdyStreamId* stream_id) { DCHECK(!url.is_empty()); *session = nullptr; @@ -106,6 +107,7 @@ *session = it->delegate->GetWeakPtrToSession(); *stream_id = it->stream_id; it->delegate->OnPushedStreamClaimed(it->url, it->stream_id); + unclaimed_pushed_streams_.erase(it); return; } ++it;
diff --git a/net/spdy/chromium/http2_push_promise_index.h b/net/spdy/chromium/http2_push_promise_index.h index fd283bc..fe70c189 100644 --- a/net/spdy/chromium/http2_push_promise_index.h +++ b/net/spdy/chromium/http2_push_promise_index.h
@@ -25,7 +25,7 @@ } // namespace test -// Value returned by FindSession() and FindStream() if no stream is found. +// Value returned by ClaimPushedStream() and FindStream() if no stream is found. const SpdyStreamId kNoPushedStreamFound = 0; // This class manages unclaimed pushed streams (push promises) from the receipt @@ -88,13 +88,14 @@ // If there exists a session compatible with |key| that has an unclaimed push // stream for |url|, then sets |*session| and |*stream| to one such session - // and stream. Makes no guarantee on which (session, stream_id) pair it - // returns if there are multiple matches. Sets |*session| to nullptr and - // |*stream| to kNoPushedStreamFound if no such session exists. - void FindSession(const SpdySessionKey& key, - const GURL& url, - base::WeakPtr<SpdySession>* session, - SpdyStreamId* stream_id) const; + // and stream, and removes entry from index. Makes no guarantee on which + // (session, stream_id) pair is claimed if there are multiple matches. Sets + // |*session| to nullptr and |*stream| to kNoPushedStreamFound if no such + // session exists. + void ClaimPushedStream(const SpdySessionKey& key, + const GURL& url, + base::WeakPtr<SpdySession>* session, + SpdyStreamId* stream_id); // Return the estimate of dynamically allocated memory in bytes. size_t EstimateMemoryUsage() const;
diff --git a/net/spdy/chromium/http2_push_promise_index_test.cc b/net/spdy/chromium/http2_push_promise_index_test.cc index 47caeda..21e8d6b9 100644 --- a/net/spdy/chromium/http2_push_promise_index_test.cc +++ b/net/spdy/chromium/http2_push_promise_index_test.cc
@@ -217,24 +217,24 @@ EXPECT_EQ(kNoPushedStreamFound, index_.FindStream(url2_, &delegate2)); } -// If |index_| is empty, then FindSession() should set its |stream_id| outparam -// to kNoPushedStreamFound for any values of inparams. +// If |index_| is empty, then ClaimPushedStream() should set its |stream_id| +// outparam to kNoPushedStreamFound for any values of inparams. TEST_F(Http2PushPromiseIndexTest, Empty) { base::WeakPtr<SpdySession> session; SpdyStreamId stream_id = 2; - index_.FindSession(key1_, url1_, &session, &stream_id); + index_.ClaimPushedStream(key1_, url1_, &session, &stream_id); EXPECT_EQ(kNoPushedStreamFound, stream_id); stream_id = 2; - index_.FindSession(key1_, url2_, &session, &stream_id); + index_.ClaimPushedStream(key1_, url2_, &session, &stream_id); EXPECT_EQ(kNoPushedStreamFound, stream_id); stream_id = 2; - index_.FindSession(key1_, url2_, &session, &stream_id); + index_.ClaimPushedStream(key1_, url2_, &session, &stream_id); EXPECT_EQ(kNoPushedStreamFound, stream_id); stream_id = 2; - index_.FindSession(key2_, url2_, &session, &stream_id); + index_.ClaimPushedStream(key2_, url2_, &session, &stream_id); EXPECT_EQ(kNoPushedStreamFound, stream_id); } @@ -246,52 +246,48 @@ TestDelegate delegate1(key1_); EXPECT_TRUE(index_.RegisterUnclaimedPushedStream(url1_, 2, &delegate1)); - // Retrieve first entry by its URL, no entry found for |url2_|. + // No entry found for |url2_|. base::WeakPtr<SpdySession> session; - SpdyStreamId stream_id = kNoPushedStreamFound; - index_.FindSession(key1_, url1_, &session, &stream_id); - EXPECT_EQ(2u, stream_id); - - stream_id = 2; - index_.FindSession(key1_, url2_, &session, &stream_id); + SpdyStreamId stream_id = 2; + index_.ClaimPushedStream(key1_, url2_, &session, &stream_id); EXPECT_EQ(kNoPushedStreamFound, stream_id); - // Register second entry. + // Claim first entry. + stream_id = kNoPushedStreamFound; + index_.ClaimPushedStream(key1_, url1_, &session, &stream_id); + EXPECT_EQ(2u, stream_id); + + // ClaimPushedStream() unregistered first entry, cannot claim it again. + stream_id = 2; + index_.ClaimPushedStream(key1_, url1_, &session, &stream_id); + EXPECT_EQ(kNoPushedStreamFound, stream_id); + + // Register two entries. Second entry uses same key. + EXPECT_TRUE(index_.RegisterUnclaimedPushedStream(url1_, 2, &delegate1)); TestDelegate delegate2(key1_); EXPECT_TRUE(index_.RegisterUnclaimedPushedStream(url2_, 4, &delegate2)); // Retrieve each entry by their respective URLs. stream_id = kNoPushedStreamFound; - index_.FindSession(key1_, url1_, &session, &stream_id); + index_.ClaimPushedStream(key1_, url1_, &session, &stream_id); EXPECT_EQ(2u, stream_id); stream_id = kNoPushedStreamFound; - index_.FindSession(key1_, url2_, &session, &stream_id); + index_.ClaimPushedStream(key1_, url2_, &session, &stream_id); EXPECT_EQ(4u, stream_id); - // Unregister first entry. - EXPECT_TRUE(index_.UnregisterUnclaimedPushedStream(url1_, 2, &delegate1)); - - // No entry found for |url1_|, retrieve second entry by its URL. + // ClaimPushedStream() calls unregistered both entries, + // cannot claim them again. stream_id = 2; - index_.FindSession(key1_, url1_, &session, &stream_id); - EXPECT_EQ(kNoPushedStreamFound, stream_id); - - stream_id = kNoPushedStreamFound; - index_.FindSession(key1_, url2_, &session, &stream_id); - EXPECT_EQ(4u, stream_id); - - // Unregister second entry. - EXPECT_TRUE(index_.UnregisterUnclaimedPushedStream(url2_, 4, &delegate2)); - - // No entries found for either URL. - stream_id = 2; - index_.FindSession(key1_, url1_, &session, &stream_id); + index_.ClaimPushedStream(key1_, url1_, &session, &stream_id); EXPECT_EQ(kNoPushedStreamFound, stream_id); stream_id = 2; - index_.FindSession(key1_, url2_, &session, &stream_id); + index_.ClaimPushedStream(key1_, url2_, &session, &stream_id); EXPECT_EQ(kNoPushedStreamFound, stream_id); + + EXPECT_FALSE(index_.UnregisterUnclaimedPushedStream(url1_, 2, &delegate1)); + EXPECT_FALSE(index_.UnregisterUnclaimedPushedStream(url2_, 4, &delegate2)); } // Create two entries with delegates that validate different SpdySessionKeys. @@ -302,52 +298,48 @@ TestDelegate delegate1(key1_); EXPECT_TRUE(index_.RegisterUnclaimedPushedStream(url1_, 2, &delegate1)); - // Retrieve first entry by its SpdySessionKey, no entry found for |key2_|. + // No entry found for |key2_|. base::WeakPtr<SpdySession> session; - SpdyStreamId stream_id = kNoPushedStreamFound; - index_.FindSession(key1_, url1_, &session, &stream_id); - EXPECT_EQ(2u, stream_id); - - stream_id = 2; - index_.FindSession(key2_, url1_, &session, &stream_id); + SpdyStreamId stream_id = 2; + index_.ClaimPushedStream(key2_, url1_, &session, &stream_id); EXPECT_EQ(kNoPushedStreamFound, stream_id); - // Register second entry. + // Claim first entry. + stream_id = kNoPushedStreamFound; + index_.ClaimPushedStream(key1_, url1_, &session, &stream_id); + EXPECT_EQ(2u, stream_id); + + // ClaimPushedStream() unregistered first entry, cannot claim it again. + stream_id = 2; + index_.ClaimPushedStream(key1_, url1_, &session, &stream_id); + EXPECT_EQ(kNoPushedStreamFound, stream_id); + + // Register two entries. Second entry uses same URL. + EXPECT_TRUE(index_.RegisterUnclaimedPushedStream(url1_, 2, &delegate1)); TestDelegate delegate2(key2_); EXPECT_TRUE(index_.RegisterUnclaimedPushedStream(url1_, 4, &delegate2)); // Retrieve each entry by their respective SpdySessionKeys. stream_id = kNoPushedStreamFound; - index_.FindSession(key1_, url1_, &session, &stream_id); + index_.ClaimPushedStream(key1_, url1_, &session, &stream_id); EXPECT_EQ(2u, stream_id); stream_id = kNoPushedStreamFound; - index_.FindSession(key2_, url1_, &session, &stream_id); + index_.ClaimPushedStream(key2_, url1_, &session, &stream_id); EXPECT_EQ(4u, stream_id); - // Unregister first entry. - EXPECT_TRUE(index_.UnregisterUnclaimedPushedStream(url1_, 2, &delegate1)); - - // No entry found for |key1_|, retrieve second entry by its SpdySessionKey. + // ClaimPushedStream() calls unregistered both entries, + // cannot claim them again. stream_id = 2; - index_.FindSession(key1_, url1_, &session, &stream_id); - EXPECT_EQ(kNoPushedStreamFound, stream_id); - - stream_id = kNoPushedStreamFound; - index_.FindSession(key2_, url1_, &session, &stream_id); - EXPECT_EQ(4u, stream_id); - - // Unregister second entry. - EXPECT_TRUE(index_.UnregisterUnclaimedPushedStream(url1_, 4, &delegate2)); - - // No entries found for either SpdySessionKeys. - stream_id = 2; - index_.FindSession(key1_, url1_, &session, &stream_id); + index_.ClaimPushedStream(key1_, url1_, &session, &stream_id); EXPECT_EQ(kNoPushedStreamFound, stream_id); stream_id = 2; - index_.FindSession(key2_, url1_, &session, &stream_id); + index_.ClaimPushedStream(key2_, url1_, &session, &stream_id); EXPECT_EQ(kNoPushedStreamFound, stream_id); + + EXPECT_FALSE(index_.UnregisterUnclaimedPushedStream(url1_, 2, &delegate1)); + EXPECT_FALSE(index_.UnregisterUnclaimedPushedStream(url1_, 4, &delegate2)); } TEST_F(Http2PushPromiseIndexTest, MultipleMatchingStreams) { @@ -358,34 +350,33 @@ EXPECT_TRUE(index_.RegisterUnclaimedPushedStream(url1_, 2, &delegate1)); EXPECT_TRUE(index_.RegisterUnclaimedPushedStream(url1_, 4, &delegate2)); - // Test that FindSession() returns one of the two entries. FindSession() - // makes no guarantee about which entry it returns if there are multiple - // matches. + // Test that ClaimPushedStream() returns one of the two entries. + // ClaimPushedStream() makes no guarantee about which entry it returns if + // there are multiple matches. base::WeakPtr<SpdySession> session; - SpdyStreamId stream_id = kNoPushedStreamFound; - index_.FindSession(key1_, url1_, &session, &stream_id); - EXPECT_NE(kNoPushedStreamFound, stream_id); + SpdyStreamId stream_id1 = kNoPushedStreamFound; + index_.ClaimPushedStream(key1_, url1_, &session, &stream_id1); + EXPECT_NE(kNoPushedStreamFound, stream_id1); - // Unregister the first entry. - EXPECT_TRUE(index_.UnregisterUnclaimedPushedStream(url1_, 2, &delegate1)); + // First call to ClaimPushedStream() unregistered one of the entries. + // Second call to ClaimPushedStream() must return the other entry. + SpdyStreamId stream_id2 = kNoPushedStreamFound; + index_.ClaimPushedStream(key1_, url1_, &session, &stream_id2); + EXPECT_NE(kNoPushedStreamFound, stream_id2); + EXPECT_NE(stream_id1, stream_id2); - // Test that the second entry can still be retrieved. - stream_id = kNoPushedStreamFound; - index_.FindSession(key1_, url1_, &session, &stream_id); - EXPECT_EQ(4u, stream_id); + // Two calls to ClaimPushedStream() unregistered both entries. + SpdyStreamId stream_id3 = 2; + index_.ClaimPushedStream(key1_, url1_, &session, &stream_id3); + EXPECT_EQ(kNoPushedStreamFound, stream_id3); - // Unregister the second entry. - EXPECT_TRUE(index_.UnregisterUnclaimedPushedStream(url1_, 4, &delegate2)); - - // Test that no entry is found. - stream_id = 2; - index_.FindSession(key1_, url1_, &session, &stream_id); - EXPECT_EQ(kNoPushedStreamFound, stream_id); + EXPECT_FALSE(index_.UnregisterUnclaimedPushedStream(url1_, 2, &delegate1)); + EXPECT_FALSE(index_.UnregisterUnclaimedPushedStream(url1_, 4, &delegate2)); } -// Test that Delegate::ValidatePushedStream() is called by FindSession(), and if -// it returns true, then Delegate::OnPushedStreamClaimed() is called with the -// appropriate arguments. +// Test that Delegate::ValidatePushedStream() is called by ClaimPushedStream(), +// and if it returns true, then Delegate::OnPushedStreamClaimed() is called with +// the appropriate arguments. TEST_F(Http2PushPromiseIndexTest, MatchCallsOnPushedStreamClaimed) { MockDelegate delegate; EXPECT_CALL(delegate, ValidatePushedStream(key1_)).WillOnce(Return(true)); @@ -395,14 +386,16 @@ base::WeakPtr<SpdySession> session; SpdyStreamId stream_id = kNoPushedStreamFound; - index_.FindSession(key1_, url1_, &session, &stream_id); + index_.ClaimPushedStream(key1_, url1_, &session, &stream_id); EXPECT_EQ(2u, stream_id); - EXPECT_TRUE(index_.UnregisterUnclaimedPushedStream(url1_, 2, &delegate)); + // ClaimPushedStream() unregistered the entry. + EXPECT_FALSE(index_.UnregisterUnclaimedPushedStream(url1_, 2, &delegate)); }; -// Test that Delegate::ValidatePushedStream() is called by FindSession(), and if -// it returns false, then Delegate::OnPushedStreamClaimed() is not called. +// Test that Delegate::ValidatePushedStream() is called by ClaimPushedStream(), +// and if it returns false, then Delegate::OnPushedStreamClaimed() is not +// called. TEST_F(Http2PushPromiseIndexTest, MismatchDoesNotCallOnPushedStreamClaimed) { MockDelegate delegate; EXPECT_CALL(delegate, ValidatePushedStream(key1_)).WillOnce(Return(false)); @@ -412,7 +405,7 @@ base::WeakPtr<SpdySession> session; SpdyStreamId stream_id = 2; - index_.FindSession(key1_, url1_, &session, &stream_id); + index_.ClaimPushedStream(key1_, url1_, &session, &stream_id); EXPECT_EQ(kNoPushedStreamFound, stream_id); EXPECT_TRUE(index_.UnregisterUnclaimedPushedStream(url1_, 2, &delegate));
diff --git a/net/spdy/chromium/spdy_http_stream.cc b/net/spdy/chromium/spdy_http_stream.cc index 17a12834..aa35adc 100644 --- a/net/spdy/chromium/spdy_http_stream.cc +++ b/net/spdy/chromium/spdy_http_stream.cc
@@ -33,11 +33,13 @@ const size_t SpdyHttpStream::kRequestBodyBufferSize = 1 << 14; // 16KB SpdyHttpStream::SpdyHttpStream(const base::WeakPtr<SpdySession>& spdy_session, + SpdyStreamId pushed_stream_id, bool direct, NetLogSource source_dependency) : MultiplexedHttpStream( std::make_unique<MultiplexedSessionHandle>(spdy_session)), spdy_session_(spdy_session), + pushed_stream_id_(pushed_stream_id), is_reused_(spdy_session_->IsReused()), source_dependency_(source_dependency), stream_(nullptr), @@ -79,8 +81,9 @@ // TODO(bnc): Remove this condition once pushed headers are properly // validated. https://crbug.com/554220. if (request_info_->method == "GET") { - int error = spdy_session_->GetPushStream(request_info_->url, priority, - &stream_, stream_net_log); + int error = + spdy_session_->GetPushedStream(request_info_->url, pushed_stream_id_, + priority, &stream_, stream_net_log); if (error != OK) return error;
diff --git a/net/spdy/chromium/spdy_http_stream.h b/net/spdy/chromium/spdy_http_stream.h index fabdbaa..7dac145 100644 --- a/net/spdy/chromium/spdy_http_stream.h +++ b/net/spdy/chromium/spdy_http_stream.h
@@ -36,6 +36,7 @@ static const size_t kRequestBodyBufferSize; // |spdy_session| must not be NULL. SpdyHttpStream(const base::WeakPtr<SpdySession>& spdy_session, + SpdyStreamId pushed_stream_id, bool direct, NetLogSource source_dependency); ~SpdyHttpStream() override; @@ -133,6 +134,12 @@ bool ShouldWaitForMoreBufferedData() const; const base::WeakPtr<SpdySession> spdy_session_; + + // The ID of the pushed stream if one is claimed by this request. + // In this case, the request fails if it cannot use that pushed stream. + // Otherwise set to kNoPushedStreamFound. + const SpdyStreamId pushed_stream_id_; + bool is_reused_; SpdyStreamRequest stream_request_; const NetLogSource source_dependency_;
diff --git a/net/spdy/chromium/spdy_http_stream_unittest.cc b/net/spdy/chromium/spdy_http_stream_unittest.cc index d6d2778..5f3d5ddcd 100644 --- a/net/spdy/chromium/spdy_http_stream_unittest.cc +++ b/net/spdy/chromium/spdy_http_stream_unittest.cc
@@ -197,8 +197,8 @@ HttpResponseInfo response; HttpRequestHeaders headers; NetLogWithSource net_log; - auto http_stream = - std::make_unique<SpdyHttpStream>(session_, true, net_log.source()); + auto http_stream = std::make_unique<SpdyHttpStream>( + session_, kNoPushedStreamFound, true, net_log.source()); // Make sure getting load timing information the stream early does not crash. LoadTimingInfo load_timing_info; EXPECT_FALSE(http_stream->GetLoadTimingInfo(&load_timing_info)); @@ -254,8 +254,8 @@ HttpResponseInfo response; HttpRequestHeaders headers; NetLogWithSource net_log; - auto http_stream = - std::make_unique<SpdyHttpStream>(session_, true, net_log.source()); + auto http_stream = std::make_unique<SpdyHttpStream>( + session_, kNoPushedStreamFound, true, net_log.source()); ASSERT_THAT(http_stream->InitializeStream(request.get(), DEFAULT_PRIORITY, net_log, CompletionCallback()), @@ -316,8 +316,8 @@ HttpResponseInfo response1; HttpRequestHeaders headers1; NetLogWithSource net_log; - auto http_stream1 = - std::make_unique<SpdyHttpStream>(session_, true, net_log.source()); + auto http_stream1 = std::make_unique<SpdyHttpStream>( + session_, kNoPushedStreamFound, true, net_log.source()); HttpRequestInfo request2; request2.method = "GET"; @@ -325,8 +325,8 @@ TestCompletionCallback callback2; HttpResponseInfo response2; HttpRequestHeaders headers2; - auto http_stream2 = - std::make_unique<SpdyHttpStream>(session_, true, net_log.source()); + auto http_stream2 = std::make_unique<SpdyHttpStream>( + session_, kNoPushedStreamFound, true, net_log.source()); // First write. ASSERT_THAT(http_stream1->InitializeStream(&request1, DEFAULT_PRIORITY, @@ -423,7 +423,8 @@ HttpResponseInfo response; HttpRequestHeaders headers; NetLogWithSource net_log; - SpdyHttpStream http_stream(session_, true, net_log.source()); + SpdyHttpStream http_stream(session_, kNoPushedStreamFound, true, + net_log.source()); ASSERT_THAT(http_stream.InitializeStream(&request, DEFAULT_PRIORITY, net_log, CompletionCallback()), IsOk()); @@ -478,7 +479,8 @@ HttpResponseInfo response; HttpRequestHeaders headers; NetLogWithSource net_log; - SpdyHttpStream http_stream(session_, true, net_log.source()); + SpdyHttpStream http_stream(session_, kNoPushedStreamFound, true, + net_log.source()); ASSERT_THAT(http_stream.InitializeStream(&request, DEFAULT_PRIORITY, net_log, CompletionCallback()), IsOk()); @@ -532,7 +534,8 @@ HttpResponseInfo response; HttpRequestHeaders headers; NetLogWithSource net_log; - SpdyHttpStream http_stream(session_, true, net_log.source()); + SpdyHttpStream http_stream(session_, kNoPushedStreamFound, true, + net_log.source()); ASSERT_THAT(http_stream.InitializeStream(&request, DEFAULT_PRIORITY, net_log, CompletionCallback()), IsOk()); @@ -600,8 +603,8 @@ upload_stream.AppendData(kUploadData, kUploadDataSize, false); NetLogWithSource net_log; - auto http_stream = - std::make_unique<SpdyHttpStream>(session_, true, net_log.source()); + auto http_stream = std::make_unique<SpdyHttpStream>( + session_, kNoPushedStreamFound, true, net_log.source()); ASSERT_THAT(http_stream->InitializeStream(&request, DEFAULT_PRIORITY, net_log, CompletionCallback()), IsOk()); @@ -695,8 +698,8 @@ upload_stream.AppendData(kUploadData, kUploadDataSize, false); NetLogWithSource net_log; - auto http_stream = - std::make_unique<SpdyHttpStream>(session_, true, net_log.source()); + auto http_stream = std::make_unique<SpdyHttpStream>( + session_, kNoPushedStreamFound, true, net_log.source()); ASSERT_THAT(http_stream->InitializeStream(&request, DEFAULT_PRIORITY, net_log, CompletionCallback()), IsOk()); @@ -779,8 +782,8 @@ upload_stream.AppendData("", 0, true); NetLogWithSource net_log; - auto http_stream = - std::make_unique<SpdyHttpStream>(session_, true, net_log.source()); + auto http_stream = std::make_unique<SpdyHttpStream>( + session_, kNoPushedStreamFound, true, net_log.source()); ASSERT_THAT(http_stream->InitializeStream(&request, DEFAULT_PRIORITY, net_log, CompletionCallback()), IsOk()); @@ -839,8 +842,8 @@ HttpResponseInfo response; HttpRequestHeaders headers; NetLogWithSource net_log; - auto http_stream = - std::make_unique<SpdyHttpStream>(session_, true, net_log.source()); + auto http_stream = std::make_unique<SpdyHttpStream>( + session_, kNoPushedStreamFound, true, net_log.source()); ASSERT_THAT(http_stream->InitializeStream(&request, DEFAULT_PRIORITY, net_log, CompletionCallback()), IsOk()); @@ -892,8 +895,8 @@ IsOk()); NetLogWithSource net_log; - auto http_stream = - std::make_unique<SpdyHttpStream>(session_, true, net_log.source()); + auto http_stream = std::make_unique<SpdyHttpStream>( + session_, kNoPushedStreamFound, true, net_log.source()); ASSERT_THAT(http_stream->InitializeStream(&request, DEFAULT_PRIORITY, net_log, CompletionCallback()), IsOk()); @@ -997,7 +1000,8 @@ HttpResponseInfo response; HttpRequestHeaders headers; NetLogWithSource net_log; - SpdyHttpStream http_stream(session_, true, net_log.source()); + SpdyHttpStream http_stream(session_, kNoPushedStreamFound, true, + net_log.source()); ASSERT_THAT(http_stream.InitializeStream(&request, DEFAULT_PRIORITY, net_log, CompletionCallback()), IsOk()); @@ -1050,7 +1054,8 @@ HttpResponseInfo response; HttpRequestHeaders headers; NetLogWithSource net_log; - SpdyHttpStream http_stream(session_, true, net_log.source()); + SpdyHttpStream http_stream(session_, kNoPushedStreamFound, true, + net_log.source()); ASSERT_THAT(http_stream.InitializeStream(&request, DEFAULT_PRIORITY, net_log, CompletionCallback()), IsOk()); @@ -1092,7 +1097,8 @@ upload_stream.AppendData("", 0, true); NetLogWithSource net_log; - SpdyHttpStream http_stream(session_, true, net_log.source()); + SpdyHttpStream http_stream(session_, kNoPushedStreamFound, true, + net_log.source()); ASSERT_THAT(http_stream.InitializeStream(&request, DEFAULT_PRIORITY, net_log, CompletionCallback()), IsOk()); @@ -1115,6 +1121,80 @@ EXPECT_FALSE(HasSpdySession(http_session_->spdy_session_pool(), key_)); } +// A SpdyHttpStream should use a matching pushed stream, even if it is +// constructed with |pushed_stream_id == kNoPushedStreamFound|. +TEST_F(SpdyHttpStreamTest, UsePushedStreamEvenWithKNoPushedStreamFound) { + SpdySerializedFrame req( + spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST, true)); + SpdySerializedFrame priority( + spdy_util_.ConstructSpdyPriority(2, 1, IDLE, true)); + MockWrite writes[] = {CreateMockWrite(req, 0), CreateMockWrite(priority, 2)}; + SpdySerializedFrame push(spdy_util_.ConstructSpdyPush( + nullptr, 0, 2, 1, "https://www.example.org/foo.dat")); + SpdySerializedFrame resp(spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1)); + MockRead reads[] = {CreateMockRead(push, 1), CreateMockRead(resp, 3), + MockRead(ASYNC, 0, 4)}; + InitSession(reads, arraysize(reads), writes, arraysize(writes)); + + // Create and initialize first stream. + NetLogWithSource net_log; + auto stream1 = std::make_unique<SpdyHttpStream>( + session_, kNoPushedStreamFound, true, net_log.source()); + + HttpRequestInfo request1; + request1.method = "GET"; + request1.url = url_; + int rv = stream1->InitializeStream(&request1, DEFAULT_PRIORITY, net_log, + CompletionCallback()); + EXPECT_THAT(rv, IsOk()); + + // Send request. + HttpResponseInfo response1; + TestCompletionCallback callback1; + rv = stream1->SendRequest(HttpRequestHeaders(), &response1, + callback1.callback()); + EXPECT_THAT(rv, IsError(ERR_IO_PENDING)); + rv = callback1.WaitForResult(); + EXPECT_THAT(rv, IsOk()); + + // Create and initialize second stream. + // This request must bind to the pushed stream, even though SpdyHttpStream + // constructor is called with kNoPushedStreamFound. + auto stream2 = std::make_unique<SpdyHttpStream>( + session_, kNoPushedStreamFound /* pushed_stream_id */, true, + net_log.source()); + + HttpRequestInfo request2; + request2.method = "GET"; + request2.url = GURL("https://www.example.org/foo.dat"); + rv = stream2->InitializeStream(&request2, DEFAULT_PRIORITY, net_log, + CompletionCallback()); + EXPECT_THAT(rv, IsOk()); + + // Send request. This should not send out any frames on the wire, because the + // request is served by a pushed stream. + HttpResponseInfo response2; + TestCompletionCallback callback2; + rv = stream2->SendRequest(HttpRequestHeaders(), &response2, + callback2.callback()); + EXPECT_THAT(rv, IsError(ERR_IO_PENDING)); + rv = callback2.WaitForResult(); + EXPECT_THAT(rv, IsOk()); + + // Read response headers for the second request. + rv = stream2->ReadResponseHeaders(callback2.callback()); + EXPECT_THAT(rv, IsOk()); + + // Read response headers for the first request. + rv = stream1->ReadResponseHeaders(callback1.callback()); + EXPECT_THAT(rv, IsError(ERR_IO_PENDING)); + rv = callback1.WaitForResult(); + EXPECT_THAT(rv, IsOk()); + + // Read EOF. + base::RunLoop().RunUntilIdle(); +} + // TODO(willchan): Write a longer test for SpdyStream that exercises all // methods.
diff --git a/net/spdy/chromium/spdy_network_transaction_unittest.cc b/net/spdy/chromium/spdy_network_transaction_unittest.cc index a70b626..edcde944 100644 --- a/net/spdy/chromium/spdy_network_transaction_unittest.cc +++ b/net/spdy/chromium/spdy_network_transaction_unittest.cc
@@ -3030,6 +3030,63 @@ EXPECT_TRUE(data.AllWriteDataConsumed()); } +TEST_F(SpdyNetworkTransactionTest, ServerCancelsPush) { + SpdySerializedFrame req( + spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST, true)); + SpdySerializedFrame priority( + spdy_util_.ConstructSpdyPriority(2, 1, IDLE, true)); + MockWrite writes[] = {CreateMockWrite(req, 0), CreateMockWrite(priority, 3)}; + + SpdySerializedFrame reply(spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1)); + SpdySerializedFrame push(spdy_util_.ConstructSpdyPush( + nullptr, 0, 2, 1, GetDefaultUrlWithPath("/foo.dat").c_str())); + SpdySerializedFrame body(spdy_util_.ConstructSpdyDataFrame(1, true)); + SpdySerializedFrame rst( + spdy_util_.ConstructSpdyRstStream(2, ERROR_CODE_INTERNAL_ERROR)); + MockRead reads[] = {CreateMockRead(reply, 1), CreateMockRead(push, 2), + CreateMockRead(body, 4), CreateMockRead(rst, 5), + MockRead(ASYNC, 0, 6)}; + + SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes)); + + NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr); + helper.RunPreTestSetup(); + helper.AddData(&data); + + // First request to open up connection. + HttpNetworkTransaction* trans1 = helper.trans(); + TestCompletionCallback callback1; + int rv = trans1->Start(&request_, callback1.callback(), log_); + EXPECT_THAT(rv, IsError(ERR_IO_PENDING)); + + // Read until response body arrives. PUSH_PROMISE comes earlier. + rv = callback1.WaitForResult(); + EXPECT_THAT(rv, IsOk()); + HttpResponseInfo response = *trans1->GetResponseInfo(); + EXPECT_TRUE(response.headers); + EXPECT_EQ("HTTP/1.1 200", response.headers->GetStatusLine()); + SpdyString result; + ReadResult(trans1, &result); + EXPECT_EQ("hello!", result); + + // Create request matching pushed stream. + HttpRequestInfo request = CreateGetPushRequest(); + HttpNetworkTransaction trans2(DEFAULT_PRIORITY, helper.session()); + TestCompletionCallback callback2; + rv = trans2.Start(&request, callback2.callback(), log_); + EXPECT_THAT(rv, IsError(ERR_IO_PENDING)); + + // Read RST_STREAM from server closing pushed stream. + rv = callback2.WaitForResult(); + EXPECT_THAT(rv, IsError(ERR_SPDY_PUSHED_STREAM_NOT_AVAILABLE)); + + // Read EOF. + base::RunLoop().RunUntilIdle(); + + EXPECT_TRUE(data.AllReadDataConsumed()); + EXPECT_TRUE(data.AllWriteDataConsumed()); +} + // Regression test for https://crbug.com/727653. TEST_F(SpdyNetworkTransactionTest, RejectServerPushWithNoMethod) { SpdySerializedFrame req(
diff --git a/net/spdy/chromium/spdy_session.cc b/net/spdy/chromium/spdy_session.cc index fac017b..0043b4cb 100644 --- a/net/spdy/chromium/spdy_session.cc +++ b/net/spdy/chromium/spdy_session.cc
@@ -817,20 +817,45 @@ net_log_.EndEvent(NetLogEventType::HTTP2_SESSION); } -int SpdySession::GetPushStream(const GURL& url, - RequestPriority priority, - SpdyStream** stream, - const NetLogWithSource& stream_net_log) { +int SpdySession::GetPushedStream(const GURL& url, + SpdyStreamId pushed_stream_id, + RequestPriority priority, + SpdyStream** stream, + const NetLogWithSource& stream_net_log) { CHECK(!in_io_loop_); + *stream = nullptr; + if (availability_state_ == STATE_DRAINING) { - *stream = nullptr; return ERR_CONNECTION_CLOSED; } - *stream = GetActivePushStream(url); - if (!*stream) - return OK; + if (pushed_stream_id == kNoPushedStreamFound) { + // Even if no pushed stream has been claimed earlier, there could still be + // one corresponding the request, if the scheme is http (those pushes are + // not considered by Http2PushPromiseIndex::ClaimPushedStream()), or if the + // pushed stream was opened in the meanwhile. + pushed_stream_id = pool_->push_promise_index()->FindStream(url, this); + if (pushed_stream_id == kNoPushedStreamFound) + return OK; + + LogPushStreamClaimed(url, pushed_stream_id); + const bool success = + pool_->push_promise_index()->UnregisterUnclaimedPushedStream( + url, pushed_stream_id, this); + DCHECK(success); + } + + DCHECK_GT(pushed_stream_id, kNoPushedStreamFound); + + ActiveStreamMap::iterator active_it = active_streams_.find(pushed_stream_id); + if (active_it == active_streams_.end()) { + // A previously claimed pushed stream might not be available, for example, + // if the server has reset it in the meanwhile. + return ERR_SPDY_PUSHED_STREAM_NOT_AVAILABLE; + } + + *stream = active_it->second; DCHECK_LT(streams_pushed_and_claimed_count_, streams_pushed_count_); streams_pushed_and_claimed_count_++; @@ -2374,28 +2399,6 @@ } } -SpdyStream* SpdySession::GetActivePushStream(const GURL& url) { - const SpdyStreamId stream_id = - pool_->push_promise_index()->FindStream(url, this); - if (stream_id == kNoPushedStreamFound) - return nullptr; - - const bool result = - pool_->push_promise_index()->UnregisterUnclaimedPushedStream( - url, stream_id, this); - DCHECK(result); - - ActiveStreamMap::iterator active_it = active_streams_.find(stream_id); - if (active_it == active_streams_.end()) { - NOTREACHED(); - return nullptr; - } - - LogPushStreamClaimed(url, stream_id); - - return active_it->second; -} - void SpdySession::RecordPingRTTHistogram(base::TimeDelta duration) { UMA_HISTOGRAM_CUSTOM_TIMES("Net.SpdyPing.RTT", duration, base::TimeDelta::FromMilliseconds(1),
diff --git a/net/spdy/chromium/spdy_session.h b/net/spdy/chromium/spdy_session.h index 101ba98..17cf4e0d 100644 --- a/net/spdy/chromium/spdy_session.h +++ b/net/spdy/chromium/spdy_session.h
@@ -284,12 +284,22 @@ // reset). Returns an error (not ERR_IO_PENDING) otherwise, and // resets |spdy_stream|. // + // If |pushed_stream_id != kNoPushedStreamFound|, then the pushed stream with + // pushed_stream_id is used. An error is returned if that stream is not + // available. + // + // If |pushed_stream_id == kNoPushedStreamFound|, then any matching pushed + // stream that has not been claimed by another request can be used. This can + // happen, for example, with http scheme pushed streams, or if the pushed + // stream was received from the server in the meanwhile. + // // If a stream was found and the stream is still open, the priority // of that stream is updated to match |priority|. - int GetPushStream(const GURL& url, - RequestPriority priority, - SpdyStream** spdy_stream, - const NetLogWithSource& stream_net_log); + int GetPushedStream(const GURL& url, + SpdyStreamId pushed_stream_id, + RequestPriority priority, + SpdyStream** spdy_stream, + const NetLogWithSource& stream_net_log); // Called when the pushed stream should be cancelled. If the pushed stream is // not claimed and active, sends RST to the server to cancel the stream. @@ -695,11 +705,6 @@ // that |stream| may hold the last reference to the session. void DeleteStream(std::unique_ptr<SpdyStream> stream, int status); - // Check if we have a pending pushed-stream for this url - // Returns the stream if found (and returns it from the pending - // list). Returns NULL otherwise. - SpdyStream* GetActivePushStream(const GURL& url); - void RecordPingRTTHistogram(base::TimeDelta duration); void RecordHistograms(); void RecordProtocolErrorHistogram(SpdyProtocolErrorDetails details);
diff --git a/net/spdy/chromium/spdy_session_key.cc b/net/spdy/chromium/spdy_session_key.cc index 6395af71..be206e5 100644 --- a/net/spdy/chromium/spdy_session_key.cc +++ b/net/spdy/chromium/spdy_session_key.cc
@@ -12,8 +12,7 @@ namespace net { -SpdySessionKey::SpdySessionKey() : privacy_mode_(PRIVACY_MODE_DISABLED) { -} +SpdySessionKey::SpdySessionKey() = default; SpdySessionKey::SpdySessionKey(const HostPortPair& host_port_pair, const ProxyServer& proxy_server, @@ -25,15 +24,6 @@ << ", privacy=" << privacy_mode; } -SpdySessionKey::SpdySessionKey(const HostPortProxyPair& host_port_proxy_pair, - PrivacyMode privacy_mode) - : host_port_proxy_pair_(host_port_proxy_pair), - privacy_mode_(privacy_mode) { - DVLOG(1) << "SpdySessionKey(hppp=" << host_port_proxy_pair.first.ToString() - << "," << host_port_proxy_pair.second.ToURI() - << ", privacy=" << privacy_mode; -} - SpdySessionKey::SpdySessionKey(const SpdySessionKey& other) = default; SpdySessionKey::~SpdySessionKey() = default;
diff --git a/net/spdy/chromium/spdy_session_key.h b/net/spdy/chromium/spdy_session_key.h index 61d78194..ef5ac19 100644 --- a/net/spdy/chromium/spdy_session_key.h +++ b/net/spdy/chromium/spdy_session_key.h
@@ -19,10 +19,6 @@ const ProxyServer& proxy_server, PrivacyMode privacy_mode); - // Temporary hack for implicit copy constructor - SpdySessionKey(const HostPortProxyPair& host_port_proxy_pair, - PrivacyMode privacy_mode); - SpdySessionKey(const SpdySessionKey& other); ~SpdySessionKey(); @@ -55,7 +51,7 @@ private: HostPortProxyPair host_port_proxy_pair_; // If enabled, then session cannot be tracked by the server. - PrivacyMode privacy_mode_; + PrivacyMode privacy_mode_ = PRIVACY_MODE_DISABLED; }; } // namespace net
diff --git a/net/spdy/chromium/spdy_session_pool.cc b/net/spdy/chromium/spdy_session_pool.cc index e9536fa..312e581a 100644 --- a/net/spdy/chromium/spdy_session_pool.cc +++ b/net/spdy/chromium/spdy_session_pool.cc
@@ -364,7 +364,8 @@ direct || request->url().SchemeIs(url::kHttpsScheme); request->OnStreamReadyOnPooledConnection( used_ssl_config, used_proxy_info, - std::make_unique<SpdyHttpStream>(spdy_session, use_relative_url, + std::make_unique<SpdyHttpStream>(spdy_session, kNoPushedStreamFound, + use_relative_url, source_dependency)); } }
diff --git a/net/spdy/chromium/spdy_session_unittest.cc b/net/spdy/chromium/spdy_session_unittest.cc index 3e5da06..8adf0cb 100644 --- a/net/spdy/chromium/spdy_session_unittest.cc +++ b/net/spdy/chromium/spdy_session_unittest.cc
@@ -1667,8 +1667,8 @@ EXPECT_EQ(0, session_unacked_recv_window_bytes()); SpdyStream* spdy_stream2; - rv = session_->GetPushStream(pushed_url, MEDIUM, &spdy_stream2, - NetLogWithSource()); + rv = session_->GetPushedStream(pushed_url, kNoPushedStreamFound, MEDIUM, + &spdy_stream2, NetLogWithSource()); ASSERT_THAT(rv, IsOk()); ASSERT_TRUE(spdy_stream2); @@ -5569,8 +5569,8 @@ EXPECT_EQ(0u, num_active_pushed_streams()); SpdyStream* pushed_stream; - int rv = session_->GetPushStream(GURL(kPushedUrl), IDLE, &pushed_stream, - NetLogWithSource()); + int rv = session_->GetPushedStream(GURL(kPushedUrl), kNoPushedStreamFound, + IDLE, &pushed_stream, NetLogWithSource()); ASSERT_THAT(rv, IsOk()); ASSERT_TRUE(pushed_stream); test::StreamDelegateCloseOnHeaders delegate2(pushed_stream->GetWeakPtr()); @@ -5592,6 +5592,113 @@ EXPECT_TRUE(data.AllReadDataConsumed()); } +// Test GetPushedStream() behavior with |pushed_stream_id| arguments different +// from kNoPushedStreamFound. +TEST_F(SpdySessionTest, GetPushedStream) { + const char kPushedUrl[] = "https://www.example.org/a.dat"; + SpdyHeaderBlock push_headers; + push_headers[":method"] = "GET"; + spdy_util_.AddUrlToHeaderBlock(kPushedUrl, &push_headers); + SpdySerializedFrame push_promise( + spdy_util_.ConstructInitialSpdyPushFrame(std::move(push_headers), 2, 1)); + SpdySerializedFrame headers_frame( + spdy_util_.ConstructSpdyPushHeaders(2, nullptr, 0)); + MockRead reads[] = { + MockRead(ASYNC, ERR_IO_PENDING, 1), CreateMockRead(push_promise, 2), + MockRead(ASYNC, ERR_IO_PENDING, 4), CreateMockRead(headers_frame, 5), + MockRead(ASYNC, ERR_IO_PENDING, 7), MockRead(ASYNC, 0, 8)}; + + SpdySerializedFrame req( + spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST, true)); + SpdySerializedFrame priority( + spdy_util_.ConstructSpdyPriority(2, 1, IDLE, true)); + SpdySerializedFrame rst( + spdy_util_.ConstructSpdyRstStream(2, ERROR_CODE_CANCEL)); + MockWrite writes[] = {CreateMockWrite(req, 0), CreateMockWrite(priority, 3), + CreateMockWrite(rst, 6)}; + + SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes)); + session_deps_.socket_factory->AddSocketDataProvider(&data); + + AddSSLSocketData(); + + CreateNetworkSession(); + CreateSpdySession(); + + base::WeakPtr<SpdyStream> spdy_stream1 = + CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM, session_, + test_url_, LOWEST, NetLogWithSource()); + ASSERT_TRUE(spdy_stream1); + EXPECT_EQ(0u, spdy_stream1->stream_id()); + test::StreamDelegateDoNothing delegate1(spdy_stream1); + spdy_stream1->SetDelegate(&delegate1); + + EXPECT_EQ(0u, num_active_streams()); + EXPECT_EQ(1u, num_created_streams()); + EXPECT_EQ(0u, num_pushed_streams()); + EXPECT_EQ(0u, num_active_pushed_streams()); + + SpdyHeaderBlock headers(spdy_util_.ConstructGetHeaderBlock(kDefaultUrl)); + spdy_stream1->SendRequestHeaders(std::move(headers), NO_MORE_DATA_TO_SEND); + + // Activate first request. + EXPECT_EQ(0u, delegate1.stream_id()); + base::RunLoop().RunUntilIdle(); + EXPECT_EQ(1u, delegate1.stream_id()); + EXPECT_EQ(1u, num_active_streams()); + EXPECT_EQ(0u, num_created_streams()); + EXPECT_EQ(0u, num_pushed_streams()); + EXPECT_EQ(0u, num_active_pushed_streams()); + + // No streams are pushed yet, therefore GetPushedStream() should return an + // error. + SpdyStream* pushed_stream; + int rv = session_->GetPushedStream(GURL(kPushedUrl), 2 /* pushed_stream_id */, + IDLE, &pushed_stream, NetLogWithSource()); + EXPECT_THAT(rv, IsError(ERR_SPDY_PUSHED_STREAM_NOT_AVAILABLE)); + + // Read PUSH_PROMISE. + data.Resume(); + base::RunLoop().RunUntilIdle(); + EXPECT_EQ(2u, num_active_streams()); + EXPECT_EQ(0u, num_created_streams()); + EXPECT_EQ(1u, num_pushed_streams()); + EXPECT_EQ(0u, num_active_pushed_streams()); + + // GetPushedStream() should return an error if there does not exist a pushed + // stream with ID |pushed_stream_id|. + rv = session_->GetPushedStream(GURL(kPushedUrl), 4 /* pushed_stream_id */, + IDLE, &pushed_stream, NetLogWithSource()); + EXPECT_THAT(rv, IsError(ERR_SPDY_PUSHED_STREAM_NOT_AVAILABLE)); + + // GetPushedStream() should return OK and return the pushed stream in + // |pushed_stream| outparam if |pushed_stream_id| matches. + rv = session_->GetPushedStream(GURL(kPushedUrl), 2 /* pushed_stream_id */, + IDLE, &pushed_stream, NetLogWithSource()); + EXPECT_THAT(rv, IsOk()); + ASSERT_TRUE(pushed_stream); + test::StreamDelegateCloseOnHeaders delegate2(pushed_stream->GetWeakPtr()); + pushed_stream->SetDelegate(&delegate2); + + // Upon reading pushed headers, delegate closes the stream. + data.Resume(); + base::RunLoop().RunUntilIdle(); + EXPECT_EQ(1u, num_active_streams()); + EXPECT_EQ(0u, num_created_streams()); + EXPECT_EQ(0u, num_pushed_streams()); + EXPECT_EQ(0u, num_active_pushed_streams()); + + // Read EOF. + data.Resume(); + base::RunLoop().RunUntilIdle(); + + EXPECT_TRUE(delegate1.StreamIsClosed()); + EXPECT_TRUE(delegate2.StreamIsClosed()); + + EXPECT_TRUE(data.AllWriteDataConsumed()); + EXPECT_TRUE(data.AllReadDataConsumed()); +} + TEST_F(SpdySessionTest, RejectInvalidUnknownFrames) { session_deps_.host_resolver->set_synchronous_mode(true);
diff --git a/net/spdy/chromium/spdy_stream_unittest.cc b/net/spdy/chromium/spdy_stream_unittest.cc index 8f546f81..cf6482d8 100644 --- a/net/spdy/chromium/spdy_stream_unittest.cc +++ b/net/spdy/chromium/spdy_stream_unittest.cc
@@ -344,8 +344,8 @@ data.RunUntilPaused(); SpdyStream* push_stream; - EXPECT_THAT(session->GetPushStream(GURL(kPushUrl), IDLE, &push_stream, - NetLogWithSource()), + EXPECT_THAT(session->GetPushedStream(GURL(kPushUrl), kNoPushedStreamFound, + IDLE, &push_stream, NetLogWithSource()), IsOk()); ASSERT_TRUE(push_stream); EXPECT_EQ(kPushUrl, push_stream->GetUrlFromHeaders().spec()); @@ -657,8 +657,8 @@ data.RunUntilPaused(); SpdyStream* push_stream; - EXPECT_THAT(session->GetPushStream(GURL(kPushUrl), IDLE, &push_stream, - NetLogWithSource()), + EXPECT_THAT(session->GetPushedStream(GURL(kPushUrl), kNoPushedStreamFound, + IDLE, &push_stream, NetLogWithSource()), IsOk()); EXPECT_FALSE(push_stream);
diff --git a/net/test/spawned_test_server/base_test_server.cc b/net/test/spawned_test_server/base_test_server.cc index 4171bbc..75a4cf8 100644 --- a/net/test/spawned_test_server/base_test_server.cc +++ b/net/test/spawned_test_server/base_test_server.cc
@@ -508,6 +508,12 @@ arguments->Set("no-anonymous-ftp-user", std::make_unique<base::Value>()); } + if (redirect_connect_to_localhost_) { + DCHECK_EQ(TYPE_BASIC_AUTH_PROXY, type_); + arguments->Set("redirect-connect-to-localhost", + std::make_unique<base::Value>()); + } + if (UsingSSL(type_)) { // Check the certificate arguments of the HTTPS server. base::FilePath certificate_path(certificates_dir_);
diff --git a/net/test/spawned_test_server/base_test_server.h b/net/test/spawned_test_server/base_test_server.h index a3592ac4..c279b6c 100644 --- a/net/test/spawned_test_server/base_test_server.h +++ b/net/test/spawned_test_server/base_test_server.h
@@ -370,6 +370,11 @@ no_anonymous_ftp_user_ = no_anonymous_ftp_user; } + // Redirect proxied CONNECT requests to localhost. + void set_redirect_connect_to_localhost(bool redirect_connect_to_localhost) { + redirect_connect_to_localhost_ = redirect_connect_to_localhost; + } + // Marks the root certificate of an HTTPS test server as trusted for // the duration of tests. bool LoadTestRootCert() const WARN_UNUSED_RESULT; @@ -454,6 +459,9 @@ // Disable creation of anonymous FTP user? bool no_anonymous_ftp_user_ = false; + // Redirect proxied CONNECT requests to localhost? + bool redirect_connect_to_localhost_ = false; + std::unique_ptr<ScopedPortException> allowed_port_; DISALLOW_COPY_AND_ASSIGN(BaseTestServer);
diff --git a/net/tools/testserver/testserver.py b/net/tools/testserver/testserver.py index 634b41e..0576ac6 100755 --- a/net/tools/testserver/testserver.py +++ b/net/tools/testserver/testserver.py
@@ -1765,6 +1765,7 @@ """ _AUTH_CREDENTIAL = 'Basic Zm9vOmJhcg==' # foo:bar + redirect_connect_to_localhost = False; def parse_request(self): """Overrides parse_request to check credential.""" @@ -1850,6 +1851,9 @@ self.send_response(400) self.end_headers() + if BasicAuthProxyRequestHandler.redirect_connect_to_localhost: + host = "127.0.0.1" + try: sock = socket.create_connection((host, port)) self.send_response(200, 'Connection established') @@ -2108,6 +2112,8 @@ print 'Echo UDP server started on port %d...' % server.server_port server_data['port'] = server.server_port elif self.options.server_type == SERVER_BASIC_AUTH_PROXY: + BasicAuthProxyRequestHandler.redirect_connect_to_localhost = \ + self.options.redirect_connect_to_localhost server = HTTPServer((host, port), BasicAuthProxyRequestHandler) print 'BasicAuthProxy server started on port %d...' % server.server_port server_data['port'] = server.server_port @@ -2323,6 +2329,12 @@ action='store_true') self.option_parser.add_option('--token-binding-params', action='append', default=[], type='int') + self.option_parser.add_option('--redirect-connect-to-localhost', + dest='redirect_connect_to_localhost', + default=False, action='store_true', + help='If set, the Proxy server will connect ' + 'to localhost instead of the requested URL ' + 'on CONNECT requests') if __name__ == '__main__':
diff --git a/net/websockets/websocket_end_to_end_test.cc b/net/websockets/websocket_end_to_end_test.cc index 27891f9..d869f83 100644 --- a/net/websockets/websocket_end_to_end_test.cc +++ b/net/websockets/websocket_end_to_end_test.cc
@@ -227,16 +227,7 @@ resolved_proxy_info_.proxy_info = *result; } - void OnTunnelConnectCompleted(const HostPortPair& endpoint, - const HostPortPair& proxy_server, - int net_error) override {} void OnFallback(const ProxyServer& bad_proxy, int net_error) override {} - void OnBeforeTunnelRequest(const HostPortPair& proxy_server, - HttpRequestHeaders* extra_headers) override {} - void OnTunnelHeadersReceived( - const HostPortPair& origin, - const HostPortPair& proxy_server, - const HttpResponseHeaders& response_headers) override {} bool IsTrustedSpdyProxy(const net::ProxyServer& proxy_server) override { return true; }
diff --git a/sandbox/linux/tests/unit_tests.cc b/sandbox/linux/tests/unit_tests.cc index 1b28aa2..515d0ea 100644 --- a/sandbox/linux/tests/unit_tests.cc +++ b/sandbox/linux/tests/unit_tests.cc
@@ -135,16 +135,7 @@ // We need to fork(), so we can't be multi-threaded, as threads could hold // locks. int num_threads = CountThreads(); -#if !defined(THREAD_SANITIZER) const int kNumExpectedThreads = 1; -#else - // Under TSAN, there is a special helper thread. It should be completely - // invisible to our testing, so we ignore it. It should be ok to fork() - // with this thread. It's currently buggy, but it's the best we can do until - // there is a way to delay the start of the thread - // (https://code.google.com/p/thread-sanitizer/issues/detail?id=19). - const int kNumExpectedThreads = 2; -#endif // The kernel is at liberty to wake a thread id futex before updating /proc. // If another test running in the same process has stopped a thread, it may
diff --git a/services/network/BUILD.gn b/services/network/BUILD.gn new file mode 100644 index 0000000..ac126434 --- /dev/null +++ b/services/network/BUILD.gn
@@ -0,0 +1,38 @@ +# Copyright 2017 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +import("//mojo/public/tools/bindings/mojom.gni") + +static_library("network_service") { + sources = [ + "cookie_manager.cc", + "cookie_manager.h", + ] + + deps = [ + "//base", + "//mojo/public/cpp/bindings", + "//net", + "//services/network/public/interfaces", + "//url", + ] +} + +source_set("tests") { + testonly = true + + sources = [ + "cookie_manager_unittest.cc", + ] + + deps = [ + "//base", + "//mojo/public/cpp/bindings", + "//net", + "//net:test_support", + "//services/network:network_service", + "//services/network/public/interfaces", + "//testing/gtest", + ] +}
diff --git a/content/network/cookie_manager.cc b/services/network/cookie_manager.cc similarity index 86% rename from content/network/cookie_manager.cc rename to services/network/cookie_manager.cc index 3214409..0012abb 100644 --- a/content/network/cookie_manager.cc +++ b/services/network/cookie_manager.cc
@@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "content/network/cookie_manager.h" +#include "services/network/cookie_manager.h" #include "net/base/registry_controlled_domains/registry_controlled_domain.h" #include "net/cookies/canonical_cookie.h" @@ -10,7 +10,7 @@ #include "net/cookies/cookie_options.h" #include "url/gurl.h" -namespace content { +namespace network { namespace { @@ -195,8 +195,9 @@ cookie_store_->DeleteAllCreatedBetweenWithPredicateAsync( start_time, end_time, - base::Bind(&PredicateWrapper::Predicate, - std::make_unique<PredicateWrapper>(std::move(filter))), + base::BindRepeating( + &PredicateWrapper::Predicate, + std::make_unique<PredicateWrapper>(std::move(filter))), std::move(callback)); } @@ -211,17 +212,18 @@ notification_registration->subscription = cookie_store_->AddCallbackForCookie( url, name, - base::Bind(&CookieManager::CookieChanged, - // base::Unretained is safe as destruction of the - // CookieManager will also destroy the - // notifications_registered list (which this object will be - // inserted into, below), which will destroy the - // CookieChangedSubscription, unregistering the callback. - base::Unretained(this), - // base::Unretained is safe as destruction of the - // NotificationRegistration will also destroy the - // CookieChangedSubscription, unregistering the callback. - base::Unretained(notification_registration.get()))); + base::BindRepeating( + &CookieManager::CookieChanged, + // base::Unretained is safe as destruction of the + // CookieManager will also destroy the + // notifications_registered list (which this object will be + // inserted into, below), which will destroy the + // CookieChangedSubscription, unregistering the callback. + base::Unretained(this), + // base::Unretained is safe as destruction of the + // NotificationRegistration will also destroy the + // CookieChangedSubscription, unregistering the callback. + base::Unretained(notification_registration.get()))); notification_registration->notification_pointer.set_connection_error_handler( base::BindOnce(&CookieManager::NotificationPipeBroken, @@ -247,18 +249,18 @@ std::move(notification_pointer); notification_registration->subscription = - cookie_store_->AddCallbackForAllChanges( - base::Bind(&CookieManager::CookieChanged, - // base::Unretained is safe as destruction of the - // CookieManager will also destroy the - // notifications_registered list (which this object will be - // inserted into, below), which will destroy the - // CookieChangedSubscription, unregistering the callback. - base::Unretained(this), - // base::Unretained is safe as destruction of the - // NotificationRegistration will also destroy the - // CookieChangedSubscription, unregistering the callback. - base::Unretained(notification_registration.get()))); + cookie_store_->AddCallbackForAllChanges(base::BindRepeating( + &CookieManager::CookieChanged, + // base::Unretained is safe as destruction of the + // CookieManager will also destroy the + // notifications_registered list (which this object will be + // inserted into, below), which will destroy the + // CookieChangedSubscription, unregistering the callback. + base::Unretained(this), + // base::Unretained is safe as destruction of the + // NotificationRegistration will also destroy the + // CookieChangedSubscription, unregistering the callback. + base::Unretained(notification_registration.get()))); notification_registration->notification_pointer.set_connection_error_handler( base::BindOnce(&CookieManager::NotificationPipeBroken, @@ -303,4 +305,4 @@ AddRequest(std::move(new_interface)); } -} // namespace content +} // namespace network
diff --git a/content/network/cookie_manager.h b/services/network/cookie_manager.h similarity index 92% rename from content/network/cookie_manager.h rename to services/network/cookie_manager.h index c623d8e..f2c0139 100644 --- a/content/network/cookie_manager.h +++ b/services/network/cookie_manager.h
@@ -2,29 +2,28 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef CONTENT_NETWORK_COOKIE_MANAGER_H_ -#define CONTENT_NETWORK_COOKIE_MANAGER_H_ +#ifndef SERVICES_NETWORK_COOKIE_MANAGER_H_ +#define SERVICES_NETWORK_COOKIE_MANAGER_H_ #include <memory> #include <string> #include <vector> #include "base/macros.h" -#include "content/common/content_export.h" #include "mojo/public/cpp/bindings/binding_set.h" #include "net/cookies/cookie_store.h" #include "services/network/public/interfaces/cookie_manager.mojom.h" class GURL; -namespace content { +namespace network { // Wrap a cookie store in an implementation of the mojo cookie interface. // This is an IO thread object; all methods on this object must be called on // the IO thread. Note that this does not restrict the locations from which // mojo messages may be sent to the object. -class CONTENT_EXPORT CookieManager : public network::mojom::CookieManager { +class CookieManager : public network::mojom::CookieManager { public: // Construct a CookieService that can serve mojo requests for the underlying // cookie store. |*cookie_store| must outlive this object. @@ -94,6 +93,6 @@ DISALLOW_COPY_AND_ASSIGN(CookieManager); }; -} // namespace content +} // namespace network -#endif // CONTENT_NETWORK_COOKIE_MANAGER_H_ +#endif // SERVICES_NETWORK_COOKIE_MANAGER_H_
diff --git a/content/network/cookie_manager_unittest.cc b/services/network/cookie_manager_unittest.cc similarity index 99% rename from content/network/cookie_manager_unittest.cc rename to services/network/cookie_manager_unittest.cc index b20d180..3f4d1664 100644 --- a/content/network/cookie_manager_unittest.cc +++ b/services/network/cookie_manager_unittest.cc
@@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "content/network/cookie_manager.h" +#include "services/network/cookie_manager.h" #include <algorithm> @@ -35,7 +35,7 @@ // sort cookie list responses from the network::mojom::CookieManager. // * CompareCookiesByValue: As above, but only by value. -namespace content { +namespace network { // Wraps a network::mojom::CookieManager in synchronous, blocking calls to make // it easier to test. @@ -199,7 +199,7 @@ base::MessageLoopForIO message_loop_; net::CookieMonster cookie_monster_; - std::unique_ptr<content::CookieManager> cookie_service_; + std::unique_ptr<CookieManager> cookie_service_; network::mojom::CookieManagerPtr cookie_service_ptr_; std::unique_ptr<SynchronousCookieManager> service_wrapper_; @@ -1799,4 +1799,4 @@ EXPECT_EQ(1u, service()->GetClientsBoundForTesting()); } -} // namespace content +} // namespace network
diff --git a/services/network/public/cpp/proxy_resolving_client_socket.cc b/services/network/public/cpp/proxy_resolving_client_socket.cc index 3646fdf..2e95253 100644 --- a/services/network/public/cpp/proxy_resolving_client_socket.cc +++ b/services/network/public/cpp/proxy_resolving_client_socket.cc
@@ -164,163 +164,6 @@ return net::ERR_IO_PENDING; } -void ProxyResolvingClientSocket::ConnectToProxy(int net_error) { - pac_request_ = NULL; - - DCHECK_NE(net_error, net::ERR_IO_PENDING); - if (net_error == net::OK) { - // Removes unsupported proxies from the list. Currently, this removes - // just the SCHEME_QUIC proxy, which doesn't yet support tunneling. - // TODO(xunjieli): Allow QUIC proxy once it supports tunneling. - proxy_info_.RemoveProxiesWithoutScheme( - net::ProxyServer::SCHEME_DIRECT | net::ProxyServer::SCHEME_HTTP | - net::ProxyServer::SCHEME_HTTPS | net::ProxyServer::SCHEME_SOCKS4 | - net::ProxyServer::SCHEME_SOCKS5); - - if (proxy_info_.is_empty()) { - // No proxies/direct to choose from. This happens when we don't support - // any of the proxies in the returned list. - net_error = net::ERR_NO_SUPPORTED_PROXIES; - } - } - - // TODO(xunjieli): This results in retrying "Direct" twice, because of - // ReconsiderProxyAfterError() path. https://crbug.com/793076. - // Try falling back to a direct connection if we have not tried that before. - if (net_error != net::OK) { - if (!tried_direct_connect_fallback_) { - tried_direct_connect_fallback_ = true; - proxy_info_.UseDirect(); - } else { - CloseTransportSocket(); - base::ResetAndReturn(&user_connect_callback_).Run(net_error); - return; - } - } - - transport_.reset(new net::ClientSocketHandle); - // Now that the proxy is resolved, issue a socket connect. - net::HostPortPair host_port_pair = net::HostPortPair::FromURL(url_); - net_error = net::InitSocketHandleForRawConnect( - host_port_pair, network_session_.get(), proxy_info_, ssl_config_, - ssl_config_, net::PRIVACY_MODE_DISABLED, net_log_, transport_.get(), - base::BindRepeating(&ProxyResolvingClientSocket::ConnectToProxyDone, - base::Unretained(this))); - if (net_error != net::ERR_IO_PENDING) { - // Since this method is always called asynchronously. it is OK to call - // ConnectToProxyDone synchronously. - ConnectToProxyDone(net_error); - } -} - -void ProxyResolvingClientSocket::ConnectToProxyDone(int net_error) { - if (net_error != net::OK) { - // If the connection fails, try another proxy. - net_error = ReconsiderProxyAfterError(net_error); - // ReconsiderProxyAfterError either returns an error (in which case it is - // not reconsidering a proxy) or returns ERR_IO_PENDING if it is considering - // another proxy. - DCHECK_NE(net_error, net::OK); - if (net_error == net::ERR_IO_PENDING) { - // Proxy reconsideration pending. Return. - return; - } - CloseTransportSocket(); - } else { - network_session_->proxy_service()->ReportSuccess(proxy_info_, NULL); - } - base::ResetAndReturn(&user_connect_callback_).Run(net_error); -} - -// TODO(xunjieli): This following method is out of sync with -// HttpStreamFactoryImpl::JobController. The logic should be refactored into a -// common place. -// This method reconsiders the proxy on certain errors. If it does -// reconsider a proxy it always returns ERR_IO_PENDING and posts a call to -// ConnectToProxy with the result of the reconsideration. -int ProxyResolvingClientSocket::ReconsiderProxyAfterError(int error) { - DCHECK(!pac_request_); - DCHECK_NE(error, net::OK); - DCHECK_NE(error, net::ERR_IO_PENDING); - // A failure to resolve the hostname or any error related to establishing a - // TCP connection could be grounds for trying a new proxy configuration. - // - // Why do this when a hostname cannot be resolved? Some URLs only make sense - // to proxy servers. The hostname in those URLs might fail to resolve if we - // are still using a non-proxy config. We need to check if a proxy config - // now exists that corresponds to a proxy server that could load the URL. - // - switch (error) { - case net::ERR_PROXY_CONNECTION_FAILED: - case net::ERR_NAME_NOT_RESOLVED: - case net::ERR_INTERNET_DISCONNECTED: - case net::ERR_ADDRESS_UNREACHABLE: - case net::ERR_CONNECTION_CLOSED: - case net::ERR_CONNECTION_RESET: - case net::ERR_CONNECTION_REFUSED: - case net::ERR_CONNECTION_ABORTED: - case net::ERR_TIMED_OUT: - case net::ERR_TUNNEL_CONNECTION_FAILED: - case net::ERR_SOCKS_CONNECTION_FAILED: - break; - case net::ERR_SOCKS_CONNECTION_HOST_UNREACHABLE: - // Remap the SOCKS-specific "host unreachable" error to a more - // generic error code (this way consumers like the link doctor - // know to substitute their error page). - // - // Note that if the host resolving was done by the SOCSK5 proxy, we can't - // differentiate between a proxy-side "host not found" versus a proxy-side - // "address unreachable" error, and will report both of these failures as - // ERR_ADDRESS_UNREACHABLE. - return net::ERR_ADDRESS_UNREACHABLE; - case net::ERR_PROXY_AUTH_REQUESTED: { - net::ProxyClientSocket* proxy_socket = - static_cast<net::ProxyClientSocket*>(transport_->socket()); - - if (proxy_socket->GetAuthController()->HaveAuth()) { - return proxy_socket->RestartWithAuth( - base::BindRepeating(&ProxyResolvingClientSocket::ConnectToProxyDone, - base::Unretained(this))); - } - return error; - } - default: - return error; - } - - if (proxy_info_.is_https() && ssl_config_.send_client_cert) { - network_session_->ssl_client_auth_cache()->Remove( - proxy_info_.proxy_server().host_port_pair()); - } - - int rv = network_session_->proxy_service()->ReconsiderProxyAfterError( - url_, std::string(), error, &proxy_info_, - base::BindRepeating(&ProxyResolvingClientSocket::ConnectToProxy, - base::Unretained(this)), - &pac_request_, NULL, net_log_); - if (rv == net::OK || rv == net::ERR_IO_PENDING) { - CloseTransportSocket(); - } else { - // If ReconsiderProxyAfterError() failed synchronously, it means - // there was nothing left to fall-back to, so fail the transaction - // with the last connection error we got. - rv = error; - } - - // We either have new proxy info or there was an error in falling back. - // In both cases we want to post ConnectToProxy (in the error case - // we might still want to fall back a direct connection). - if (rv != net::ERR_IO_PENDING) { - base::ThreadTaskRunnerHandle::Get()->PostTask( - FROM_HERE, base::BindOnce(&ProxyResolvingClientSocket::ConnectToProxy, - weak_factory_.GetWeakPtr(), rv)); - // Since we potentially have another try to go (trying the direct connect) - // set the return code code to ERR_IO_PENDING. - rv = net::ERR_IO_PENDING; - } - return rv; -} - void ProxyResolvingClientSocket::Disconnect() { CloseTransportSocket(); if (pac_request_) { @@ -417,10 +260,167 @@ NOTIMPLEMENTED(); } +void ProxyResolvingClientSocket::ConnectToProxy(int net_error) { + pac_request_ = NULL; + + DCHECK_NE(net_error, net::ERR_IO_PENDING); + if (net_error == net::OK) { + // Removes unsupported proxies from the list. Currently, this removes + // just the SCHEME_QUIC proxy, which doesn't yet support tunneling. + // TODO(xunjieli): Allow QUIC proxy once it supports tunneling. + proxy_info_.RemoveProxiesWithoutScheme( + net::ProxyServer::SCHEME_DIRECT | net::ProxyServer::SCHEME_HTTP | + net::ProxyServer::SCHEME_HTTPS | net::ProxyServer::SCHEME_SOCKS4 | + net::ProxyServer::SCHEME_SOCKS5); + + if (proxy_info_.is_empty()) { + // No proxies/direct to choose from. This happens when we don't support + // any of the proxies in the returned list. + net_error = net::ERR_NO_SUPPORTED_PROXIES; + } + } + + // TODO(xunjieli): This results in retrying "Direct" twice, because of + // ReconsiderProxyAfterError() path. https://crbug.com/793076. + // Try falling back to a direct connection if we have not tried that before. + if (net_error != net::OK) { + if (!tried_direct_connect_fallback_) { + tried_direct_connect_fallback_ = true; + proxy_info_.UseDirect(); + } else { + CloseTransportSocket(); + base::ResetAndReturn(&user_connect_callback_).Run(net_error); + return; + } + } + + transport_.reset(new net::ClientSocketHandle); + // Now that the proxy is resolved, issue a socket connect. + net::HostPortPair host_port_pair = net::HostPortPair::FromURL(url_); + net_error = net::InitSocketHandleForRawConnect( + host_port_pair, network_session_.get(), proxy_info_, ssl_config_, + ssl_config_, net::PRIVACY_MODE_DISABLED, net_log_, transport_.get(), + base::BindRepeating(&ProxyResolvingClientSocket::ConnectToProxyDone, + base::Unretained(this))); + if (net_error != net::ERR_IO_PENDING) { + // Since this method is always called asynchronously. it is OK to call + // ConnectToProxyDone synchronously. + ConnectToProxyDone(net_error); + } +} + +void ProxyResolvingClientSocket::ConnectToProxyDone(int net_error) { + if (net_error != net::OK) { + // If the connection fails, try another proxy. + net_error = ReconsiderProxyAfterError(net_error); + // ReconsiderProxyAfterError either returns an error (in which case it is + // not reconsidering a proxy) or returns ERR_IO_PENDING if it is considering + // another proxy. + DCHECK_NE(net_error, net::OK); + if (net_error == net::ERR_IO_PENDING) { + // Proxy reconsideration pending. Return. + return; + } + CloseTransportSocket(); + } else { + network_session_->proxy_service()->ReportSuccess(proxy_info_, NULL); + } + base::ResetAndReturn(&user_connect_callback_).Run(net_error); +} + void ProxyResolvingClientSocket::CloseTransportSocket() { if (transport_.get() && transport_->socket()) transport_->socket()->Disconnect(); transport_.reset(); } +// TODO(xunjieli): This following method is out of sync with +// HttpStreamFactoryImpl::JobController. The logic should be refactored into a +// common place. +// This method reconsiders the proxy on certain errors. If it does +// reconsider a proxy it always returns ERR_IO_PENDING and posts a call to +// ConnectToProxy with the result of the reconsideration. +int ProxyResolvingClientSocket::ReconsiderProxyAfterError(int error) { + DCHECK(!pac_request_); + DCHECK_NE(error, net::OK); + DCHECK_NE(error, net::ERR_IO_PENDING); + // A failure to resolve the hostname or any error related to establishing a + // TCP connection could be grounds for trying a new proxy configuration. + // + // Why do this when a hostname cannot be resolved? Some URLs only make sense + // to proxy servers. The hostname in those URLs might fail to resolve if we + // are still using a non-proxy config. We need to check if a proxy config + // now exists that corresponds to a proxy server that could load the URL. + // + switch (error) { + case net::ERR_PROXY_CONNECTION_FAILED: + case net::ERR_NAME_NOT_RESOLVED: + case net::ERR_INTERNET_DISCONNECTED: + case net::ERR_ADDRESS_UNREACHABLE: + case net::ERR_CONNECTION_CLOSED: + case net::ERR_CONNECTION_RESET: + case net::ERR_CONNECTION_REFUSED: + case net::ERR_CONNECTION_ABORTED: + case net::ERR_TIMED_OUT: + case net::ERR_TUNNEL_CONNECTION_FAILED: + case net::ERR_SOCKS_CONNECTION_FAILED: + break; + case net::ERR_SOCKS_CONNECTION_HOST_UNREACHABLE: + // Remap the SOCKS-specific "host unreachable" error to a more + // generic error code (this way consumers like the link doctor + // know to substitute their error page). + // + // Note that if the host resolving was done by the SOCSK5 proxy, we can't + // differentiate between a proxy-side "host not found" versus a proxy-side + // "address unreachable" error, and will report both of these failures as + // ERR_ADDRESS_UNREACHABLE. + return net::ERR_ADDRESS_UNREACHABLE; + case net::ERR_PROXY_AUTH_REQUESTED: { + net::ProxyClientSocket* proxy_socket = + static_cast<net::ProxyClientSocket*>(transport_->socket()); + + if (proxy_socket->GetAuthController()->HaveAuth()) { + return proxy_socket->RestartWithAuth( + base::BindRepeating(&ProxyResolvingClientSocket::ConnectToProxyDone, + base::Unretained(this))); + } + return error; + } + default: + return error; + } + + if (proxy_info_.is_https() && ssl_config_.send_client_cert) { + network_session_->ssl_client_auth_cache()->Remove( + proxy_info_.proxy_server().host_port_pair()); + } + + int rv = network_session_->proxy_service()->ReconsiderProxyAfterError( + url_, std::string(), error, &proxy_info_, + base::BindRepeating(&ProxyResolvingClientSocket::ConnectToProxy, + base::Unretained(this)), + &pac_request_, NULL, net_log_); + if (rv == net::OK || rv == net::ERR_IO_PENDING) { + CloseTransportSocket(); + } else { + // If ReconsiderProxyAfterError() failed synchronously, it means + // there was nothing left to fall-back to, so fail the transaction + // with the last connection error we got. + rv = error; + } + + // We either have new proxy info or there was an error in falling back. + // In both cases we want to post ConnectToProxy (in the error case + // we might still want to fall back a direct connection). + if (rv != net::ERR_IO_PENDING) { + base::ThreadTaskRunnerHandle::Get()->PostTask( + FROM_HERE, base::BindOnce(&ProxyResolvingClientSocket::ConnectToProxy, + weak_factory_.GetWeakPtr(), rv)); + // Since we potentially have another try to go (trying the direct connect) + // set the return code code to ERR_IO_PENDING. + rv = net::ERR_IO_PENDING; + } + return rv; +} + } // namespace network
diff --git a/services/service_manager/embedder/embedded_service_info.h b/services/service_manager/embedder/embedded_service_info.h index 8a45b244..92880df8 100644 --- a/services/service_manager/embedder/embedded_service_info.h +++ b/services/service_manager/embedder/embedded_service_info.h
@@ -10,6 +10,7 @@ #include "base/callback.h" #include "base/memory/ref_counted.h" #include "base/message_loop/message_loop.h" +#include "base/optional.h" #include "base/single_thread_task_runner.h" #include "base/threading/platform_thread.h" #include "services/service_manager/embedder/service_manager_embedder_export.h" @@ -50,6 +51,12 @@ // If the service uses its own thread, this determines the priority of the // thread. base::ThreadPriority thread_priority = base::ThreadPriority::NORMAL; + + // If set, serves as a hint to the embedding environment that instances of + // this service should share a process with similar instances of any other + // services that are registered with the same group name. Choice of group + // names is arbitrary. + base::Optional<std::string> process_group; }; } // namespace service_manager
diff --git a/testing/buildbot/chromium.android.fyi.json b/testing/buildbot/chromium.android.fyi.json index 574bf65..2061fae 100644 --- a/testing/buildbot/chromium.android.fyi.json +++ b/testing/buildbot/chromium.android.fyi.json
@@ -1728,7 +1728,8 @@ "device_type": "sprout" } ], - "expiration": 14400 + "expiration": 14400, + "hard_timeout": 960 }, "test": "gpu_unittests" }, @@ -4563,7 +4564,8 @@ { "device_type": "coho" } - ] + ], + "hard_timeout": 960 }, "test": "gpu_unittests" }, @@ -5548,7 +5550,8 @@ { "device_type": "gce_x86" } - ] + ], + "hard_timeout": 960 }, "test": "gpu_unittests" },
diff --git a/testing/buildbot/chromium.android.json b/testing/buildbot/chromium.android.json index bbcdd90..793a006 100644 --- a/testing/buildbot/chromium.android.json +++ b/testing/buildbot/chromium.android.json
@@ -1592,6 +1592,7 @@ "device_type": "hammerhead" } ], + "hard_timeout": 960, "output_links": [ { "link": [ @@ -3269,6 +3270,7 @@ "device_type": "hammerhead" } ], + "hard_timeout": 960, "output_links": [ { "link": [ @@ -4887,7 +4889,7 @@ } ], "expiration": 10800, - "hard_timeout": 450, + "hard_timeout": 960, "output_links": [ { "link": [ @@ -7858,7 +7860,7 @@ } ], "expiration": 10800, - "hard_timeout": 450, + "hard_timeout": 960, "output_links": [ { "link": [ @@ -12624,7 +12626,7 @@ } ], "expiration": 10800, - "hard_timeout": 450, + "hard_timeout": 960, "output_links": [ { "link": [
diff --git a/testing/buildbot/chromium.fyi.json b/testing/buildbot/chromium.fyi.json index 0b04d48..3abde81 100644 --- a/testing/buildbot/chromium.fyi.json +++ b/testing/buildbot/chromium.fyi.json
@@ -4392,7 +4392,6 @@ "--mus" ], "name": "ash_unittests-mus", - "override_isolate_target": "ash_unittests", "swarming": { "can_use_on_swarming_builders": true }, @@ -4442,7 +4441,6 @@ "--mus" ], "name": "mus_content_browsertests", - "override_isolate_target": "content_browsertests", "swarming": { "can_use_on_swarming_builders": true, "shards": 2 @@ -4479,6 +4477,16 @@ "test": "keyboard_unittests" }, { + "args": [ + "--mus" + ], + "name": "mus_unit_tests", + "swarming": { + "can_use_on_swarming_builders": true + }, + "test": "unit_tests" + }, + { "swarming": { "can_use_on_swarming_builders": true },
diff --git a/testing/buildbot/chromium.linux.json b/testing/buildbot/chromium.linux.json index 5814644..129cf61 100644 --- a/testing/buildbot/chromium.linux.json +++ b/testing/buildbot/chromium.linux.json
@@ -463,6 +463,53 @@ } ] }, + "test": "mojo_common_unittests" + }, + { + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "kvm": "1" + } + ] + }, + "test": "mojo_public_bindings_unittests" + }, + { + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "kvm": "1" + } + ] + }, + "test": "mojo_public_system_unittests" + }, + { + "args": [ + "--test-launcher-filter-file=../../testing/buildbot/filters/fuchsia.service_manager_unittests.filter" + ], + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "kvm": "1" + } + ] + }, + "test": "service_manager_unittests" + }, + { + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "kvm": "1" + } + ] + }, "test": "skia_unittests" }, { @@ -475,6 +522,20 @@ ] }, "test": "sql_unittests" + }, + { + "args": [ + "--test-launcher-filter-file=../../testing/buildbot/filters/fuchsia.ui_base_unittests.filter" + ], + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "kvm": "1" + } + ] + }, + "test": "ui_base_unittests" } ] },
diff --git a/testing/buildbot/filters/mojo.fyi.network_browser_tests.filter b/testing/buildbot/filters/mojo.fyi.network_browser_tests.filter index ff64ac4..ae9b5e6e 100644 --- a/testing/buildbot/filters/mojo.fyi.network_browser_tests.filter +++ b/testing/buildbot/filters/mojo.fyi.network_browser_tests.filter
@@ -22,9 +22,6 @@ -ChromeSecurityExploitBrowserTest.CreateFilesystemURLInExtensionOrigin -ChromeSitePerProcessTest.LaunchExternalProtocolFromSubframe -ContentFaviconDriverTest.ReloadBypassingCache --ContentVerifierTest.DotSlashPaths --ContentVerifierTest.FailOnDone --ContentVerifierTest.FailOnRead -CredentialManagerBrowserTest.CreatePublicKeyCredentialAlgorithmNotSupported -CredentialManagerBrowserTest.CreatePublicKeyCredentialNotImplemented -CredentialManagerBrowserTest.MojoConnectionRecreatedAfterNavigation @@ -639,10 +636,8 @@ # Switch test from using a custom net::URLRequestFileJob to using a test # URLLoaderFactory via SetNetworkFactoryForTesting. -ErrorPageOfflineTestWithAllowDinosaurFalse.CheckEasterEggIsDisabled --DNSErrorPageTest.Empty404 --DNSErrorPageTest.SniffSmallHttpErrorResponseAsDownload +-ErrorPageSniffTest.SniffSmallHttpErrorResponseAsDownload -DNSErrorPageTest.StaleCacheStatus --DNSErrorPageTest.DNSError_DoClickLink # Switch test from using a net::URLRequestFileJob that adds load timing to # to using a test URLLoaderFactory via SetNetworkFactoryForTesting.
diff --git a/testing/buildbot/test_suite_exceptions.pyl b/testing/buildbot/test_suite_exceptions.pyl index 0fef513..5e04423 100644 --- a/testing/buildbot/test_suite_exceptions.pyl +++ b/testing/buildbot/test_suite_exceptions.pyl
@@ -1913,30 +1913,6 @@ }, }, }, - 'gpu_unittests': { - 'modifications': { - 'KitKat Tablet Tester': { - 'swarming': { - 'hard_timeout': 450, - }, - }, - 'Lollipop Tablet Tester': { - 'swarming': { - 'hard_timeout': 450, - }, - }, - 'Marshmallow Phone Tester (rel)': { - 'swarming': { - 'hard_timeout': 960, - }, - }, - 'Marshmallow Tablet Tester': { - 'swarming': { - 'hard_timeout': 450, - }, - }, - }, - }, 'headless_browsertests': { 'remove_from': [ 'Linux Tests (dbg)(1)(32)', @@ -2451,7 +2427,6 @@ # chromium.linux 'Cast Audio Linux', 'Cast Linux', - 'Fuchsia x64', # chromium.memory 'Linux ASan LSan Tests (1)', 'Linux Chromium OS ASan LSan Tests (1)', @@ -2496,7 +2471,6 @@ # chromium.linux 'Cast Audio Linux', 'Cast Linux', - 'Fuchsia x64', # chromium.memory 'Linux ASan LSan Tests (1)', 'Linux Chromium OS ASan LSan Tests (1)', @@ -2542,7 +2516,6 @@ # chromium.linux 'Cast Audio Linux', 'Cast Linux', - 'Fuchsia x64', # chromium.memory 'Linux ASan LSan Tests (1)', 'Linux Chromium OS ASan LSan Tests (1)', @@ -3039,7 +3012,6 @@ # chromium.linux 'Cast Audio Linux', 'Cast Linux', - 'Fuchsia x64', 'Linux Tests (dbg)(1)(32)', # On chromium.mac, unclear why these aren't run. 'Mac10.10 Tests', @@ -3596,10 +3568,6 @@ }, }, 'ui_base_unittests': { - 'remove_from': [ - # chromium.linux - 'Fuchsia x64', - ], 'modifications': { 'KitKat Tablet Tester': { 'swarming': {
diff --git a/testing/buildbot/test_suites.pyl b/testing/buildbot/test_suites.pyl index e55c16d..040055f 100644 --- a/testing/buildbot/test_suites.pyl +++ b/testing/buildbot/test_suites.pyl
@@ -381,7 +381,11 @@ 'crypto_unittests': {}, 'google_apis_unittests': {}, 'gpu_ipc_service_unittests': {}, - 'gpu_unittests': {}, + 'gpu_unittests': { + 'android_swarming': { + 'hard_timeout': 960, + }, + }, 'ipc_tests': {}, 'jingle_unittests': {}, 'media_blink_unittests': {}, @@ -1121,7 +1125,6 @@ 'args': [ '--mus', ], - 'override_isolate_target': 'ash_unittests', 'test': 'ash_unittests', }, 'mus_browser_tests': { @@ -1139,12 +1142,17 @@ 'args': [ '--mus', ], - 'override_isolate_target': 'content_browsertests', 'swarming': { 'shards': 2, }, 'test': 'content_browsertests', }, + 'mus_unit_tests': { + 'args': [ + '--mus', + ], + 'test': 'unit_tests', + }, }, 'network_service_gtests': { @@ -2224,7 +2232,7 @@ 'viz_fyi_gtests', ], - 'mojo_chromiumos_gtests': [ + 'mojo_chromiumos_fyi_gtests': [ 'aura_non_clang_gtests', 'mash_chromium_gtests', 'mojo_chromiumos_specific_gtests',
diff --git a/testing/buildbot/waterfalls.pyl b/testing/buildbot/waterfalls.pyl index 53499ac3..801e2767 100644 --- a/testing/buildbot/waterfalls.pyl +++ b/testing/buildbot/waterfalls.pyl
@@ -1123,7 +1123,7 @@ 'mash:all', ], 'test_suites': { - 'gtest_tests': 'mojo_chromiumos_gtests', + 'gtest_tests': 'mojo_chromiumos_fyi_gtests', 'isolated_scripts': 'mojo_chromiumos_isolated_scripts', }, },
diff --git a/third_party/WebKit/LayoutTests/TestExpectations b/third_party/WebKit/LayoutTests/TestExpectations index b9eb7e7..0f83eee5 100644 --- a/third_party/WebKit/LayoutTests/TestExpectations +++ b/third_party/WebKit/LayoutTests/TestExpectations
@@ -739,7 +739,7 @@ crbug.com/767269 [ Win ] inspector-protocol/layout-fonts/cjk-ideograph-fallback-by-lang.js [ Pass Failure ] -crbug.com/788110 [ Linux ] inspector-protocol/layout-fonts/unicode-range-combining-chars-fallback.js [ Pass Failure ] +crbug.com/788110 [ Linux Win10 ] inspector-protocol/layout-fonts/unicode-range-combining-chars-fallback.js [ Pass Failure ] # Run these tests with under virtual/scalefactor... only. crbug.com/567837 fast/hidpi/static [ Skip ] @@ -1414,7 +1414,7 @@ crbug.com/665577 virtual/threaded/fast/scroll-behavior/overflow-scroll-root-frame-animates.html [ Pass Timeout ] crbug.com/665577 virtual/threaded/fast/scroll-behavior/smooth-scroll/mousewheel-scroll.html [ Pass Failure ] -crbug.com/665577 [ Linux Win ] virtual/threaded/fast/scroll-behavior/smooth-scroll/mousewheel-scroll-interrupted.html [ Pass Failure ] +crbug.com/665577 [ Linux Win ] virtual/threaded/fast/scroll-behavior/smooth-scroll/mousewheel-scroll-interrupted.html [ Pass Failure Timeout ] crbug.com/665577 [ Linux Win ] virtual/threaded/fast/scroll-behavior/smooth-scroll/track-scroll.html [ Pass Failure ] crbug.com/599670 [ Win ] http/tests/devtools/resource-parameters-ipv6.js [ Timeout Pass ] @@ -1626,21 +1626,8 @@ crbug.com/501659 http/tests/security/xss-DENIED-xml-external-entity.xhtml [ Failure ] crbug.com/501659 fast/css/stylesheet-candidate-nodes-crash.xhtml [ Failure ] -# Mac10.10-specific failures that still need triaging. -# Form controls need rebaseline because of the default font change. -# If you see wider INPUT elements or narrower TEXTAREA elements, you may do just -# rebaseline. See crbug.com/508768#c6 -crbug.com/509025 [ Mac10.10 ] fast/css/css2-system-fonts.html [ Failure ] -crbug.com/509025 [ Mac10.10 ] fast/forms/select/hidden-listbox.html [ Failure ] -crbug.com/509025 [ Mac10.10 ] fast/forms/textarea/textarea-newline.html [ Failure ] - crbug.com/545140 [ Mac10.10 Mac10.11 Retina Mac10.12 ] fast/encoding/denormalised-voiced-japanese-chars.html [ Failure ] -crbug.com/509025 [ Mac10.10 ] fast/events/context-no-deselect.html [ Failure ] -crbug.com/509025 [ Mac10.10 ] virtual/rootlayerscrolls/scrollbars/rtl/overflow-scroll-rtl.html [ Failure ] -crbug.com/509025 [ Mac10.10 ] virtual/rootlayerscrolls/scrollbars/short-scrollbar.html [ Failure ] -crbug.com/509025 [ Mac10.10 ] virtual/mouseevent_fractional/fast/events/context-no-deselect.html [ Failure ] - crbug.com/621772 fast/forms/color/color-suggestion-picker-with-scrollbar-appearance.html [ Pass Failure ] crbug.com/652995 fast/forms/text/input-text-scroll-left-on-blur.html [ Pass Failure ] @@ -2477,8 +2464,6 @@ crbug.com/701047 [ Mac10.12 ] editing/style/block-style-003.html [ Failure ] crbug.com/701047 [ Mac10.12 ] editing/style/block-styles-007.html [ Failure ] -crbug.com/735245 http/tests/devtools/application-panel/storage-view-reports-quota.js [ Pass Timeout Failure ] - # [css-grid] crbug.com/659610 fast/css-grid-layout/grid-baseline.html [ Failure ] crbug.com/659610 fast/css-grid-layout/grid-baseline-margins.html [ Failure ] @@ -3009,7 +2994,7 @@ crbug.com/736255 [ Mac ] external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/flexbox/flexbox-baseline-multi-item-vert-001b.html [ Skip ] crbug.com/736732 virtual/enable_wasm/external/wpt/wasm/wasm_local_iframe_test.html [ Timeout Pass ] -crbug.com/798116 [ Linux Win7 ] fast/forms/select/listbox-in-multi-column.html [ Failure Pass ] +crbug.com/798116 [ Win7 ] fast/forms/select/listbox-in-multi-column.html [ Skip ] # These imported tests exercise tens of thousands of code points and generate large results. Marked slow, but still timeout. crbug.com/736056 [ Mac ] external/wpt/encoding/legacy-mb-japanese [ Timeout Pass ] @@ -3183,7 +3168,7 @@ crbug.com/755405 [ Android ] editing/selection/previous-line-position.html [ Failure ] crbug.com/755405 [ Android ] editing/style/block-styles-007.html [ Failure ] crbug.com/755405 [ Android ] fast/backgrounds/background-clip-text.html [ Failure ] -crbug.com/755405 [ Android ] fast/css/child-style-can-override-visited-style.html [ Failure ] +crbug.com/755405 [ Android ] fast/css/child-style-can-override-visited-style.html [ Failure Timeout ] crbug.com/755405 [ Android ] fast/css/clip-zooming.html [ Failure ] crbug.com/755405 [ Android ] fast/css/compare-content-style.html [ Failure ] crbug.com/755405 [ Android ] fast/css/first-letter-hover.html [ Failure ]
diff --git a/third_party/WebKit/LayoutTests/external/WPT_BASE_MANIFEST.json b/third_party/WebKit/LayoutTests/external/WPT_BASE_MANIFEST.json index 02c36ec2..baa92a1 100644 --- a/third_party/WebKit/LayoutTests/external/WPT_BASE_MANIFEST.json +++ b/third_party/WebKit/LayoutTests/external/WPT_BASE_MANIFEST.json
@@ -4855,6 +4855,12 @@ {} ] ], + "uievents/mouse/layout_change_should_fire_mouseover-manual.html": [ + [ + "/uievents/mouse/layout_change_should_fire_mouseover-manual.html", + {} + ] + ], "uievents/mouse/mouseevent_move_button-manual.html": [ [ "/uievents/mouse/mouseevent_move_button-manual.html", @@ -77693,6 +77699,18 @@ {} ] ], + "css/selectors/any-link-dynamic-001.html": [ + [ + "/css/selectors/any-link-dynamic-001.html", + [ + [ + "/css/selectors/any-link-dynamic-001-ref.html", + "==" + ] + ], + {} + ] + ], "css/selectors/focus-within-001.html": [ [ "/css/selectors/focus-within-001.html", @@ -110415,11 +110433,6 @@ {} ] ], - "css/css-multicol/multicol-gap-animation-003-expected.txt": [ - [ - {} - ] - ], "css/css-multicol/multicol-gap-fraction-001-ref.xht": [ [ {} @@ -121860,6 +121873,11 @@ {} ] ], + "css/selectors/any-link-dynamic-001-ref.html": [ + [ + {} + ] + ], "css/selectors/attribute-selectors/attribute-case/resources/semantics-quirks.html": [ [ {} @@ -178306,6 +178324,12 @@ {} ] ], + "hr-time/performance-tojson.html": [ + [ + "/hr-time/performance-tojson.html", + {} + ] + ], "hr-time/test_cross_frame_start.html": [ [ "/hr-time/test_cross_frame_start.html", @@ -190154,6 +190178,12 @@ {} ] ], + "longtask-timing/longtask-tojson.html": [ + [ + "/longtask-timing/longtask-tojson.html", + {} + ] + ], "longtask-timing/shared-renderer/longtask-in-new-window.html": [ [ "/longtask-timing/shared-renderer/longtask-in-new-window.html", @@ -201734,6 +201764,12 @@ {} ] ], + "performance-timeline/performanceentry-tojson.html": [ + [ + "/performance-timeline/performanceentry-tojson.html", + {} + ] + ], "performance-timeline/po-callback-mutate.any.js": [ [ "/performance-timeline/po-callback-mutate.any.html", @@ -210304,6 +210340,12 @@ {} ] ], + "resource-timing/resource-timing-tojson.html": [ + [ + "/resource-timing/resource-timing-tojson.html", + {} + ] + ], "resource-timing/resource-timing.html": [ [ "/resource-timing/resource-timing.html", @@ -268425,10 +268467,6 @@ "5e83250f2f2ff49682eae68056330aa3b4c673c7", "testharness" ], - "css/css-multicol/multicol-gap-animation-003-expected.txt": [ - "697b921d83c68c5ec34ad0fef1de9bcf20555024", - "support" - ], "css/css-multicol/multicol-gap-animation-003.html": [ "6d5c81b2277c34bac89e8cde247dd9aabbdd505f", "testharness" @@ -292773,6 +292811,14 @@ "b45da5560d0eb821b5552f1b67fab5cead4508b1", "support" ], + "css/selectors/any-link-dynamic-001-ref.html": [ + "342d89969da0ca3782efacee0ecbf882c718d6c6", + "support" + ], + "css/selectors/any-link-dynamic-001.html": [ + "c33602e863151182d29afd88a8878374bb118b69", + "reftest" + ], "css/selectors/attribute-selectors/attribute-case/cssom.html": [ "d5e05750213fbf7959125d64e9ea1a26948ba91d", "testharness" @@ -303413,6 +303459,10 @@ "4aef47650d5cbc750393c3ac9423dbff24a15917", "testharness" ], + "hr-time/performance-tojson.html": [ + "2d45889944dab7b0489a03a649a70e1177bca428", + "testharness" + ], "hr-time/resources/now_frame.html": [ "031edb78f5ab21f51005fdb30a99a605669254ce", "support" @@ -323033,6 +323083,10 @@ "e9c7f9671fba6eba939a3241bbddffb2a6c2bb13", "testharness" ], + "longtask-timing/longtask-tojson.html": [ + "c80d01bb7d3825dbdad09137b47ab4e5327f7fbf", + "testharness" + ], "longtask-timing/resources/makelongtask.js": [ "64401c9b936a3a1bb43744d821258d43628819ca", "support" @@ -332381,6 +332435,10 @@ "30e6893af2cda301efb45fa7cfe16cec04701445", "testharness" ], + "performance-timeline/performanceentry-tojson.html": [ + "bc8a6f3fb13af9df11781a21b96f342e7d7ddf4e", + "testharness" + ], "performance-timeline/performanceobservers.js": [ "0faeecf506da5b8a5c722a1ce8c7b5854227bca0", "support" @@ -340885,6 +340943,10 @@ "b15a57e2eee61f2748bf758e6f3e06e84234f1e3", "support" ], + "resource-timing/resource-timing-tojson.html": [ + "643ce44bcf4a279853f07bde1abb376314e0b3bf", + "testharness" + ], "resource-timing/resource-timing.html": [ "eb3e3064aa55df9ce9a0679a51d0b01d2fb63422", "testharness" @@ -346429,6 +346491,10 @@ "6b1d7bce96ca023959d5248aa8af0aa83c6d3aa5", "testharness" ], + "uievents/mouse/layout_change_should_fire_mouseover-manual.html": [ + "4e96209d99278b974347c6bd636454b0e7daf3c4", + "manual" + ], "uievents/mouse/mouseevent_move_button-manual.html": [ "9cc673035fef3c2e8677e8d6679babfe8a1af854", "manual"
diff --git a/third_party/WebKit/LayoutTests/external/wpt/2dcontext/OWNERS b/third_party/WebKit/LayoutTests/external/wpt/2dcontext/OWNERS index 14ca7d4e..3b83b67 100644 --- a/third_party/WebKit/LayoutTests/external/wpt/2dcontext/OWNERS +++ b/third_party/WebKit/LayoutTests/external/wpt/2dcontext/OWNERS
@@ -1,2 +1,3 @@ # TEAM: paint-dev@chromium.org # COMPONENT: Blink>Canvas +# WPT-NOTIFY: true \ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/external/wpt/background-fetch/OWNERS b/third_party/WebKit/LayoutTests/external/wpt/background-fetch/OWNERS index f4dc67b..6b3427b 100644 --- a/third_party/WebKit/LayoutTests/external/wpt/background-fetch/OWNERS +++ b/third_party/WebKit/LayoutTests/external/wpt/background-fetch/OWNERS
@@ -1 +1,5 @@ file://third_party/WebKit/Source/modules/background_fetch/OWNERS + +# TEAM: platform-capabilities@chromium.org +# COMPONENT: Blink>BackgroundFetch +# WPT-NOTIFY: true
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-transforms/OWNERS b/third_party/WebKit/LayoutTests/external/wpt/css/css-transforms/OWNERS index 2c3d32a..e090a5a 100644 --- a/third_party/WebKit/LayoutTests/external/wpt/css/css-transforms/OWNERS +++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-transforms/OWNERS
@@ -1,2 +1,3 @@ # TEAM: paint-dev@chromium.org # COMPONENT: Blink>Transforms +# WPT-NOTIFY: true \ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/geometry/OWNERS b/third_party/WebKit/LayoutTests/external/wpt/css/geometry/OWNERS index f850950..b788e32 100644 --- a/third_party/WebKit/LayoutTests/external/wpt/css/geometry/OWNERS +++ b/third_party/WebKit/LayoutTests/external/wpt/css/geometry/OWNERS
@@ -1,5 +1,6 @@ # TEAM: paint-dev@chromium.org # COMPONENT: Blink>Geometry +# WPT-NOTIFY: true xlai@chromium.org jinho.bang@samsung.com hs1217.lee@samsung.com
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/selectors/any-link-dynamic-001-ref.html b/third_party/WebKit/LayoutTests/external/wpt/css/selectors/any-link-dynamic-001-ref.html new file mode 100644 index 0000000..b540742 --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/css/selectors/any-link-dynamic-001-ref.html
@@ -0,0 +1,10 @@ +<!DOCTYPE html> +<meta charset="utf-8"> +<title>CSS test reference</title> +<link rel="author" title="Boris Zbarsky" href="mailto:bzbarsky@mit.edu"> +<style> + span { color: green; } +</style> +<body> + <a></a><span>This should be green</span> +</body>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/selectors/any-link-dynamic-001.html b/third_party/WebKit/LayoutTests/external/wpt/css/selectors/any-link-dynamic-001.html new file mode 100644 index 0000000..e84989f --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/css/selectors/any-link-dynamic-001.html
@@ -0,0 +1,14 @@ +<!DOCTYPE html> +<meta charset="utf-8"> +<title>CSS test: Handling of dynamic changes to :any-link selectors</title> +<link rel="author" title="Boris Zbarsky" href="mailto:bzbarsky@mit.edu"> +<link rel="match" href="any-link-dynamic-001-ref.html"> +<link rel="help" href="https://drafts.csswg.org/selectors-4/#the-any-link-pseudo"> +<style> + span { color: green; } + :any-link + span { color: red; } +</style> +<body onload="window.oldColor = getComputedStyle(document.querySelector('span')).color; + document.querySelector('a').removeAttribute('href');"> + <a href=""></a><span>This should be green</span> +</body>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/encrypted-media/OWNERS b/third_party/WebKit/LayoutTests/external/wpt/encrypted-media/OWNERS index 72726ec..96cb6024 100644 --- a/third_party/WebKit/LayoutTests/external/wpt/encrypted-media/OWNERS +++ b/third_party/WebKit/LayoutTests/external/wpt/encrypted-media/OWNERS
@@ -1 +1,3 @@ +# COMPONENT: Internals>Media>Encrypted +# WPT-NOTIFY: true jrummell@chromium.org
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/media-elements/track/track-element/track-disabled-addcue.html b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/media-elements/track/track-element/track-disabled-addcue.html new file mode 100644 index 0000000..038e6f6 --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/media-elements/track/track-element/track-disabled-addcue.html
@@ -0,0 +1,33 @@ +<!DOCTYPE html> +<title>Adding cues to a disabled text track</title> +<script src="/common/media.js"></script> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script> +async_test(function(t) { + var cueDuration = 0.1; + var video = document.createElement("video"); + var track = video.addTextTrack("subtitles"); + track.mode = "disabled"; + + for (var i = 0; i < 10; ++i) { + var start = i * cueDuration; + var end = start + cueDuration; + track.addCue(new VTTCue(start, end, "Test Cue " + i)); + } + + // Waiting for 2 cue durations to elapse. + video.ontimeupdate = t.step_func(function(event) { + if (event.target.currentTime < (2 * cueDuration)) + return; + + // End test after at least 2 cueDurations to make sure the test + // would have gone through the period where the first 2 cues would + // have been rendered if the track was not disabled. + t.done(); + }); + + video.src = getVideoURI("/media/test"); + video.play(); +}); +</script> \ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/media-elements/track/track-element/track-disabled.html b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/media-elements/track/track-element/track-disabled.html new file mode 100644 index 0000000..d517b9d --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/media-elements/track/track-element/track-disabled.html
@@ -0,0 +1,28 @@ +<!DOCTYPE html> +<title>Disabling a track</title> +<script src="/common/media.js"></script> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<video> + <track kind="subtitles" src="resources/captions.vtt"/> +</video> +<script> +async_test(function(t) { + var video = document.querySelector("video"); + video.textTracks[0].mode = "disabled"; + + // Waiting for the duration of the first cue to elapse. + video.ontimeupdate = t.step_func(function (event) { + if (event.target.currentTime < 1) + return; + + // End test after the duration of the first cue to make sure + // the test would have gone through the period where this cue + // would have been rendered if the track was not disabled. + t.done(); + }); + + video.src = getVideoURI("/media/test"); + video.play(); +}); +</script> \ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/media/track/track-element-dom-change-crash.html b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/media-elements/track/track-element/track-element-dom-change.html similarity index 63% rename from third_party/WebKit/LayoutTests/media/track/track-element-dom-change-crash.html rename to third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/media-elements/track/track-element/track-element-dom-change.html index 277525ec..ff447f3 100644 --- a/third_party/WebKit/LayoutTests/media/track/track-element-dom-change-crash.html +++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/media-elements/track/track-element/track-element-dom-change.html
@@ -1,7 +1,7 @@ <!DOCTYPE html> -<title>Tests that the browser handles simple DOM mutations properly.</title> -<script src="../../resources/testharness.js"></script> -<script src="../../resources/testharnessreport.js"></script> +<title>Simple DOM mutations with track element</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> <script> test(function() { var video = document.createElement("video");
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/media-elements/track/track-element/track-element-src-change-error.html b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/media-elements/track/track-element/track-element-src-change-error.html new file mode 100644 index 0000000..ffc8ec0 --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/media-elements/track/track-element/track-element-src-change-error.html
@@ -0,0 +1,92 @@ +<!DOCTYPE html> +<title>HTMLTrackElement 'src' attribute mutations</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<video> + <track src="resources/settings.vtt" default> + <script> + async_test(function(t) { + var cues = null; + var testTrack = document.querySelector("track"); + var stage = 0; + var timer = null; + function step_onLoad() { + switch (stage) { + case 0: + cues = testTrack.track.cues; + assert_equals(testTrack.readyState, HTMLTrackElement.LOADED, "readyState after first loading of the track"); + assert_equals(cues.length, 4, "Number of cues after first loading of the track"); + ++stage; + testTrack.src = "resources/non-existing-file.vtt"; // this should fail + break; + case 1: + case 3: + case 5: + assert_unreached("'error' event did not fire, stage = " + stage); + break; + case 2: + assert_equals(testTrack.readyState, HTMLTrackElement.LOADED, "readyState after loading of the second track"); + assert_equals(cues.length, 4, "Number of cues after loading of the second track"); + assert_equals(cues[cues.length-1].text, 'I said Bear is coming now!!!! Tab separators.', "Last cue content check"); + ++stage; + testTrack.src = ""; // this should fail + // CuesList will be cleared in the next tick. Spec claims that this should happen immediately, + // but all implementations are doing this asynchronously. + assert_equals(cues.length, 4, "Number of cues immediately after 'src' mutation with the empty URL"); + // This should raise onError event. If no, we'll know about this after some time. + timer = t.step_timeout(t.unreached_func("'error' event is not fired when an empty URL is set"), 100); + break; + case 4: + assert_equals(testTrack.readyState, HTMLTrackElement.LOADED, "readyState after loading of the second track"); + assert_equals(cues.length, 4, "Number of cues after loading of the second track"); + assert_equals(cues[cues.length-1].text, 'I said Bear is coming now!!!! Tab separators.', "Last cue content check"); + ++stage; + testTrack.removeAttribute('src'); + // This should raise onError event, so we'll wait for it for some time + timer = t.step_timeout(t.unreached_func("'error' event is not fired when an empty URL is set"), 100); + break; + default: + assert_unreached("unexpected stage number = " + stage); + break; + } + } + + function step_onError() { + switch (stage) { + case 0: + case 2: + case 4: + assert_unreached("'error' event fired, stage = " + stage); + break; + case 1: + assert_equals(cues, testTrack.track.cues, ".cues object are the same after 'src' attr mutation"); + assert_equals(cues.length, 0, "Number of cues after trying to load non-existing url"); + assert_equals(testTrack.readyState, HTMLTrackElement.ERROR, "readyState after trying to load non-existing url"); + ++stage; + testTrack.src = "resources/settings.vtt"; + break; + case 3: + clearTimeout(timer); + assert_equals(testTrack.readyState, HTMLTrackElement.ERROR, "readyState after setting an empty URL"); + assert_equals(cues, testTrack.track.cues, ".cues object are the same after 'src' attr mutation"); + assert_equals(cues.length, 0, "Number of cues with an empty URL set"); + ++stage; + testTrack.src = "resources/settings.vtt"; + break; + case 5: + clearTimeout(timer); + assert_equals(testTrack.readyState, HTMLTrackElement.ERROR, "readyState after removing 'src' attr"); + assert_equals(cues.length, 0, "Number of cues after removing 'src' attr"); + t.done(); + break; + default: + assert_unreached("unexpected stage number = " + stage); + break; + } + } + + testTrack.onload = t.step_func(step_onLoad); + testTrack.onerror = t.step_func(step_onError); + }); + </script> +</video> \ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/media-elements/track/track-element/track-element-src-change.html b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/media-elements/track/track-element/track-element-src-change.html new file mode 100644 index 0000000..34a53d15 --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/media-elements/track/track-element/track-element-src-change.html
@@ -0,0 +1,57 @@ +<!DOCTYPE html> +<title>HTMLTrackElement 'src' attribute mutations</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<video> + <track src="resources/settings.vtt" default> + <script> + async_test(function(t) { + var cues = null; + var testTrack = document.querySelector("track"); + var stage = 0; + function step_onLoad() { + switch (stage) { + case 0: + cues = testTrack.track.cues; + assert_equals(testTrack.readyState, HTMLTrackElement.LOADED, "readyState after first loading of the track"); + assert_equals(cues.length, 4, "Number of cues after first loading of the track"); + assert_equals(cues[cues.length-1].text, 'I said Bear is coming now!!!! Tab separators.', "Last cue content check"); + ++stage; + testTrack.src = "resources/entities.vtt"; + // CuesList will be cleared in a microtask. Spec claims that this should happen immediately, + // but all known implementations are doing this asynchronously. + assert_equals(cues.length, 4, "Number of cues immediately after 'src' mutation with the new URL"); + break; + case 1: + assert_equals(testTrack.readyState, HTMLTrackElement.LOADED), "readyState after loading of the second track"; + assert_equals(cues, testTrack.track.cues, ".cues object are the same after 'src' attr mutation"); + assert_equals(cues.length, 7, "Number of cues after loading of the second track"); + assert_equals(cues[cues.length-1].text, 'This & is parsed to the same as &.', "Last cue content check"); + ++stage; + testTrack.src = "resources/settings.vtt"; + break; + case 2: + assert_equals(testTrack.readyState, HTMLTrackElement.LOADED, "readyState after after loading of the first track again"); + assert_equals(cues[cues.length-1].text, 'I said Bear is coming now!!!! Tab separators.', "Last cue content check"); + assert_equals(cues, testTrack.track.cues, ".cues object are the same after 'src' attr mutation"); + assert_equals(cues.length, 4, "Number of cues after loading of the first track"); + ++stage; + testTrack.src = "resources/settings.vtt"; + // This should not raise onLoad or onError event, so we'll wait for it for some time + t.step_timeout(t.step_func_done(function() { + assert_equals(testTrack.readyState, HTMLTrackElement.LOADED, "readyState after changing 'src' to the same value"); + assert_equals(cues, testTrack.track.cues, ".cues object are the same after 'src' attr mutation"); + assert_equals(cues.length, 4, "Number of cues after changing 'src' to the same value"); + }, 100)); + break; + case 3: + assert_unreached("'load' event should not fire, stage = " + stage); + break; + } + } + + testTrack.onload = t.step_func(step_onLoad); + testTrack.onerror = t.unreached_func("'error' event should not fire"); + }); + </script> +</video> \ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/external/wpt/imagebitmap-renderingcontext/OWNERS b/third_party/WebKit/LayoutTests/external/wpt/imagebitmap-renderingcontext/OWNERS index 14ca7d4e..3b83b67 100644 --- a/third_party/WebKit/LayoutTests/external/wpt/imagebitmap-renderingcontext/OWNERS +++ b/third_party/WebKit/LayoutTests/external/wpt/imagebitmap-renderingcontext/OWNERS
@@ -1,2 +1,3 @@ # TEAM: paint-dev@chromium.org # COMPONENT: Blink>Canvas +# WPT-NOTIFY: true \ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/external/wpt/images/OWNERS b/third_party/WebKit/LayoutTests/external/wpt/images/OWNERS index 990a4f1..6640d0e 100644 --- a/third_party/WebKit/LayoutTests/external/wpt/images/OWNERS +++ b/third_party/WebKit/LayoutTests/external/wpt/images/OWNERS
@@ -1,2 +1,3 @@ # TEAM: paint-dev@chromium.org # COMPONENT: Blink>Image +# WPT-NOTIFY: true \ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/external/wpt/notifications/OWNERS b/third_party/WebKit/LayoutTests/external/wpt/notifications/OWNERS index 1c13657..b47764966 100644 --- a/third_party/WebKit/LayoutTests/external/wpt/notifications/OWNERS +++ b/third_party/WebKit/LayoutTests/external/wpt/notifications/OWNERS
@@ -1 +1,5 @@ +file://third_party/WebKit/Source/modules/notifications/OWNERS + # TEAM: platform-capabilities@chromium.org +# COMPONENT: UI>Notifications +# WPT-NOTIFY: true
diff --git a/third_party/WebKit/LayoutTests/external/wpt/offscreen-canvas/OWNERS b/third_party/WebKit/LayoutTests/external/wpt/offscreen-canvas/OWNERS index 14ca7d4e..3b83b67 100644 --- a/third_party/WebKit/LayoutTests/external/wpt/offscreen-canvas/OWNERS +++ b/third_party/WebKit/LayoutTests/external/wpt/offscreen-canvas/OWNERS
@@ -1,2 +1,3 @@ # TEAM: paint-dev@chromium.org # COMPONENT: Blink>Canvas +# WPT-NOTIFY: true \ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/external/wpt/svg/OWNERS b/third_party/WebKit/LayoutTests/external/wpt/svg/OWNERS index 9e4d106..cf0ed9aa 100644 --- a/third_party/WebKit/LayoutTests/external/wpt/svg/OWNERS +++ b/third_party/WebKit/LayoutTests/external/wpt/svg/OWNERS
@@ -1,2 +1,3 @@ # TEAM: paint-dev@chromium.org # COMPONENT: Blink>SVG +# WPT-NOTIFY: true \ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/http/tests/devtools/application-panel/storage-view-reports-quota-expected.txt b/third_party/WebKit/LayoutTests/http/tests/devtools/application-panel/storage-view-reports-quota-expected.txt index c4b54ea..61726d2f4 100644 --- a/third_party/WebKit/LayoutTests/http/tests/devtools/application-panel/storage-view-reports-quota-expected.txt +++ b/third_party/WebKit/LayoutTests/http/tests/devtools/application-panel/storage-view-reports-quota-expected.txt
@@ -2,11 +2,11 @@ Tree element found: true Clear storage view is visible: true -0 B used out of -- storage quota +-- B used out of -- storage quota Usage breakdown: Running: Now with data -9.5 MB used out of -- storage quota +-- KB used out of -- storage quota Usage breakdown: -IndexedDB: 9.5 MB +IndexedDB: --.- KB
diff --git a/third_party/WebKit/LayoutTests/http/tests/devtools/application-panel/storage-view-reports-quota.js b/third_party/WebKit/LayoutTests/http/tests/devtools/application-panel/storage-view-reports-quota.js index ce21f4787..d333a7a 100644 --- a/third_party/WebKit/LayoutTests/http/tests/devtools/application-panel/storage-view-reports-quota.js +++ b/third_party/WebKit/LayoutTests/http/tests/devtools/application-panel/storage-view-reports-quota.js
@@ -15,7 +15,7 @@ async function writeArray() { var array = []; - for (var i = 0; i < 5000000; i++) + for (var i = 0; i < 20000; i++) array.push(i % 10); var mainFrameId = TestRunner.resourceTreeModel.mainFrame.id; await new Promise(resolve => ApplicationTestRunner.createDatabase(mainFrameId, 'Database1', resolve)); @@ -38,7 +38,8 @@ }); // Quota will vary between setups, rather strip it altogether var clean = view._quotaRow.innerHTML.replace(/\ /g, ' '); - var quotaStripped = clean.replace(/(.*) \d+ .?B([^\d]*)/, '$1 --$2'); + // Clean usage value because it's platform-dependent. + var quotaStripped = clean.replace(/[\d.]+ (K?B used out of) \d+ .?B([^\d]*)/, '-- $1 --$2'); TestRunner.addResult(quotaStripped); TestRunner.addResult('Usage breakdown:'); @@ -48,8 +49,11 @@ for (var j = 0; j < children.length; j++) { if (children[j].classList.contains('usage-breakdown-legend-title')) typeUsage = children[j].textContent + typeUsage; - if (children[j].classList.contains('usage-breakdown-legend-value')) - typeUsage = typeUsage + children[j].textContent; + if (children[j].classList.contains('usage-breakdown-legend-value')) { + // Clean usage value because it's platform-dependent. + var cleanedValue = children[j].textContent.replace(/\d+.\d\sKB/, '--.- KB'); + typeUsage = typeUsage + cleanedValue; + } } TestRunner.addResult(typeUsage); } @@ -71,7 +75,7 @@ TestRunner.markStep('Now with data'); await writeArray(); - await dumpWhenMatches(clearStorageView, usage => usage > 5000000); + await dumpWhenMatches(clearStorageView, usage => usage > 20000); TestRunner.completeTest(); })();
diff --git a/third_party/WebKit/LayoutTests/http/tests/devtools/extensions/extensions-api-expected.txt b/third_party/WebKit/LayoutTests/http/tests/devtools/extensions/extensions-api-expected.txt index 0cf8c01..a39ed5b3 100644 --- a/third_party/WebKit/LayoutTests/http/tests/devtools/extensions/extensions-api-expected.txt +++ b/third_party/WebKit/LayoutTests/http/tests/devtools/extensions/extensions-api-expected.txt
@@ -1,5 +1,5 @@ -CONSOLE WARNING: line 31: network.onFinished is deprecated. Use network.onRequestFinished instead -CONSOLE WARNING: line 31: webInspector.resources is deprecated. Use webInspector.network instead +CONSOLE WARNING: line 32: network.onFinished is deprecated. Use network.onRequestFinished instead +CONSOLE WARNING: line 32: webInspector.resources is deprecated. Use webInspector.network instead Tests public interface of WebInspector Extensions API Started extension.
diff --git a/third_party/WebKit/LayoutTests/media/track/captions-webvtt/tc022-entities.vtt b/third_party/WebKit/LayoutTests/media/track/captions-webvtt/tc022-entities.vtt deleted file mode 100644 index a8817954..0000000 --- a/third_party/WebKit/LayoutTests/media/track/captions-webvtt/tc022-entities.vtt +++ /dev/null
@@ -1,30 +0,0 @@ -WEBVTT -Cue content with escape characters for &, <, >, LRM, RLM and non-breaking space. - -1 -00:00:00.000 --> 00:00:30.500 align:start position:20% -This cue has an ampersand & character. - -2 -00:00:31.000 --> 00:01:00.500 align:start position:20% -This cue has a less than < character. - -3 -00:01:01.000 --> 00:02:00.500 align:start position:20% -This cue has a greater than > character. - -4 -00:02:01.000 --> 00:02:30.500 align:start position:20% -This cue has a Left-to-Right Mark ‎. - -5 -00:02:31.000 --> 00:03:00.500 align:start position:20% -This cue has a Right-to-Left Mark ‏. - -6 -00:03:01.000 --> 00:03:30.500 align:start position:20% -This cue has a non-breaking space . - -7 -00:03:31.000 --> 00:04:00.500 -This & is parsed to the same as &.
diff --git a/third_party/WebKit/LayoutTests/media/track/track-disabled-addcue.html b/third_party/WebKit/LayoutTests/media/track/track-disabled-addcue.html deleted file mode 100644 index 147eced..0000000 --- a/third_party/WebKit/LayoutTests/media/track/track-disabled-addcue.html +++ /dev/null
@@ -1,34 +0,0 @@ -<!DOCTYPE html> -<title>Test adding cues to a disabled text track. </title> -<script src="../media-file.js"></script> -<script src="../../resources/testharness.js"></script> -<script src="../../resources/testharnessreport.js"></script> -<script> -async_test(function(t) { - var cueDuration = 0.1; - var video = document.createElement("video"); - var track = video.addTextTrack("subtitles"); - track.mode = "disabled"; - - for (var i = 0; i < 10; ++i) { - var start = i * cueDuration; - var end = start + cueDuration; - track.addCue(new VTTCue(start, end, "Test Cue " + i)); - } - - // Waiting for 2 cue durations to elapse. - video.ontimeupdate = t.step_func(function(e) { - if (e.target.currentTime < (2 * cueDuration)) - return; - - // End test after at least 2 cueDurations to make sure the test - // doesn't crash during the period the first 2 cues would have been - // rendered if the track was not disabled. - // 2 cue durations have elapsed. - t.done(); - }); - - video.src = findMediaFile("video", "../content/test"); - video.play(); -}); -</script> \ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/media/track/track-disabled.html b/third_party/WebKit/LayoutTests/media/track/track-disabled.html deleted file mode 100644 index 5b44aa8..0000000 --- a/third_party/WebKit/LayoutTests/media/track/track-disabled.html +++ /dev/null
@@ -1,29 +0,0 @@ -<!DOCTYPE html> -<title>Test disabling a track.</title> -<video> - <track kind="subtitles" src="captions-webvtt/captions.vtt"/> -</video> -<script src="../media-file.js"></script> -<script src="../../resources/testharness.js"></script> -<script src="../../resources/testharnessreport.js"></script> -<script> -async_test(function(t) { - var video = document.querySelector("video"); - video.textTracks[0].mode = "disabled"; - - // Waiting for the duration of the first cue to elapse. - video.ontimeupdate = t.step_func(function (e) { - if (e.target.currentTime < 1) - return; - - // End test after the duration of the first cue to make sure - // the test doesn't crash during the period this cue would - // have been rendered if the track was not disabled. - // The duration of the first cue has elapsed. - t.done(); - }); - - video.src = findMediaFile("video", "../content/test"); - video.play(); -}); -</script> \ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/media/track/track-element-src-change-error-handling.html b/third_party/WebKit/LayoutTests/media/track/track-element-src-change-error-handling.html deleted file mode 100644 index cce06bd0..0000000 --- a/third_party/WebKit/LayoutTests/media/track/track-element-src-change-error-handling.html +++ /dev/null
@@ -1,93 +0,0 @@ - -<!DOCTYPE html> -<title>HTMLTrackElement 'src' attribute mutations</title> -<script src="../../resources/testharness.js"></script> -<script src="../../resources/testharnessreport.js"></script> -<video> - <track src="captions-webvtt/tc013-settings.vtt" default> -</video> -<script> -async_test(function(t) { - var cues = null; - var testTrack = document.querySelector("track"); - var stage = 0; - var timer = null; - function step_onLoad() { - switch (stage) { - case 0: - cues = testTrack.track.cues; - assert_equals(testTrack.readyState, HTMLTrackElement.LOADED, "readyState after first loading of the track"); - assert_equals(cues.length, 4, "Number of cues after first loading of the track"); - ++stage; - testTrack.src = "captions-webvtt/non-existing-file.vtt"; // this should fail - break; - case 1: - case 3: - case 5: - assert_unreached("'error' event did not fire, stage = " + stage); - break; - case 2: - assert_equals(testTrack.readyState, HTMLTrackElement.LOADED, "readyState after loading of the second track"); - assert_equals(cues.length, 4, "Number of cues after loading of the second track"); - assert_equals(cues[cues.length-1].text, 'I said Bear is coming now!!!! Tab separators.', "Last cue content check"); - ++stage; - testTrack.src = ""; // this should fail - // CuesList will be cleared in the next tick. Spec claims that this should happen immediately, - // but all implementations are doing this asynchronously. - assert_equals(cues.length, 4, "Number of cues immediately after 'src' mutation with the empty URL"); - // This should raise onError event. If no, we'll know about this after some time. - timer = t.step_timeout(t.unreached_func("'error' event is not fired when an empty URL is set"), 100); - break; - case 4: - assert_equals(testTrack.readyState, HTMLTrackElement.LOADED, "readyState after loading of the second track"); - assert_equals(cues.length, 4, "Number of cues after loading of the second track"); - assert_equals(cues[cues.length-1].text, 'I said Bear is coming now!!!! Tab separators.', "Last cue content check"); - ++stage; - testTrack.removeAttribute('src'); - // This should raise onError event, so we'll wait for it for some time - timer = t.step_timeout(t.unreached_func("'error' event is not fired when an empty URL is set"), 100); - break; - default: - assert_unreached("unexpected stage number = " + stage); - break; - } - } - - function step_onError() { - switch (stage) { - case 0: - case 2: - case 4: - assert_unreached("'error' event fired, stage = " + stage); - break; - case 1: - assert_equals(cues, testTrack.track.cues, ".cues object are the same after 'src' attr mutation"); - assert_equals(cues.length, 0, "Number of cues after trying to load non-existing url"); - assert_equals(testTrack.readyState, HTMLTrackElement.ERROR, "readyState after trying to load non-existing url"); - ++stage; - testTrack.src = "captions-webvtt/tc013-settings.vtt"; - break; - case 3: - clearTimeout(timer); - assert_equals(testTrack.readyState, HTMLTrackElement.ERROR, "readyState after setting an empty URL"); - assert_equals(cues, testTrack.track.cues, ".cues object are the same after 'src' attr mutation"); - assert_equals(cues.length, 0, "Number of cues with an empty URL set"); - ++stage; - testTrack.src = "captions-webvtt/tc013-settings.vtt"; - break; - case 5: - clearTimeout(timer); - assert_equals(testTrack.readyState, HTMLTrackElement.ERROR, "readyState after removing 'src' attr"); - assert_equals(cues.length, 0, "Number of cues after removing 'src' attr"); - t.done(); - break; - default: - assert_unreached("unexpected stage number = " + stage); - break; - } - } - - testTrack.onload = t.step_func(step_onLoad); - testTrack.onerror = t.step_func(step_onError); -}); -</script> \ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/media/track/track-element-src-change.html b/third_party/WebKit/LayoutTests/media/track/track-element-src-change.html deleted file mode 100644 index 4a09f81..0000000 --- a/third_party/WebKit/LayoutTests/media/track/track-element-src-change.html +++ /dev/null
@@ -1,57 +0,0 @@ -<!DOCTYPE html> -<title>HTMLTrackElement 'src' attribute mutations</title> -<script src="../../resources/testharness.js"></script> -<script src="../../resources/testharnessreport.js"></script> -<video> - <track src="captions-webvtt/tc013-settings.vtt" default> -</video> -<script> -async_test(function(t) { - var cues = null; - var testTrack = document.querySelector("track"); - var stage = 0; - function step_onLoad() { - switch (stage) { - case 0: - cues = testTrack.track.cues; - assert_equals(testTrack.readyState, HTMLTrackElement.LOADED, "readyState after first loading of the track"); - assert_equals(cues.length, 4, "Number of cues after first loading of the track"); - assert_equals(cues[cues.length-1].text, 'I said Bear is coming now!!!! Tab separators.', "Last cue content check"); - ++stage; - testTrack.src = "captions-webvtt/tc022-entities.vtt"; - // CuesList will be cleared in a microtask. Spec claims that this should happen immediately, - // but all known implementations are doing this asynchronously. - assert_equals(cues.length, 4, "Number of cues immediately after 'src' mutation with the new URL"); - break; - case 1: - assert_equals(testTrack.readyState, HTMLTrackElement.LOADED), "readyState after loading of the second track"; - assert_equals(cues, testTrack.track.cues, ".cues object are the same after 'src' attr mutation"); - assert_equals(cues.length, 7, "Number of cues after loading of the second track"); - assert_equals(cues[cues.length-1].text, 'This & is parsed to the same as &.', "Last cue content check"); - ++stage; - testTrack.src = "captions-webvtt/tc013-settings.vtt"; - break; - case 2: - assert_equals(testTrack.readyState, HTMLTrackElement.LOADED, "readyState after after loading of the first track again"); - assert_equals(cues[cues.length-1].text, 'I said Bear is coming now!!!! Tab separators.', "Last cue content check"); - assert_equals(cues, testTrack.track.cues, ".cues object are the same after 'src' attr mutation"); - assert_equals(cues.length, 4, "Number of cues after loading of the first track"); - ++stage; - testTrack.src = "captions-webvtt/tc013-settings.vtt"; - // This should not raise onLoad or onError event, so we'll wait for it for some time - t.step_timeout(t.step_func_done(function() { - assert_equals(testTrack.readyState, HTMLTrackElement.LOADED, "readyState after changing 'src' to the same value"); - assert_equals(cues, testTrack.track.cues, ".cues object are the same after 'src' attr mutation"); - assert_equals(cues.length, 4, "Number of cues after changing 'src' to the same value"); - }, 100)); - break; - case 3: - assert_unreached("'load' event should not fire, stage = " + stage); - break; - } - } - - testTrack.onload = t.step_func(step_onLoad); - testTrack.onerror = t.unreached_func("'error' event should not fire"); -}); -</script> \ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/paint/markers/first-letter.html b/third_party/WebKit/LayoutTests/paint/markers/first-letter.html new file mode 100644 index 0000000..86f4228 --- /dev/null +++ b/third_party/WebKit/LayoutTests/paint/markers/first-letter.html
@@ -0,0 +1,46 @@ +<!DOCTYPE html> +<script src="../../resources/run-after-layout-and-paint.js"></script> +<style> +div:first-letter { + color: red; +} +</style> + +<div id="div">None Composition Spelling TextMatch</div> + +<script> +function addCompositionMarker(elem, start, end) { + const range = document.createRange(); + const textNode = elem.firstChild; + range.setStart(textNode, start); + range.setEnd(textNode, end); + if (typeof internals !== 'undefined') + internals.addCompositionMarker(range, 'orange', 'thin', 'lightBlue'); +}; + +function addSpellingMarker(elem, start, end) { + const range = document.createRange(); + const textNode = elem.firstChild; + range.setStart(textNode, start); + range.setEnd(textNode, end); + if (typeof internals !== 'undefined') + internals.setMarker(document, range, 'spelling'); +}; + +function addTextMatchMarker(elem, start, end) { + const range = document.createRange(); + const textNode = elem.firstChild; + range.setStart(textNode, start); + range.setEnd(textNode, end); + if (typeof internals !== 'undefined') { + internals.addTextMatchMarker(range, 'kActive'); + internals.setMarkedTextMatchesAreHighlighted(document, true); + } +}; + +onload = runAfterLayoutAndPaint(function() { + addCompositionMarker(div, 5, 16); + addSpellingMarker(div, 17, 25); + addTextMatchMarker(div, 26, 35); +}, true); +</script>
diff --git a/third_party/WebKit/LayoutTests/platform/linux/paint/markers/first-letter-expected.png b/third_party/WebKit/LayoutTests/platform/linux/paint/markers/first-letter-expected.png new file mode 100644 index 0000000..687a4d0f88 --- /dev/null +++ b/third_party/WebKit/LayoutTests/platform/linux/paint/markers/first-letter-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/paint/markers/first-letter-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/paint/markers/first-letter-expected.txt new file mode 100644 index 0000000..53221d4 --- /dev/null +++ b/third_party/WebKit/LayoutTests/platform/linux/paint/markers/first-letter-expected.txt
@@ -0,0 +1,11 @@ +layer at (0,0) size 800x600 + LayoutView at (0,0) size 800x600 +layer at (0,0) size 800x36 + LayoutBlockFlow {HTML} at (0,0) size 800x36 + LayoutBlockFlow {BODY} at (8,8) size 784x20 + LayoutBlockFlow {DIV} at (0,0) size 784x20 + LayoutInline {<pseudo:first-letter>} at (0,0) size 12x19 [color=#FF0000] + LayoutTextFragment (anonymous) at (0,0) size 12x19 + text run at (0,0) width 12: "N" + LayoutTextFragment {#text} at (12,0) size 236x19 + text run at (12,0) width 236: "one Composition Spelling TextMatch"
diff --git a/third_party/WebKit/LayoutTests/platform/linux/virtual/spv175/paint/markers/first-letter-expected.png b/third_party/WebKit/LayoutTests/platform/linux/virtual/spv175/paint/markers/first-letter-expected.png new file mode 100644 index 0000000..687a4d0f88 --- /dev/null +++ b/third_party/WebKit/LayoutTests/platform/linux/virtual/spv175/paint/markers/first-letter-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/virtual/spv175/paint/markers/first-letter-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/virtual/spv175/paint/markers/first-letter-expected.txt new file mode 100644 index 0000000..53221d4 --- /dev/null +++ b/third_party/WebKit/LayoutTests/platform/linux/virtual/spv175/paint/markers/first-letter-expected.txt
@@ -0,0 +1,11 @@ +layer at (0,0) size 800x600 + LayoutView at (0,0) size 800x600 +layer at (0,0) size 800x36 + LayoutBlockFlow {HTML} at (0,0) size 800x36 + LayoutBlockFlow {BODY} at (8,8) size 784x20 + LayoutBlockFlow {DIV} at (0,0) size 784x20 + LayoutInline {<pseudo:first-letter>} at (0,0) size 12x19 [color=#FF0000] + LayoutTextFragment (anonymous) at (0,0) size 12x19 + text run at (0,0) width 12: "N" + LayoutTextFragment {#text} at (12,0) size 236x19 + text run at (12,0) width 236: "one Composition Spelling TextMatch"
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mac10.10/fast/events/context-no-deselect-expected.png b/third_party/WebKit/LayoutTests/platform/mac-mac10.10/fast/events/context-no-deselect-expected.png index 62e128e..7305d55 100644 --- a/third_party/WebKit/LayoutTests/platform/mac-mac10.10/fast/events/context-no-deselect-expected.png +++ b/third_party/WebKit/LayoutTests/platform/mac-mac10.10/fast/events/context-no-deselect-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mac10.10/fast/events/context-no-deselect-expected.txt b/third_party/WebKit/LayoutTests/platform/mac-mac10.10/fast/events/context-no-deselect-expected.txt index c2b1ef0..bb54cbd 100644 --- a/third_party/WebKit/LayoutTests/platform/mac-mac10.10/fast/events/context-no-deselect-expected.txt +++ b/third_party/WebKit/LayoutTests/platform/mac-mac10.10/fast/events/context-no-deselect-expected.txt
@@ -5,7 +5,6 @@ LayoutBlockFlow {BODY} at (8,8) size 784x584 LayoutTextControl {INPUT} at (0,0) size 131x19 [bgcolor=#FFFFFF] [border: (2px inset #EEEEEE)] LayoutText {#text} at (0,0) size 0x0 - LayoutText {#text} at (0,0) size 0x0 layer at (11,11) size 125x13 LayoutBlockFlow {DIV} at (3,3) size 125x13 LayoutText {#text} at (0,0) size 89x13
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mac10.10/fast/forms/select/hidden-listbox-expected.txt b/third_party/WebKit/LayoutTests/platform/mac-mac10.10/fast/forms/select/hidden-listbox-expected.txt index 8453bf45..5169a1ca 100644 --- a/third_party/WebKit/LayoutTests/platform/mac-mac10.10/fast/forms/select/hidden-listbox-expected.txt +++ b/third_party/WebKit/LayoutTests/platform/mac-mac10.10/fast/forms/select/hidden-listbox-expected.txt
@@ -7,8 +7,8 @@ text run at (0,0) width 523: "This tests that the whole listbox control is hidden when visibility is set to hidden. " LayoutBR {BR} at (522,14) size 1x0 LayoutText {#text} at (0,0) size 0x0 -hidden layer at (8,26) size 179x59 clip at (9,27) size 166x57 scrollHeight 56 - LayoutListBox {SELECT} at (0,18.25) size 178.84x58.75 [bgcolor=#FFFFFF] [border: (1px solid #999999)] - LayoutBlockFlow {OPTION} at (1,1) size 165.84x14.19 - LayoutText {#text} at (2,0) size 162x13 - text run at (2,0) width 162: "This text should not be visible" +hidden layer at (8,26) size 166x59 clip at (9,27) size 153x57 + LayoutListBox {SELECT} at (0,18) size 165.67x58.75 [bgcolor=#FFFFFF] [border: (1px solid #999999)] + LayoutBlockFlow {OPTION} at (1,1) size 152.67x14.19 + LayoutText {#text} at (2,0) size 149x13 + text run at (2,0) width 149: "This text should not be visible"
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mac10.10/virtual/mouseevent_fractional/fast/events/context-no-deselect-expected.png b/third_party/WebKit/LayoutTests/platform/mac-mac10.10/virtual/mouseevent_fractional/fast/events/context-no-deselect-expected.png new file mode 100644 index 0000000..7305d55 --- /dev/null +++ b/third_party/WebKit/LayoutTests/platform/mac-mac10.10/virtual/mouseevent_fractional/fast/events/context-no-deselect-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mac10.10/virtual/mouseevent_fractional/fast/events/context-no-deselect-expected.txt b/third_party/WebKit/LayoutTests/platform/mac-mac10.10/virtual/mouseevent_fractional/fast/events/context-no-deselect-expected.txt new file mode 100644 index 0000000..bb54cbd --- /dev/null +++ b/third_party/WebKit/LayoutTests/platform/mac-mac10.10/virtual/mouseevent_fractional/fast/events/context-no-deselect-expected.txt
@@ -0,0 +1,13 @@ +layer at (0,0) size 800x600 + LayoutView at (0,0) size 800x600 +layer at (0,0) size 800x600 + LayoutBlockFlow {HTML} at (0,0) size 800x600 + LayoutBlockFlow {BODY} at (8,8) size 784x584 + LayoutTextControl {INPUT} at (0,0) size 131x19 [bgcolor=#FFFFFF] [border: (2px inset #EEEEEE)] + LayoutText {#text} at (0,0) size 0x0 +layer at (11,11) size 125x13 + LayoutBlockFlow {DIV} at (3,3) size 125x13 + LayoutText {#text} at (0,0) size 89x13 + text run at (0,0) width 89: "some sample text" +selection start: position 5 of child 0 {#text} of child 0 {DIV} of {#document-fragment} of child 1 {INPUT} of body +selection end: position 15 of child 0 {#text} of child 0 {DIV} of {#document-fragment} of child 1 {INPUT} of body
diff --git a/third_party/WebKit/LayoutTests/platform/mac/paint/markers/first-letter-expected.png b/third_party/WebKit/LayoutTests/platform/mac/paint/markers/first-letter-expected.png new file mode 100644 index 0000000..c21e7bbd --- /dev/null +++ b/third_party/WebKit/LayoutTests/platform/mac/paint/markers/first-letter-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/paint/markers/first-letter-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/paint/markers/first-letter-expected.txt new file mode 100644 index 0000000..7711ef15 --- /dev/null +++ b/third_party/WebKit/LayoutTests/platform/mac/paint/markers/first-letter-expected.txt
@@ -0,0 +1,11 @@ +layer at (0,0) size 800x600 + LayoutView at (0,0) size 800x600 +layer at (0,0) size 800x34 + LayoutBlockFlow {HTML} at (0,0) size 800x34 + LayoutBlockFlow {BODY} at (8,8) size 784x18 + LayoutBlockFlow {DIV} at (0,0) size 784x18 + LayoutInline {<pseudo:first-letter>} at (0,0) size 12x18 [color=#FF0000] + LayoutTextFragment (anonymous) at (0,0) size 12x18 + text run at (0,0) width 12: "N" + LayoutTextFragment {#text} at (11,0) size 241x18 + text run at (11,0) width 241: "one Composition Spelling TextMatch"
diff --git a/third_party/WebKit/LayoutTests/platform/win/paint/markers/first-letter-expected.png b/third_party/WebKit/LayoutTests/platform/win/paint/markers/first-letter-expected.png new file mode 100644 index 0000000..4c05ea8 --- /dev/null +++ b/third_party/WebKit/LayoutTests/platform/win/paint/markers/first-letter-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/paint/markers/first-letter-expected.txt b/third_party/WebKit/LayoutTests/platform/win/paint/markers/first-letter-expected.txt new file mode 100644 index 0000000..32f1681 --- /dev/null +++ b/third_party/WebKit/LayoutTests/platform/win/paint/markers/first-letter-expected.txt
@@ -0,0 +1,11 @@ +layer at (0,0) size 800x600 + LayoutView at (0,0) size 800x600 +layer at (0,0) size 800x36 + LayoutBlockFlow {HTML} at (0,0) size 800x36 + LayoutBlockFlow {BODY} at (8,8) size 784x20 + LayoutBlockFlow {DIV} at (0,0) size 784x20 + LayoutInline {<pseudo:first-letter>} at (0,0) size 12x19 [color=#FF0000] + LayoutTextFragment (anonymous) at (0,0) size 12x19 + text run at (0,0) width 12: "N" + LayoutTextFragment {#text} at (12,0) size 223x19 + text run at (12,0) width 223: "one Composition Spelling TextMatch"
diff --git a/third_party/WebKit/LayoutTests/typedcssom/cssMatrixComponent.html b/third_party/WebKit/LayoutTests/typedcssom/cssMatrixComponent.html index 3920f6a..d9d1bf0 100644 --- a/third_party/WebKit/LayoutTests/typedcssom/cssMatrixComponent.html +++ b/third_party/WebKit/LayoutTests/typedcssom/cssMatrixComponent.html
@@ -65,10 +65,6 @@ test(() => { assert_equals(matrixComponent.is2D, params.is2D); }, "is2D value is correct for " + params.cssText); - - test(() => { - assert_equals(matrixComponent.toString(), params.cssText); - }, "toString is correct for " + params.cssText); } test(() => {
diff --git a/third_party/WebKit/LayoutTests/typedcssom/cssPerspective.html b/third_party/WebKit/LayoutTests/typedcssom/cssPerspective.html index d7c8a0ea..8ed43658 100644 --- a/third_party/WebKit/LayoutTests/typedcssom/cssPerspective.html +++ b/third_party/WebKit/LayoutTests/typedcssom/cssPerspective.html
@@ -7,12 +7,6 @@ let EPSILON = 1e-6; test(() => { - let perspective = new CSSPerspective(new CSSUnitValue(10, 'px')); - - assert_equals(perspective.toString(), 'perspective(10px)'); -}, "toString should return perspective(<CSSNumericValue.cssString()>)"); - -test(() => { let transformValue = new CSSTransformValue([new CSSPerspective(CSS.em(10))]); assert_throws(new TypeError(), () => { transformValue.toMatrix();
diff --git a/third_party/WebKit/LayoutTests/typedcssom/cssRotation.html b/third_party/WebKit/LayoutTests/typedcssom/cssRotation.html index 8c4ed25..bac1c6b50 100644 --- a/third_party/WebKit/LayoutTests/typedcssom/cssRotation.html +++ b/third_party/WebKit/LayoutTests/typedcssom/cssRotation.html
@@ -111,20 +111,6 @@ }); }, "Invalid arguments to constructor should throw"); -for (let params of testParams) { - test(() => { - assert_equals(params.input.toString(), params.cssText); - }, "toString value is correct for " + params.cssText); -} - -test(() => { - let rotation = new CSSRotation(1, 2, 3, CSS.deg(10)); - assert_equals(rotation.toString(), 'rotate3d(1, 2, 3, 10deg)'); - rotation.is2D = true; - assert_true(rotation.is2D); - assert_equals(rotation.toString(), 'rotate(10deg)'); -}, "x, y, and z components are not included in toString when is2D is true"); - test(() => { // Obtained by doing the following in a console: // $0.style.transform = 'rotate3d(1, 2, 3, 10rad)';
diff --git a/third_party/WebKit/LayoutTests/typedcssom/cssScale.html b/third_party/WebKit/LayoutTests/typedcssom/cssScale.html index d3f6d34..6c88a98 100644 --- a/third_party/WebKit/LayoutTests/typedcssom/cssScale.html +++ b/third_party/WebKit/LayoutTests/typedcssom/cssScale.html
@@ -50,12 +50,6 @@ } ]; -for (let params of testParams) { - test(() => { - assert_equals(params.input.toString(), params.cssText); - }, "toString is correct for " + params.cssText); -} - test(() => { assert_throws(new TypeError(), () => { new CSSScale(); }); assert_throws(new TypeError(), () => { new CSSScale(1); });
diff --git a/third_party/WebKit/LayoutTests/typedcssom/cssSkew.html b/third_party/WebKit/LayoutTests/typedcssom/cssSkew.html deleted file mode 100644 index d224db4..0000000 --- a/third_party/WebKit/LayoutTests/typedcssom/cssSkew.html +++ /dev/null
@@ -1,66 +0,0 @@ -<!DOCTYPE html> -<script src="../resources/testharness.js"></script> -<script src="../resources/testharnessreport.js"></script> -<script src="resources/comparisons.js"></script> - -<script> -var EPSILON = 1e-6; // float epsilon - -function tanUnitValue(unitValue) { - if (unitValue.unit == 'deg') { - var radians = unitValue.value * Math.PI / 180; - return Math.tan(radians); - } - if (unitValue.unit = 'rad') { - return Math.tan(unitValue.value); - } - // We've only used degrees and radians in this test. - throw Error('Test bug: helper function tanUnitValue needs updating.'); -} - -var testParams = [ - { - input: new CSSSkew(new CSSUnitValue(0, 'deg'), new CSSUnitValue(0, 'deg')), - ax: new CSSUnitValue(0, 'deg'), - ay: new CSSUnitValue(0, 'deg'), - cssText: "skew(0deg, 0deg)" - }, - { - input: new CSSSkew(new CSSUnitValue(1, 'deg'), new CSSUnitValue(2, 'deg')), - ax: new CSSUnitValue(1, 'deg'), - ay: new CSSUnitValue(2, 'deg'), - cssText: "skew(1deg, 2deg)"}, - { - input: new CSSSkew(new CSSUnitValue(-2, 'deg'), new CSSUnitValue(-4, 'deg')), - ax: new CSSUnitValue(-2, 'deg'), - ay: new CSSUnitValue(-4, 'deg'), - cssText: "skew(-2deg, -4deg)" - }, - { - input: new CSSSkew( - new CSSUnitValue(3.4, 'deg'), new CSSUnitValue(2.7, 'deg')), - ax: new CSSUnitValue(3.4, 'deg'), - ay: new CSSUnitValue(2.7, 'deg'), - cssText: "skew(3.4deg, 2.7deg)" - }, - { - input: new CSSSkew(new CSSUnitValue(1, 'rad'), new CSSUnitValue(0, 'deg')), - ax: new CSSUnitValue(1, 'rad'), - ay: new CSSUnitValue(0, 'deg'), - cssText: "skew(1rad, 0deg)" - }, - { - input: new CSSSkew(new CSSUnitValue(0, 'deg'), new CSSUnitValue(1, 'rad')), - ax: new CSSUnitValue(0, 'deg'), - ay: new CSSUnitValue(1, 'rad'), - cssText: "skew(0deg, 1rad)" - } -]; - -for (let params of testParams) { - test(() => { - assert_equals(params.input.toString(), params.cssText); - }, "toString is correct for " + params.cssText); -} - -</script>
diff --git a/third_party/WebKit/LayoutTests/typedcssom/cssTranslation.html b/third_party/WebKit/LayoutTests/typedcssom/cssTranslation.html index 9eb5720..1260d3c7 100644 --- a/third_party/WebKit/LayoutTests/typedcssom/cssTranslation.html +++ b/third_party/WebKit/LayoutTests/typedcssom/cssTranslation.html
@@ -47,12 +47,6 @@ }, ]; -for (let params of testParams) { - test(() => { - assert_equals(params.input.toString(), params.cssText); - }, "toString value is correct for " + params.cssText); -} - test(() => { assert_throws(new TypeError(), () => { new CSSTranslation(CSS.px(0), CSS.px(0), CSS.percent(10));
diff --git a/third_party/WebKit/LayoutTests/typedcssom/stylevalue-serialization/cssTransformValue.html b/third_party/WebKit/LayoutTests/typedcssom/stylevalue-serialization/cssTransformValue.html new file mode 100644 index 0000000..d75a3b4 --- /dev/null +++ b/third_party/WebKit/LayoutTests/typedcssom/stylevalue-serialization/cssTransformValue.html
@@ -0,0 +1,115 @@ +<!doctype html> +<meta charset="utf-8"> +<title>IDL-constructed CSSTransformValue serialization tests</title> +<link rel="help" href="https://drafts.css-houdini.org/css-typed-om-1/#positionvalue-serialization"> +<script src="../../resources/testharness.js"></script> +<script src="../../resources/testharnessreport.js"></script> +<script src="../resources/testhelper.js"></script> +<script> +'use strict'; + +const gTestCases = [ + { + value: new CSSTranslation(CSS.percent(1), CSS.px(1)), + cssText: 'translate(1%, 1px)', + desc: 'CSSTranslation with 2 arguments' + }, + { + value: new CSSTranslation(CSS.px(1), CSS.percent(2), CSS.px(3)), + cssText: 'translate3d(1px, 2%, 3px)', + desc: 'CSSTranslation with 3 arguments' + }, + { + value: new CSSScale(CSS.number(2), CSS.number(3)), + cssText: 'scale(2, 3)', + desc: 'CSSScale with 2 arguments' + }, + { + value: new CSSScale(CSS.number(1), CSS.number(2), CSS.number(3)), + cssText: 'scale3d(1, 2, 3)', + desc: 'CSSScale with 3 arguments' + }, + { + value: new CSSRotation(CSS.deg(90)), + cssText: 'rotate(90deg)', + desc: 'CSSRotation with 1 argument' + }, + { + value: new CSSRotation(CSS.number(1), CSS.number(2), CSS.number(3), CSS.deg(90)), + cssText: 'rotate3d(1, 2, 3, 90deg)', + desc: 'CSSRotation with 4 arguments' + }, + { + value: new CSSSkew(CSS.deg(90), CSS.deg(45)), + cssText: 'skew(90deg, 45deg)', + desc: 'CSSSkew' + }, + { + value: new CSSPerspective(CSS.px(1)), + cssText: 'perspective(1px)', + desc: 'CSSPerspective' + }, + { + value: new CSSTransformValue([new CSSPerspective(CSS.px(1))]), + cssText: 'perspective(1px)', + desc: 'CSSTransformValue with a single transform' + }, + { + value: new CSSTransformValue([ + new CSSTranslation(CSS.px(1), CSS.px(0)), + new CSSRotation(CSS.deg(90)), + new CSSPerspective(CSS.px(1)), + new CSSSkew(CSS.deg(90), CSS.deg(45)), + new CSSScale(CSS.number(1), CSS.number(2), CSS.number(3)), + ]), + cssText: 'translate(1px, 0px) rotate(90deg) perspective(1px) skew(90deg, 45deg) scale3d(1, 2, 3)', + desc: 'CSSTransformValue with multiple transforms' + }, + { + value: new CSSTransformValue([ + new CSSTranslation(new CSSMathSum(CSS.px(1), CSS.em(1)), CSS.px(0)), + new CSSRotation(new CSSMathSum(CSS.deg(90), CSS.turn(1))), + new CSSPerspective(new CSSMathSum(CSS.px(1), CSS.em(1))), + new CSSSkew(new CSSMathProduct(CSS.deg(90), 2), new CSSMathProduct(CSS.turn(1), 2)), + new CSSScale( + new CSSMathProduct(CSS.number(1), CSS.number(2)), + new CSSMathSum(CSS.number(1), CSS.number(1)), + new CSSMathProduct(CSS.number(3)) + ), + ]), + cssText: 'translate(calc(1px + 1em), 0px) rotate(calc(90deg + 1turn)) perspective(calc(1px + 1em)) skew(calc(90deg * 2), calc(1turn * 2)) scale3d(calc(1 * 2), calc(1 + 1), calc(3))', + desc: 'CSSTransformValue containing CSSMathValues' + }, + { + value: new CSSMatrixComponent(new DOMMatrixReadOnly([1, 2, 3, 4, 5, 6])), + cssText: 'matrix(1, 2, 3, 4, 5, 6)', + desc: 'CSSMatrixComponent with 6 elements' + }, + { + value: new CSSMatrixComponent(new DOMMatrixReadOnly([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16])), + cssText: 'matrix3d(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16)', + desc: 'CSSMatrixComponent with 16 elements' + }, +]; + +for (const {value, cssText, desc} of gTestCases) { + test(() => { + assert_equals(value.toString(), cssText); + }, desc + ' serializes correctly'); +} + +test(() => { + let result = new CSSTransformValue([ + new CSSTranslation(CSS.px(1), CSS.px(2), CSS.px(3)), + new CSSRotation(1, 2, 3, CSS.deg(90)), + new CSSScale(1, 2, 3), + ]); + + for (const transform of result) { + transform.is2D = true; + } + + assert_equals(result.toString(), 'translate(1px, 2px) rotate(90deg) scale(1, 2)'); +}, 'CSSTransformValue with updated is2D serializes as 2D transforms'); + +</script>
diff --git a/third_party/WebKit/Source/DEPS b/third_party/WebKit/Source/DEPS index 07607a1..8cf10da 100644 --- a/third_party/WebKit/Source/DEPS +++ b/third_party/WebKit/Source/DEPS
@@ -1,6 +1,7 @@ include_rules = [ "+base/callback.h", "+base/callback_forward.h", + "+base/containers/span.h", "+base/debug", "+base/gtest_prod_util.h", "+base/location.h",
diff --git a/third_party/WebKit/Source/bindings/core/v8/serialization/SerializedScriptValue.h b/third_party/WebKit/Source/bindings/core/v8/serialization/SerializedScriptValue.h index ada23e1..6761d245 100644 --- a/third_party/WebKit/Source/bindings/core/v8/serialization/SerializedScriptValue.h +++ b/third_party/WebKit/Source/bindings/core/v8/serialization/SerializedScriptValue.h
@@ -33,6 +33,7 @@ #include <memory> +#include "base/containers/span.h" #include "bindings/core/v8/NativeValueTraits.h" #include "bindings/core/v8/ScriptValue.h" #include "bindings/core/v8/serialization/Transferables.h" @@ -147,8 +148,8 @@ String ToWireString() const; - StringView GetWireData() const { - return StringView(data_buffer_.get(), data_buffer_size_); + base::span<const uint8_t> GetWireData() const { + return {data_buffer_.get(), data_buffer_size_}; } // Deserializes the value (in the current context). Returns a null value in
diff --git a/third_party/WebKit/Source/bindings/core/v8/serialization/SerializedScriptValueTest.cpp b/third_party/WebKit/Source/bindings/core/v8/serialization/SerializedScriptValueTest.cpp index d0f4874d..d16867d 100644 --- a/third_party/WebKit/Source/bindings/core/v8/serialization/SerializedScriptValueTest.cpp +++ b/third_party/WebKit/Source/bindings/core/v8/serialization/SerializedScriptValueTest.cpp
@@ -26,13 +26,12 @@ scope.GetIsolate(), v8OriginalTrue, SerializedScriptValue::SerializeOptions(), ASSERT_NO_EXCEPTION); - StringView wire_data = sourceSerializedScriptValue->GetWireData(); - DCHECK(wire_data.Is8Bit()); + base::span<const uint8_t> wire_data = + sourceSerializedScriptValue->GetWireData(); scoped_refptr<SerializedScriptValue> serializedScriptValue = SerializedScriptValue::Create( - reinterpret_cast<const char*>(wire_data.Characters8()), - wire_data.length()); + reinterpret_cast<const char*>(wire_data.data()), wire_data.length()); v8::Local<v8::Value> deserialized = serializedScriptValue->Deserialize(scope.GetIsolate()); EXPECT_TRUE(deserialized->IsTrue());
diff --git a/third_party/WebKit/Source/bindings/modules/v8/V8BindingForModulesTest.cpp b/third_party/WebKit/Source/bindings/modules/v8/V8BindingForModulesTest.cpp index b86c6069..05134bc 100644 --- a/third_party/WebKit/Source/bindings/modules/v8/V8BindingForModulesTest.cpp +++ b/third_party/WebKit/Source/bindings/modules/v8/V8BindingForModulesTest.cpp
@@ -148,10 +148,9 @@ scoped_refptr<SerializedScriptValue> serialized_value = SerializedScriptValue::Serialize(isolate, value, options, non_throwable_exception_state); - StringView ssv_wire_data = serialized_value->GetWireData(); - DCHECK(ssv_wire_data.Is8Bit()); + base::span<const uint8_t> ssv_wire_data = serialized_value->GetWireData(); DCHECK(wire_bytes->IsEmpty()); - wire_bytes->Append(ssv_wire_data.Characters8(), ssv_wire_data.length()); + wire_bytes->Append(ssv_wire_data.data(), ssv_wire_data.length()); // Sanity check that the serialization header has not changed, as the tests // that use this method rely on the header format.
diff --git a/third_party/WebKit/Source/core/css/cssom/CSSRotation.cpp b/third_party/WebKit/Source/core/css/cssom/CSSRotation.cpp index 4ecbe724..03ab7c9 100644 --- a/third_party/WebKit/Source/core/css/cssom/CSSRotation.cpp +++ b/third_party/WebKit/Source/core/css/cssom/CSSRotation.cpp
@@ -165,8 +165,8 @@ DCHECK(x_->to(CSSPrimitiveValue::UnitType::kNumber)); DCHECK(y_->to(CSSPrimitiveValue::UnitType::kNumber)); DCHECK(z_->to(CSSPrimitiveValue::UnitType::kNumber)); + DCHECK(angle_->to(CSSPrimitiveValue::UnitType::kRadians)); - CSSUnitValue* angle = ToCSSUnitValue(angle_); CSSFunctionValue* result = CSSFunctionValue::Create(is2D() ? CSSValueRotate : CSSValueRotate3d); if (!is2D()) { @@ -180,8 +180,12 @@ result->Append(*y); result->Append(*z); } - result->Append( - *CSSPrimitiveValue::Create(angle->value(), angle->GetInternalUnit())); + + const CSSValue* angle = angle_->ToCSSValue(); + if (!angle) + return nullptr; + + result->Append(*angle); return result; }
diff --git a/third_party/WebKit/Source/core/css/cssom/CSSSkew.cpp b/third_party/WebKit/Source/core/css/cssom/CSSSkew.cpp index d539457e..52463f44 100644 --- a/third_party/WebKit/Source/core/css/cssom/CSSSkew.cpp +++ b/third_party/WebKit/Source/core/css/cssom/CSSSkew.cpp
@@ -88,15 +88,14 @@ } const CSSFunctionValue* CSSSkew::ToCSSValue() const { - // TDOO(meade): Handle calc angles here. - CSSUnitValue* ax = ToCSSUnitValue(ax_); - CSSUnitValue* ay = ToCSSUnitValue(ay_); + const CSSValue* ax = ax_->ToCSSValue(); + const CSSValue* ay = ay_->ToCSSValue(); + if (!ax || !ay) + return nullptr; CSSFunctionValue* result = CSSFunctionValue::Create(CSSValueSkew); - result->Append( - *CSSPrimitiveValue::Create(ax->value(), ax->GetInternalUnit())); - result->Append( - *CSSPrimitiveValue::Create(ay->value(), ay->GetInternalUnit())); + result->Append(*ax); + result->Append(*ay); return result; }
diff --git a/third_party/WebKit/Source/core/dom/Node.cpp b/third_party/WebKit/Source/core/dom/Node.cpp index f16af36..458af6e4 100644 --- a/third_party/WebKit/Source/core/dom/Node.cpp +++ b/third_party/WebKit/Source/core/dom/Node.cpp
@@ -2226,8 +2226,16 @@ if (IsDisabledFormControl(this) && event.IsMouseEvent() && !RuntimeEnabledFeatures::SendMouseEventsDisabledFormControlsEnabled()) { - UseCounter::Count(GetDocument(), - WebFeature::kDispatchMouseEventOnDisabledFormControl); + if (HasEventListeners(event.type())) { + UseCounter::Count(GetDocument(), + WebFeature::kDispatchMouseEventOnDisabledFormControl); + if (event.type() == EventTypeNames::mousedown || + event.type() == EventTypeNames::mouseup) { + UseCounter::Count( + GetDocument(), + WebFeature::kDispatchMouseUpDownEventOnDisabledFormControl); + } + } return; }
diff --git a/third_party/WebKit/Source/core/dom/events/EventPath.cpp b/third_party/WebKit/Source/core/dom/events/EventPath.cpp index 601c648..315c468 100644 --- a/third_party/WebKit/Source/core/dom/events/EventPath.cpp +++ b/third_party/WebKit/Source/core/dom/events/EventPath.cpp
@@ -380,6 +380,15 @@ return false; } +bool EventPath::HasEventListenersInPath(const AtomicString& event_type) const { + for (const auto& context : node_event_contexts_) { + const Node* target_node = context.GetNode(); + if (target_node && target_node->HasEventListeners(event_type)) + return true; + } + return false; +} + NodeEventContext& EventPath::TopNodeEventContext() { DCHECK(!IsEmpty()); return Last();
diff --git a/third_party/WebKit/Source/core/dom/events/EventPath.h b/third_party/WebKit/Source/core/dom/events/EventPath.h index 2ca9e3e..e43d69b55 100644 --- a/third_party/WebKit/Source/core/dom/events/EventPath.h +++ b/third_party/WebKit/Source/core/dom/events/EventPath.h
@@ -80,6 +80,7 @@ void AdjustForTouchEvent(const TouchEvent&); bool DisabledFormControlExistsInPath() const; + bool HasEventListenersInPath(const AtomicString& event_type) const; NodeEventContext& TopNodeEventContext();
diff --git a/third_party/WebKit/Source/core/events/MouseEvent.cpp b/third_party/WebKit/Source/core/events/MouseEvent.cpp index cbf2d02e7..54a89e32 100644 --- a/third_party/WebKit/Source/core/events/MouseEvent.cpp +++ b/third_party/WebKit/Source/core/events/MouseEvent.cpp
@@ -27,6 +27,7 @@ #include "core/frame/LocalDOMWindow.h" #include "core/frame/LocalFrame.h" #include "core/frame/LocalFrameView.h" +#include "core/frame/UseCounter.h" #include "core/input/InputDeviceCapabilities.h" #include "core/layout/LayoutObject.h" #include "core/layout/LayoutView.h" @@ -447,8 +448,19 @@ return dispatcher.Dispatch(); if (!send_to_disabled_form_controls && - IsDisabledFormControl(&dispatcher.GetNode())) + IsDisabledFormControl(&dispatcher.GetNode())) { + if (GetEventPath().HasEventListenersInPath(type())) { + UseCounter::Count(dispatcher.GetNode().GetDocument(), + WebFeature::kDispatchMouseEventOnDisabledFormControl); + if (type() == EventTypeNames::mousedown || + type() == EventTypeNames::mouseup) { + UseCounter::Count( + dispatcher.GetNode().GetDocument(), + WebFeature::kDispatchMouseUpDownEventOnDisabledFormControl); + } + } return DispatchEventResult::kCanceledBeforeDispatch; + } if (type().IsEmpty()) return DispatchEventResult::kNotCanceled; // Shouldn't happen.
diff --git a/third_party/WebKit/Source/core/inspector/InspectorPageAgent.cpp b/third_party/WebKit/Source/core/inspector/InspectorPageAgent.cpp index 5b1707f4..95709ba2 100644 --- a/third_party/WebKit/Source/core/inspector/InspectorPageAgent.cpp +++ b/third_party/WebKit/Source/core/inspector/InspectorPageAgent.cpp
@@ -588,19 +588,6 @@ return Response::OK(); } -Response InspectorPageAgent::navigate(const String& url, - Maybe<String> referrer, - Maybe<String> transitionType, - String* out_frame_id, - Maybe<String>* out_loader_id, - Maybe<String>* errorText) { - LocalFrame* frame = inspected_frames_->Root(); - *out_frame_id = IdentifiersFactory::FrameId(frame); - DocumentLoader* loader = frame->Loader().GetDocumentLoader(); - *out_loader_id = IdentifiersFactory::LoaderId(loader); - return Response::OK(); -} - Response InspectorPageAgent::stopLoading() { return Response::OK(); }
diff --git a/third_party/WebKit/Source/core/inspector/InspectorPageAgent.h b/third_party/WebKit/Source/core/inspector/InspectorPageAgent.h index d8aae489..e2f813b 100644 --- a/third_party/WebKit/Source/core/inspector/InspectorPageAgent.h +++ b/third_party/WebKit/Source/core/inspector/InspectorPageAgent.h
@@ -118,12 +118,6 @@ protocol::Response setLifecycleEventsEnabled(bool) override; protocol::Response reload(Maybe<bool> bypass_cache, Maybe<String> script_to_evaluate_on_load) override; - protocol::Response navigate(const String& url, - Maybe<String> referrer, - Maybe<String> transitionType, - String* frame_id, - Maybe<String>* loader_id, - Maybe<String>* errorText) override; protocol::Response stopLoading() override; protocol::Response setAdBlockingEnabled(bool) override; protocol::Response getResourceTree(
diff --git a/third_party/WebKit/Source/core/inspector/inspector_protocol_config.json b/third_party/WebKit/Source/core/inspector/inspector_protocol_config.json index 810fd76f..a41535d 100644 --- a/third_party/WebKit/Source/core/inspector/inspector_protocol_config.json +++ b/third_party/WebKit/Source/core/inspector/inspector_protocol_config.json
@@ -80,7 +80,7 @@ { "domain": "Page", "exclude": ["getNavigationHistory", "navigateToHistoryEntry", "captureScreenshot", "screencastFrameAck", "handleJavaScriptDialog", "setColorPickerEnabled", - "getAppManifest", "requestAppBanner", "setControlNavigations", "processNavigation", "printToPDF", "bringToFront", "setDownloadBehavior"], + "getAppManifest", "requestAppBanner", "setControlNavigations", "processNavigation", "printToPDF", "bringToFront", "setDownloadBehavior", "navigate"], "async": ["getResourceContent", "searchInResource"], "exclude_events": ["screencastFrame", "screencastVisibilityChanged", "colorPicked", "interstitialShown", "interstitialHidden", "javascriptDialogOpening", "javascriptDialogClosed", "navigationRequested"] },
diff --git a/third_party/WebKit/Source/core/messaging/BlinkCloneableMessageStructTraits.h b/third_party/WebKit/Source/core/messaging/BlinkCloneableMessageStructTraits.h index 1a3b6ff..6abf59f9 100644 --- a/third_party/WebKit/Source/core/messaging/BlinkCloneableMessageStructTraits.h +++ b/third_party/WebKit/Source/core/messaging/BlinkCloneableMessageStructTraits.h
@@ -18,10 +18,7 @@ blink::BlinkCloneableMessage> { static base::span<const uint8_t> encoded_message( blink::BlinkCloneableMessage& input) { - StringView wire_data = input.message->GetWireData(); - return base::make_span( - reinterpret_cast<const uint8_t*>(wire_data.Characters8()), - wire_data.length()); + return input.message->GetWireData(); } static Vector<blink::mojom::blink::SerializedBlobPtr> blobs(
diff --git a/third_party/WebKit/Source/core/paint/InlineTextBoxPainter.cpp b/third_party/WebKit/Source/core/paint/InlineTextBoxPainter.cpp index c504070..d24007e 100644 --- a/third_party/WebKit/Source/core/paint/InlineTextBoxPainter.cpp +++ b/third_party/WebKit/Source/core/paint/InlineTextBoxPainter.cpp
@@ -39,12 +39,19 @@ std::pair<unsigned, unsigned> GetTextMatchMarkerPaintOffsets( const DocumentMarker& marker, const InlineTextBox& text_box) { + // text_box.Start() returns an offset relative to the start of the layout + // object. We add the LineLayoutItem's TextStartOffset() to get a DOM offset + // (which is what DocumentMarker uses). This is necessary to get proper + // behavior with the :first-letter psuedo element. + const unsigned text_box_start = + text_box.Start() + text_box.GetLineLayoutItem().TextStartOffset(); + DCHECK_EQ(DocumentMarker::kTextMatch, marker.GetType()); - const unsigned start_offset = marker.StartOffset() > text_box.Start() - ? marker.StartOffset() - text_box.Start() + const unsigned start_offset = marker.StartOffset() > text_box_start + ? marker.StartOffset() - text_box_start : 0U; const unsigned end_offset = - std::min(marker.EndOffset() - text_box.Start(), text_box.Len()); + std::min(marker.EndOffset() - text_box_start, text_box.Len()); return std::make_pair(start_offset, end_offset); } @@ -440,10 +447,17 @@ DCHECK(inline_text_box_.Truncation() != kCFullTruncation); DCHECK(inline_text_box_.Len()); + // inline_text_box_.Start() returns an offset relative to the start of the + // layout object. We add the LineLayoutItem's TextStartOffset() to get a DOM + // offset (which is what DocumentMarker uses). This is necessary to get proper + // behavior with the :first-letter psuedo element. + const unsigned inline_text_box_start = + inline_text_box_.Start() + + inline_text_box_.GetLineLayoutItem().TextStartOffset(); + // Start painting at the beginning of the text or the specified underline // start offset, whichever is greater. - unsigned paint_start = - std::max(inline_text_box_.Start(), marker.StartOffset()); + unsigned paint_start = std::max(inline_text_box_start, marker.StartOffset()); // Cap the maximum paint start to the last character in the text box. paint_start = std::min(paint_start, inline_text_box_.end()); @@ -455,8 +469,8 @@ // paint_start and paint_end are currently relative to the start of the text // node. Subtract to make them relative to the start of the InlineTextBox. - paint_start -= inline_text_box_.Start(); - paint_end -= inline_text_box_.Start(); + paint_start -= inline_text_box_start; + paint_end -= inline_text_box_start; return ApplyTruncationToPaintOffsets({paint_start, paint_end}); }
diff --git a/third_party/WebKit/Source/core/paint/PaintLayerPainter.cpp b/third_party/WebKit/Source/core/paint/PaintLayerPainter.cpp index a02910c..cc01d0d 100644 --- a/third_party/WebKit/Source/core/paint/PaintLayerPainter.cpp +++ b/third_party/WebKit/Source/core/paint/PaintLayerPainter.cpp
@@ -747,10 +747,10 @@ } } -static void ForAllFragments( - GraphicsContext& context, - const PaintLayerFragments& fragments, - const std::function<void(const PaintLayerFragment&)> function) { +template <typename Function> +static void ForAllFragments(GraphicsContext& context, + const PaintLayerFragments& fragments, + const Function& function) { for (size_t i = 0; i < fragments.size(); ++i) { Optional<ScopedDisplayItemFragment> scoped_display_item_fragment; if (i)
diff --git a/third_party/WebKit/Source/core/paint/PaintPropertyTreeBuilder.cpp b/third_party/WebKit/Source/core/paint/PaintPropertyTreeBuilder.cpp index 98aaf67..a6ab157 100644 --- a/third_party/WebKit/Source/core/paint/PaintPropertyTreeBuilder.cpp +++ b/third_party/WebKit/Source/core/paint/PaintPropertyTreeBuilder.cpp
@@ -1652,6 +1652,8 @@ if (RuntimeEnabledFeatures::SlimmingPaintV2Enabled()) return; + // TODO(crbug.com/797779): Implement fragments across frame boundaries. + const auto* enclosing_pagination_layer = context_.painting_layer->EnclosingPaginationLayer(); if (!enclosing_pagination_layer) @@ -1679,8 +1681,7 @@ first_fragment.SetPaginationOffset( ToLayoutPoint(iterator.PaginationOffset())); } - } else { - DCHECK(parent_composited_layer); + } else if (parent_composited_layer) { // All objects under the composited layer use the same pagination offset. first_fragment.SetPaginationOffset( parent_composited_layer->GetLayoutObject()
diff --git a/third_party/WebKit/Source/core/paint/PaintPropertyTreeBuilderTest.cpp b/third_party/WebKit/Source/core/paint/PaintPropertyTreeBuilderTest.cpp index f3458eb..29739cc 100644 --- a/third_party/WebKit/Source/core/paint/PaintPropertyTreeBuilderTest.cpp +++ b/third_party/WebKit/Source/core/paint/PaintPropertyTreeBuilderTest.cpp
@@ -3735,6 +3735,36 @@ // TODO(crbug.com/797779): Add code to verify fragments under the iframe. } +TEST_P(PaintPropertyTreeBuilderTest, CompositedMulticolFrameUnderMulticol) { + // TODO(crbug.com/796768): Currently this test crashes for SPv2 when mapping + // layer clip rects from one fragment to another. May need to adjust fragment + // clip hierarchy to fix the crash. + if (RuntimeEnabledFeatures::SlimmingPaintV2Enabled()) + return; + + SetBodyInnerHTML(R"HTML( + <style>body { margin: 0 }</style> + <div style='columns: 3; column-gap: 0; column-fill: auto; + width: 300px; height: 200px'> + <div style='height: 300px'></div> + <iframe id='iframe' style='will-change: transform; + width: 90px; height: 300px; border: none; background: green'></iframe> + </div> + )HTML"); + SetChildFrameHTML(R"HTML( + <style>body { margin: 0 }</style> + <div style='columns: 2; column-gap: 0; column-fill: auto; + width: 80px; height: 100px'> + <div id="multicolContent" style='height: 200px; background: blue'></div> + </div> + )HTML"); + + // This should not crash on duplicated subsequences in the iframe. + GetDocument().View()->UpdateAllLifecyclePhases(); + + // TODO(crbug.com/797779): Add code to verify fragments under the iframe. +} + TEST_P(PaintPropertyTreeBuilderTest, FragmentedBecomesUnfragmentedClearPaginationOffset) { SetBodyInnerHTML(R"HTML(
diff --git a/third_party/WebKit/Source/core/testing/Internals.cpp b/third_party/WebKit/Source/core/testing/Internals.cpp index 8e3e29f..aef84a1 100644 --- a/third_party/WebKit/Source/core/testing/Internals.cpp +++ b/third_party/WebKit/Source/core/testing/Internals.cpp
@@ -2860,12 +2860,11 @@ DOMArrayBuffer* Internals::serializeObject( scoped_refptr<SerializedScriptValue> value) const { - StringView view = value->GetWireData(); - DCHECK(view.Is8Bit()); + base::span<const uint8_t> span = value->GetWireData(); DOMArrayBuffer* buffer = - DOMArrayBuffer::CreateUninitializedOrNull(view.length(), sizeof(LChar)); + DOMArrayBuffer::CreateUninitializedOrNull(span.length(), sizeof(uint8_t)); if (buffer) - memcpy(buffer->Data(), view.Characters8(), view.length()); + memcpy(buffer->Data(), span.data(), span.length()); return buffer; }
diff --git a/third_party/WebKit/Source/devtools/front_end/Tests.js b/third_party/WebKit/Source/devtools/front_end/Tests.js index 89c80ee..fd97c75 100644 --- a/third_party/WebKit/Source/devtools/front_end/Tests.js +++ b/third_party/WebKit/Source/devtools/front_end/Tests.js
@@ -902,11 +902,22 @@ }; TestSuite.prototype.testWindowInitializedOnNavigateBack = function() { + var test = this; + test.takeControl(); var messages = ConsoleModel.consoleModel.messages(); - this.assertEquals(1, messages.length); - var text = messages[0].messageText; - if (text.indexOf('Uncaught') !== -1) - this.fail(text); + if (messages.length === 1) { + checkMessages(); + } else { + ConsoleModel.consoleModel.addEventListener( + ConsoleModel.ConsoleModel.Events.MessageAdded, checkMessages.bind(this), this); + } + + function checkMessages() { + var messages = ConsoleModel.consoleModel.messages(); + test.assertEquals(1, messages.length); + test.assertTrue(messages[0].messageText.indexOf('Uncaught') === -1); + test.releaseControl(); + } }; TestSuite.prototype.testConsoleContextNames = function() {
diff --git a/third_party/WebKit/Source/devtools/front_end/extensions/ExtensionAPI.js b/third_party/WebKit/Source/devtools/front_end/extensions/ExtensionAPI.js index 945f961..693f9e2 100644 --- a/third_party/WebKit/Source/devtools/front_end/extensions/ExtensionAPI.js +++ b/third_party/WebKit/Source/devtools/front_end/extensions/ExtensionAPI.js
@@ -94,6 +94,11 @@ * @suppressGlobalPropertiesCheck */ function injectedExtensionAPI(extensionInfo, inspectedTabId, themeName, testHook, injectedScriptId) { + var chrome = window.chrome || {}; + var devtools_descriptor = Object.getOwnPropertyDescriptor(chrome, 'devtools'); + if (devtools_descriptor) + return; + var apiPrivate = {}; defineCommonExtensionSymbols(apiPrivate); @@ -757,13 +762,7 @@ var extensionServer = new ExtensionServerClient(); var coreAPI = new InspectorExtensionAPI(); - var chrome = window.chrome || {}; - // Override chrome.devtools as a workaround for a error-throwing getter being exposed - // in extension pages loaded into a non-extension process (only happens for remote client - // extensions) - var devtools_descriptor = Object.getOwnPropertyDescriptor(chrome, 'devtools'); - if (!devtools_descriptor || devtools_descriptor.get) - Object.defineProperty(chrome, 'devtools', {value: {}, enumerable: true}); + Object.defineProperty(chrome, 'devtools', {value: {}, enumerable: true}); // Only expose tabId on chrome.devtools.inspectedWindow, not webInspector.inspectedWindow. chrome.devtools.inspectedWindow = {};
diff --git a/third_party/WebKit/Source/devtools/front_end/network/RequestHeadersView.js b/third_party/WebKit/Source/devtools/front_end/network/RequestHeadersView.js index a55bf58c..781f171 100644 --- a/third_party/WebKit/Source/devtools/front_end/network/RequestHeadersView.js +++ b/third_party/WebKit/Source/devtools/front_end/network/RequestHeadersView.js
@@ -109,7 +109,8 @@ */ _formatHeader(name, value) { var fragment = createDocumentFragment(); - fragment.createChild('div', 'header-name').textContent = name + ':'; + fragment.createChild('div', 'header-name').textContent = name + ': '; + fragment.createChild('span', 'header-separator'); fragment.createChild('div', 'header-value source-code').textContent = value; return fragment; @@ -253,9 +254,10 @@ for (var i = 0; i < params.length; ++i) { var paramNameValue = createDocumentFragment(); if (params[i].name !== '') { - var name = this._formatParameter(params[i].name + ':', 'header-name', this._decodeRequestParameters); + var name = this._formatParameter(params[i].name + ': ', 'header-name', this._decodeRequestParameters); var value = this._formatParameter(params[i].value, 'header-value source-code', this._decodeRequestParameters); paramNameValue.appendChild(name); + paramNameValue.createChild('span', 'header-separator'); paramNameValue.appendChild(value); } else { paramNameValue.appendChild( @@ -373,7 +375,8 @@ if (this._request.statusCode) { var statusCodeFragment = createDocumentFragment(); - statusCodeFragment.createChild('div', 'header-name').textContent = Common.UIString('Status Code') + ':'; + statusCodeFragment.createChild('div', 'header-name').textContent = Common.UIString('Status Code') + ': '; + statusCodeFragment.createChild('span', 'header-separator'); var statusCodeImage = statusCodeFragment.createChild('label', 'resource-status-image', 'dt-icon-label'); statusCodeImage.title = this._request.statusCode + ' ' + this._request.statusText;
diff --git a/third_party/WebKit/Source/devtools/front_end/network/requestHeadersTree.css b/third_party/WebKit/Source/devtools/front_end/network/requestHeadersTree.css index 2b2239b..5d3ae946 100644 --- a/third_party/WebKit/Source/devtools/front_end/network/requestHeadersTree.css +++ b/third_party/WebKit/Source/devtools/front_end/network/requestHeadersTree.css
@@ -64,12 +64,16 @@ .tree-outline .header-name { color: rgb(33%, 33%, 33%); display: inline-block; - margin-right: 0.5em; + margin-right: 0.25em; font-weight: bold; vertical-align: top; white-space: pre-wrap; } +.tree-outline .header-separator { + user-select: none; +} + .tree-outline .header-value { display: inline; margin-right: 1em;
diff --git a/third_party/WebKit/Source/devtools/front_end/persistence/NetworkPersistenceManager.js b/third_party/WebKit/Source/devtools/front_end/persistence/NetworkPersistenceManager.js index 1247aa2..97f7e428 100644 --- a/third_party/WebKit/Source/devtools/front_end/persistence/NetworkPersistenceManager.js +++ b/third_party/WebKit/Source/devtools/front_end/persistence/NetworkPersistenceManager.js
@@ -351,7 +351,7 @@ * @param {!Workspace.UISourceCode} uiSourceCode */ _networkUISourceCodeRemoved(uiSourceCode) { - if (uiSourceCode.project().type() === Workspace.projectTypes.Network) + if (uiSourceCode.project().type() !== Workspace.projectTypes.Network) return; this._unbind(uiSourceCode); this._networkUISourceCodeForEncodedPath.delete(this._encodedPathFromUrl(uiSourceCode.url()));
diff --git a/third_party/WebKit/Source/modules/indexeddb/IDBTestHelper.cpp b/third_party/WebKit/Source/modules/indexeddb/IDBTestHelper.cpp index e3bb3ca1..e4c055a 100644 --- a/third_party/WebKit/Source/modules/indexeddb/IDBTestHelper.cpp +++ b/third_party/WebKit/Source/modules/indexeddb/IDBTestHelper.cpp
@@ -21,13 +21,11 @@ scoped_refptr<SerializedScriptValue> null_ssv = SerializedScriptValue::NullValue(); - StringView ssv_wire_bytes = null_ssv->GetWireData(); - DCHECK(ssv_wire_bytes.Is8Bit()); + base::span<const uint8_t> ssv_wire_bytes = null_ssv->GetWireData(); scoped_refptr<SharedBuffer> idb_value_buffer = SharedBuffer::Create(); - idb_value_buffer->Append( - reinterpret_cast<const char*>(ssv_wire_bytes.Characters8()), - ssv_wire_bytes.length()); + idb_value_buffer->Append(reinterpret_cast<const char*>(ssv_wire_bytes.data()), + ssv_wire_bytes.length()); return IDBValue::Create(std::move(idb_value_buffer), Vector<scoped_refptr<BlobDataHandle>>(), Vector<WebBlobInfo>(), IDBKey::CreateNumber(42.0),
diff --git a/third_party/WebKit/Source/modules/indexeddb/IDBValueWrapping.cpp b/third_party/WebKit/Source/modules/indexeddb/IDBValueWrapping.cpp index 47b222b..6fa01de 100644 --- a/third_party/WebKit/Source/modules/indexeddb/IDBValueWrapping.cpp +++ b/third_party/WebKit/Source/modules/indexeddb/IDBValueWrapping.cpp
@@ -123,7 +123,6 @@ #endif // DCHECK_IS_ON() wire_data_ = serialized_value_->GetWireData(); - DCHECK(wire_data_.Is8Bit()); for (const auto& kvp : serialized_value_->BlobDataHandles()) blob_handles_.push_back(std::move(kvp.value)); } @@ -147,7 +146,7 @@ // Blob::Create to avoid a buffer copy. std::unique_ptr<BlobData> wrapper_blob_data = BlobData::Create(); wrapper_blob_data->SetContentType(String(kWrapMimeType)); - wrapper_blob_data->AppendBytes(wire_data_.Characters8(), wire_data_size); + wrapper_blob_data->AppendBytes(wire_data_.data(), wire_data_size); scoped_refptr<BlobDataHandle> wrapper_handle = BlobDataHandle::Create(std::move(wrapper_blob_data), wire_data_size); blob_info_.emplace_back(wrapper_handle->Uuid(), wrapper_handle->GetType(), @@ -162,9 +161,10 @@ IDBValueWrapper::WriteVarInt(serialized_value_->BlobDataHandles().size(), wire_data_buffer_); - wire_data_ = StringView(wire_data_buffer_.data(), wire_data_buffer_.size()); + wire_data_ = base::make_span( + reinterpret_cast<const uint8_t*>(wire_data_buffer_.data()), + wire_data_buffer_.size()); DCHECK(!wire_data_buffer_.IsEmpty()); - DCHECK(wire_data_.Is8Bit()); return true; } @@ -177,16 +177,15 @@ if (wire_data_buffer_.IsEmpty()) { // The wire bytes are coming directly from the SSV's GetWireData() call. - DCHECK_EQ(wire_data_.Characters8(), - serialized_value_->GetWireData().Characters8()); + DCHECK_EQ(wire_data_.data(), serialized_value_->GetWireData().data()); DCHECK_EQ(wire_data_.length(), serialized_value_->GetWireData().length()); - return SharedBuffer::Create(wire_data_.Characters8(), + return SharedBuffer::Create(wire_data_.data(), static_cast<size_t>(wire_data_.length())); } // The wire bytes are coming from wire_data_buffer_, so we can avoid a copy. DCHECK_EQ(wire_data_buffer_.data(), - reinterpret_cast<const char*>(wire_data_.Characters8())); + reinterpret_cast<const char*>(wire_data_.data())); DCHECK_EQ(wire_data_buffer_.size(), wire_data_.length()); return SharedBuffer::AdoptVector(wire_data_buffer_); }
diff --git a/third_party/WebKit/Source/modules/indexeddb/IDBValueWrapping.h b/third_party/WebKit/Source/modules/indexeddb/IDBValueWrapping.h index e0aa0785..0e6b29af 100644 --- a/third_party/WebKit/Source/modules/indexeddb/IDBValueWrapping.h +++ b/third_party/WebKit/Source/modules/indexeddb/IDBValueWrapping.h
@@ -185,7 +185,7 @@ Vector<char> wire_data_buffer_; // Points into SerializedScriptValue's data buffer, or into wire_data_buffer_. - StringView wire_data_; + base::span<const uint8_t> wire_data_; size_t original_data_length_ = 0;
diff --git a/third_party/WebKit/Source/modules/notifications/NotificationData.cpp b/third_party/WebKit/Source/modules/notifications/NotificationData.cpp index cd3200cb..b701d5f 100644 --- a/third_party/WebKit/Source/modules/notifications/NotificationData.cpp +++ b/third_party/WebKit/Source/modules/notifications/NotificationData.cpp
@@ -95,13 +95,7 @@ if (exception_state.HadException()) return WebNotificationData(); - StringView ssv_wire_data = serialized_script_value->GetWireData(); - DCHECK(ssv_wire_data.Is8Bit()); - Vector<char> serialized_data; - serialized_data.ReserveInitialCapacity(ssv_wire_data.length()); - serialized_data.Append(ssv_wire_data.Characters8(), ssv_wire_data.length()); - - web_data.data = serialized_data; + web_data.data = WebVector<char>(serialized_script_value->GetWireData()); } Vector<WebNotificationAction> actions;
diff --git a/third_party/WebKit/Source/platform/heap/HeapTest.cpp b/third_party/WebKit/Source/platform/heap/HeapTest.cpp index 1a43500..9b870d5 100644 --- a/third_party/WebKit/Source/platform/heap/HeapTest.cpp +++ b/third_party/WebKit/Source/platform/heap/HeapTest.cpp
@@ -42,6 +42,7 @@ #include "platform/heap/HeapTestUtilities.h" #include "platform/heap/SafePoint.h" #include "platform/heap/SelfKeepAlive.h" +#include "platform/heap/StackFrameDepth.h" #include "platform/heap/ThreadState.h" #include "platform/heap/Visitor.h" #include "platform/testing/UnitTestHelpers.h" @@ -6253,6 +6254,20 @@ EXPECT_EQ(kGrowsTowardsLower, StackGrowthDirection()); } +TEST(HeapTest, StackFrameDepthDisabledByDefault) { + StackFrameDepth depth; + // Only allow recursion after explicitly enabling the stack limit. + EXPECT_FALSE(depth.IsSafeToRecurse()); +} + +TEST(HeapTest, StackFrameDepthEnable) { + StackFrameDepth depth; + StackFrameDepthScope scope(&depth); + // The scope may fail to enable recursion when the stack is close to the + // limit. In all other cases we should be able to safely recurse. + EXPECT_TRUE(depth.IsSafeToRecurse() || !depth.IsEnabled()); +} + class TestMixinAllocationA : public GarbageCollected<TestMixinAllocationA>, public GarbageCollectedMixin { USING_GARBAGE_COLLECTED_MIXIN(TestMixinAllocationA);
diff --git a/third_party/WebKit/Source/platform/heap/StackFrameDepth.h b/third_party/WebKit/Source/platform/heap/StackFrameDepth.h index 47ed658..73c8fb9 100644 --- a/third_party/WebKit/Source/platform/heap/StackFrameDepth.h +++ b/third_party/WebKit/Source/platform/heap/StackFrameDepth.h
@@ -77,7 +77,7 @@ // The stack pointer is assumed to grow towards lower addresses; // |kMinimumStackLimit| then being the limit that a stack // pointer will always exceed. - static const uintptr_t kMinimumStackLimit = ~0ul; + static const uintptr_t kMinimumStackLimit = ~uintptr_t{0}; static uintptr_t GetFallbackStackLimit();
diff --git a/third_party/WebKit/Source/platform/runtime_enabled_features.json5 b/third_party/WebKit/Source/platform/runtime_enabled_features.json5 index 714cda7f..68e6f5e 100644 --- a/third_party/WebKit/Source/platform/runtime_enabled_features.json5 +++ b/third_party/WebKit/Source/platform/runtime_enabled_features.json5
@@ -273,7 +273,7 @@ }, { name: "CSSScrollSnapPoints", - status: "test", + status: "experimental", }, { name: "CSSSnapSize",
diff --git a/third_party/WebKit/Tools/Scripts/merge-layout-test-results b/third_party/WebKit/Tools/Scripts/merge-layout-test-results index fda1453e..1b0d6b0 100755 --- a/third_party/WebKit/Tools/Scripts/merge-layout-test-results +++ b/third_party/WebKit/Tools/Scripts/merge-layout-test-results
@@ -101,7 +101,12 @@ help='Directories to merge the results from.') # Swarming Isolated Merge Script API - # script.py --build-properties /s/build.json --output-json /tmp/output.json shard0/output.json shard1/output.json + # script.py \ + # --build-properties /s/build.json \ + # --output-json /tmp/output.json \ + # --task-output-dir /path/to/task/output/dir \ + # shard0/output.json \ + # shard1/output.json parser.add_argument( '-o', '--output-json', help='(Swarming Isolated Merge Script API) Output JSON file to create.') @@ -109,6 +114,9 @@ '--build-properties', help='(Swarming Isolated Merge Script API) Build property JSON file provided by recipes.') parser.add_argument( + '--task-output-dir', + help='(Swarming Isolated Merge Script API) Directory containing all swarming task results.') + parser.add_argument( '--results-json-override-with-build-property', nargs=2, metavar=('RESULT_JSON_KEY', 'BUILD_PROPERTY_KEY'), default=[], action='append',
diff --git a/third_party/WebKit/public/platform/web_feature.mojom b/third_party/WebKit/public/platform/web_feature.mojom index f109f87e..fb53e9261 100644 --- a/third_party/WebKit/public/platform/web_feature.mojom +++ b/third_party/WebKit/public/platform/web_feature.mojom
@@ -1827,6 +1827,7 @@ kCSSSelectorWebkitTextfieldDecorationContainer = 2318, kCSSSelectorWebkitUnknownPseudo = 2319, kFilterAsContainingBlockMayChangeOutput = 2320, + kDispatchMouseUpDownEventOnDisabledFormControl = 2321, // Add new features immediately above this line. Don't change assigned // numbers of any item, and don't reuse removed slots.
diff --git a/tools/binary_size/libsupersize/archive.py b/tools/binary_size/libsupersize/archive.py index a39e13a..105ccaa 100644 --- a/tools/binary_size/libsupersize/archive.py +++ b/tools/binary_size/libsupersize/archive.py
@@ -72,6 +72,9 @@ elif full_name.startswith('rel.'): symbol.flags |= models.FLAG_REL symbol.full_name = full_name[4:] + elif full_name.startswith('hot.'): + symbol.flags |= models.FLAG_HOT + symbol.full_name = full_name[4:] def _NormalizeNames(raw_symbols):
diff --git a/tools/binary_size/libsupersize/function_signature.py b/tools/binary_size/libsupersize/function_signature.py index fbd1e67..4fb954c 100644 --- a/tools/binary_size/libsupersize/function_signature.py +++ b/tools/binary_size/libsupersize/function_signature.py
@@ -77,9 +77,11 @@ space_idx = paren_idx - 6 while True: space_idx = _FindLastCharOutsideOfBrackets(name, ' ', space_idx) - # Special case: "operator new", and "operator<< <template>". + # Special cases: "operator new", "operator< <templ>", "operator<< <tmpl>". + # No space is added for operator>><tmpl>. if -1 == space_idx or ( -1 == name.find('operator', space_idx - 8, space_idx) and + -1 == name.find('operator<', space_idx - 9, space_idx) and -1 == name.find('operator<<', space_idx - 10, space_idx)): break space_idx -= 8 @@ -93,13 +95,10 @@ if last_right_idx == -1: return name left_idx = _FindLastCharOutsideOfBrackets(name, '<', last_right_idx + 1) - if left_idx == -1: - return name - # Special case: std::operator<< < - if left_idx > 0 and name[left_idx - 1] == ' ': - left_idx -= 1 - name = name[:left_idx] + name[last_right_idx + 1:] - last_right_idx = left_idx + if left_idx != -1: + # Leave in empty <>s to denote that it's a template. + name = name[:left_idx + 1] + name[last_right_idx:] + last_right_idx = left_idx def _NormalizeTopLevelGccLambda(name, left_paren_idx):
diff --git a/tools/binary_size/libsupersize/function_signature_test.py b/tools/binary_size/libsupersize/function_signature_test.py index b830366b..65e755bfb 100755 --- a/tools/binary_size/libsupersize/function_signature_test.py +++ b/tools/binary_size/libsupersize/function_signature_test.py
@@ -16,7 +16,7 @@ def check(ret_part, name_part, params_part, after_part='', name_without_templates=None): if name_without_templates is None: - name_without_templates = re.sub(r'<.*?>', '', name_part) + after_part + name_without_templates = re.sub(r'<.*?>', '<>', name_part) + after_part signature = ''.join((name_part, params_part, after_part)) got_full_name, got_template_name, got_name = ( @@ -60,7 +60,22 @@ check('std::basic_ostream<char, std::char_traits<char> >& ', 'std::operator<< <std::char_traits<char> >', '(std::basic_ostream<char, std::char_traits<char> >&, char)', - name_without_templates='std::operator<<') + name_without_templates='std::operator<< <>') + check('', + 'std::basic_istream<char, std::char_traits<char> >' + '::operator>>', + '(unsigned int&)', + name_without_templates='std::basic_istream<>::operator>>') + check('', + 'std::operator><std::allocator<char> >', '()', + name_without_templates='std::operator><>') + check('', + 'std::operator>><std::allocator<char> >', + '(std::basic_istream<char, std::char_traits<char> >&)', + name_without_templates='std::operator>><>') + check('', + 'std::basic_istream<char>::operator>', '(unsigned int&)', + name_without_templates='std::basic_istream<>::operator>') check('v8::internal::SlotCallbackResult ', 'v8::internal::UpdateTypedSlotHelper::UpdateCodeTarget' '<v8::PointerUpdateJobTraits<(v8::Direction)1>::Foo(v8::Heap*, ' @@ -71,7 +86,7 @@ '{lambda(v8::SlotType)#2}::operator()(v8::SlotType) const::' '{lambda(v8::Object**)#1})', name_without_templates=( - 'v8::internal::UpdateTypedSlotHelper::UpdateCodeTarget')) + 'v8::internal::UpdateTypedSlotHelper::UpdateCodeTarget<>')) check('', 'WTF::StringAppend<WTF::String, WTF::String>::operator WTF::String', '()', @@ -86,7 +101,7 @@ # Test with multiple template args. check('int ', 'Foo<int()>::bar<a<b> >', '()', - name_without_templates='Foo::bar') + name_without_templates='Foo<>::bar<>') # SkArithmeticImageFilter.cpp has class within function body. e.g.: # ArithmeticFP::onCreateGLSLInstance() looks like: @@ -125,7 +140,7 @@ check('', 'blink::CSSValueKeywordsHash::findValueImpl', '(char const*)', '::value_word_list') check('', 'foo::Bar<Z<Y> >::foo<bar>', '(abc)', '::var<baz>', - name_without_templates='foo::Bar::foo::var') + name_without_templates='foo::Bar<>::foo<>::var<>') if __name__ == '__main__': logging.basicConfig(level=logging.DEBUG,
diff --git a/tools/binary_size/libsupersize/models.py b/tools/binary_size/libsupersize/models.py index 72abfdf..0dc9aba8 100644 --- a/tools/binary_size/libsupersize/models.py +++ b/tools/binary_size/libsupersize/models.py
@@ -89,6 +89,7 @@ FLAG_REL_LOCAL = 16 FLAG_GENERATED_SOURCE = 32 FLAG_CLONE = 64 +FLAG_HOT = 128 DIFF_STATUS_UNCHANGED = 0 @@ -247,6 +248,8 @@ parts.append('gen') if flags & FLAG_CLONE: parts.append('clone') + if flags & FLAG_HOT: + parts.append('hot') return '{%s}' % ','.join(parts) def IsBss(self):
diff --git a/tools/binary_size/libsupersize/testdata/test.map b/tools/binary_size/libsupersize/testdata/test.map index ba91d9e..e1a6a12b 100644 --- a/tools/binary_size/libsupersize/testdata/test.map +++ b/tools/binary_size/libsupersize/testdata/test.map
@@ -92,7 +92,7 @@ .text._ZN5blink23ContiguousContainerBase11shrinkToFitEv 0x002a0000 0x10 obj/third_party/WebKit.a(PaintChunker.o) 0x002a0001 blink::ContiguousContainerBase::shrinkToFit() - .text._ZN5blink23ContiguousContainerBase11shrinkToFitEv2 + .text.hot._ZN5blink23ContiguousContainerBase11shrinkToFitEv2 0x002a0010 0xc obj/third_party/WebKit.a(PaintChunker.o) 0x002a0011 blink::ContiguousContainerBase::shrinkToFit() [clone .part.1234] [clone .isra.2] .text._ZN5blink23ContiguousContainerBaseC2EOS0_
diff --git a/tools/chrome_proxy/webdriver/lite_page.py b/tools/chrome_proxy/webdriver/lite_page.py index b0d1d54..a9d83e2a 100644 --- a/tools/chrome_proxy/webdriver/lite_page.py +++ b/tools/chrome_proxy/webdriver/lite_page.py
@@ -147,7 +147,7 @@ # Android because it depends on window size of the browser. @AndroidOnly @ChromeVersionBeforeM(65) - def testLitePageBTF(self): + def testLitePageBTFOldFlags(self): # If it was attempted to run with another experiment, skip this test. if common.ParseFlags().browser_args and ('--data-reduction-proxy-experiment' in common.ParseFlags().browser_args): @@ -192,11 +192,64 @@ self.assertHasChromeProxyViaHeader(response) self.assertIn(response.status, [200, 204]) + # Checks that a Lite Page does not have an error when scrolling to the bottom + # of the page and is able to load all resources. This test is only run on + # Android because it depends on window size of the browser. + @AndroidOnly + @ChromeVersionEqualOrAfterM(65) + def testLitePageBTFWithoutFallback(self): + # If it was attempted to run with another experiment, skip this test. + if common.ParseFlags().browser_args and ('--data-reduction-proxy-experiment' + in common.ParseFlags().browser_args): + self.skipTest('This test cannot be run with other experiments.') + with TestDriver() as test_driver: + test_driver.AddChromeArg('--enable-spdy-proxy-auth') + # Need to force 2G speed to get lite-page response. + test_driver.AddChromeArg('--force-effective-connection-type=2G') + + # Need to force lite page so target page doesn't fallback to Lo-Fi + # Set exp=alt1 to force Lite-page response. + test_driver.AddChromeArg('--data-reduction-proxy-experiment=alt1') + + # This page is long and has many media resources. + test_driver.LoadURL('http://check.googlezip.net/metrics/index.html') + + # Verify that a Lite Page response for the main frame was seen. + lite_page_responses = 0 + for response in test_driver.GetHTTPResponses(): + # Skip CSI requests when validating Lite Page headers. CSI requests + # aren't expected to have LoFi headers. + if '/csi?' in response.url: + continue + if response.url.startswith('data:'): + continue + if (self.checkLitePageResponse(response)): + lite_page_responses = lite_page_responses + 1 + self.assertEqual(1, lite_page_responses) + + # Scroll to the bottom of the window and ensure scrollHeight increases. + original_scroll_height = test_driver.ExecuteJavascriptStatement( + 'document.body.scrollHeight') + test_driver.ExecuteJavascriptStatement( + 'window.scrollTo(0,Math.max(document.body.scrollHeight));') + # Give some time for loading after scrolling. + time.sleep(2) + new_scroll_height = test_driver.ExecuteJavascriptStatement( + 'document.body.scrollHeight') + self.assertGreater(new_scroll_height, original_scroll_height) + + # Make sure there were more requests that were proxied. + responses = test_driver.GetHTTPResponses(override_has_logs=True) + self.assertNotEqual(0, len(responses)) + for response in responses: + self.assertHasChromeProxyViaHeader(response) + self.assertIn(response.status, [200, 204]) + # Checks that a Nano Lite Page does not have an error when scrolling to the # bottom of the page and is able to load all resources. This test is only run # on Android because it depends on window size of the browser. @AndroidOnly - @ChromeVersionEqualOrAfterM(61) + @ChromeVersionEqualOrAfterM(65) def testLitePageBTFNano(self): # If it was attempted to run with another experiment, skip this test. if common.ParseFlags().browser_args and ('--data-reduction-proxy-experiment' @@ -316,7 +369,6 @@ self.assertEqual(0, lite_page_responses) self.assertNotEqual(0, lofi_resource) - self.assertNotEqual(0, lofi_resource) # Checks that the server provides a preview (either Lite Page or fallback # to LoFi) for a 2G connection.
diff --git a/tools/chrome_proxy/webdriver/lofi.py b/tools/chrome_proxy/webdriver/lofi.py index 59caa20..87ea292 100644 --- a/tools/chrome_proxy/webdriver/lofi.py +++ b/tools/chrome_proxy/webdriver/lofi.py
@@ -14,7 +14,7 @@ # The test page is uncacheable otherwise a cached page may be served that # doesn't have the correct via headers. @ChromeVersionBeforeM(65) - def testLoFi(self): + def testLoFiOldFlags(self): with TestDriver() as test_driver: test_driver.AddChromeArg('--enable-spdy-proxy-auth') test_driver.AddChromeArg('--enable-features=' @@ -42,15 +42,16 @@ histogram = test_driver.GetHistogram('Previews.InfoBarAction.LoFi', 5) self.assertEqual(1, histogram['count']) - # Checks that the compressed image is below a certain threshold. - # The test page is uncacheable otherwise a cached page may be served that - # doesn't have the correct via headers. - @ChromeVersionEqualOrAfterM(65) - def testLoFiWithServerPreviewsFlag(self): + # Checks that LoFi images are served when LoFi slow connections are used and + # the network quality estimator returns Slow2G. + @ChromeVersionBeforeM(65) + def testLoFiSlowConnectionOldFlags(self): with TestDriver() as test_driver: test_driver.AddChromeArg('--enable-spdy-proxy-auth') test_driver.AddChromeArg('--enable-features=' 'DataReductionProxyDecidesTransform') + test_driver.AddChromeArg('--data-reduction-proxy-lo-fi=slow-connections-' + 'only') # Disable server experiments such as tamper detection. test_driver.AddChromeArg('--data-reduction-proxy-server-experiments-' 'disabled') @@ -74,16 +75,18 @@ # Verify that Lo-Fi responses were seen. self.assertNotEqual(0, lofi_responses) + # Verify Lo-Fi previews info bar recorded + histogram = test_driver.GetHistogram('Previews.InfoBarAction.LoFi', 5) + self.assertEqual(1, histogram['count']) + # Checks that LoFi images are served when LoFi slow connections are used and # the network quality estimator returns Slow2G. - @ChromeVersionBeforeM(65) - def testLoFiSlowConnection(self): + @ChromeVersionEqualOrAfterM(65) + def testLoFiOnSlowConnection(self): with TestDriver() as test_driver: test_driver.AddChromeArg('--enable-spdy-proxy-auth') test_driver.AddChromeArg('--enable-features=' 'DataReductionProxyDecidesTransform') - test_driver.AddChromeArg('--data-reduction-proxy-lo-fi=slow-connections-' - 'only') # Disable server experiments such as tamper detection. test_driver.AddChromeArg('--data-reduction-proxy-server-experiments-' 'disabled') @@ -113,7 +116,8 @@ # Checks that LoFi images are NOT served when the network quality estimator # returns fast connection type. - def testLoFiFastConnection(self): + @ChromeVersionBeforeM(65) + def testLoFiFastConnectionOldFlags(self): with TestDriver() as test_driver: test_driver.AddChromeArg('--enable-spdy-proxy-auth') test_driver.AddChromeArg('--enable-features=' @@ -151,6 +155,45 @@ histogram = test_driver.GetHistogram('Previews.InfoBarAction.LoFi', 5) self.assertEqual(histogram, {}) + # Checks that LoFi images are NOT served when the network quality estimator + # returns fast connection. + @ChromeVersionEqualOrAfterM(65) + def testLoFiFastConnection(self): + with TestDriver() as test_driver: + test_driver.AddChromeArg('--enable-spdy-proxy-auth') + test_driver.AddChromeArg('--enable-features=' + 'DataReductionProxyDecidesTransform') + # Disable server experiments such as tamper detection. + test_driver.AddChromeArg('--data-reduction-proxy-server-experiments-' + 'disabled') + test_driver.AddChromeArg('--force-fieldtrial-params=' + 'NetworkQualityEstimator.Enabled:' + 'force_effective_connection_type/4G') + test_driver.AddChromeArg('--force-fieldtrials=NetworkQualityEstimator/' + 'Enabled') + + test_driver.LoadURL('http://check.googlezip.net/static/index.html') + + lofi_responses = 0 + for response in test_driver.GetHTTPResponses(): + if response.url.endswith('html'): + # Main resource should accept transforms but not be transformed. + self.assertEqual('lite-page', + response.request_headers['chrome-proxy-accept-transform']) + self.assertNotIn('chrome-proxy-content-transform', + response.response_headers) + if 'chrome-proxy' in response.response_headers: + self.assertNotIn('page-policies', + response.response_headers['chrome-proxy']) + else: + # No subresources should accept transforms. + self.assertNotIn('chrome-proxy-accept-transform', + response.request_headers) + + # Verify no Lo-Fi previews info bar recorded + histogram = test_driver.GetHistogram('Previews.InfoBarAction.LoFi', 5) + self.assertEqual(histogram, {}) + # Checks that LoFi images are not served, but the if-heavy CPAT header is # added when LoFi slow connections are used and the network quality estimator # returns 4G. @@ -201,7 +244,7 @@ # load should not pick the Lo-Fi placeholder from cache and original image # should be loaded. @ChromeVersionBeforeM(65) - def testLoFiCacheBypass(self): + def testLoFiCacheBypassOldFlags(self): # If it was attempted to run with another experiment, skip this test. if common.ParseFlags().browser_args and ('--data-reduction-proxy-experiment' in common.ParseFlags().browser_args): @@ -282,7 +325,7 @@ # load should not pick the Lo-Fi placeholder from cache and original image # should be loaded. @ChromeVersionEqualOrAfterM(65) - def testLoFiCacheBypassWithServerPreviewsFlag(self): + def testLoFiCacheBypass(self): # If it was attempted to run with another experiment, skip this test. if common.ParseFlags().browser_args and ('--data-reduction-proxy-experiment' in common.ParseFlags().browser_args): @@ -362,7 +405,7 @@ # directive is provided when LoFi is always-on without Lite Pages enabled. @ChromeVersionEqualOrAfterM(61) @ChromeVersionBeforeM(65) - def testLoFiForcedExperiment(self): + def testLoFiForcedExperimentOldFlags(self): # If it was attempted to run with another experiment, skip this test. if common.ParseFlags().browser_args and ('--data-reduction-proxy-experiment' in common.ParseFlags().browser_args):
diff --git a/tools/clang/scripts/update.py b/tools/clang/scripts/update.py index 78542c9..b6c0a3cf 100755 --- a/tools/clang/scripts/update.py +++ b/tools/clang/scripts/update.py
@@ -27,7 +27,7 @@ # Do NOT CHANGE this if you don't know what you're doing -- see # https://chromium.googlesource.com/chromium/src/+/master/docs/updating_clang.md # Reverting problematic clang rolls is safe, though. -CLANG_REVISION = '318667' +CLANG_REVISION = '321529' use_head_revision = bool(os.environ.get('LLVM_FORCE_HEAD_REVISION', '0') in ('1', 'YES')) @@ -890,6 +890,11 @@ args.force_local_build): AddSvnToPathOnWin() + if use_head_revision: + # TODO(hans): Trunk was updated; remove after the next roll. + global VERSION + VERSION = '7.0.0' + global CLANG_REVISION, PACKAGE_VERSION if args.print_revision: if use_head_revision or args.llvm_force_head_revision:
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml index 6362cc2..748c729 100644 --- a/tools/metrics/histograms/enums.xml +++ b/tools/metrics/histograms/enums.xml
@@ -1333,6 +1333,26 @@ <int value="4" label="Account check failed"/> </enum> +<enum name="ArcBootContinueCodeInstallationResult"> + <int value="0" label="Success"/> + <int value="1" label="Host side code is not ready"/> + <int value="2" label="Can not install host code"/> +</enum> + +<enum name="ArcCodeRelocationResult"> + <int value="0" label="Success"/> + <int value="1" label="Error bootlockboxd not ready"/> + <int value="2" label="Error unable to relocate"/> + <int value="3" label="Error unable to sign"/> +</enum> + +<enum name="ArcCodeVerificationResult"> + <int value="0" label="Success"/> + <int value="1" label="Error bootlockboxd not ready"/> + <int value="2" label="The first boot after OTA or OOBE boot"/> + <int value="3" label="Invalid code"/> +</enum> + <enum name="ArcContainerLifetimeEvent"> <int value="0" label="Starting"/> <int value="1" label="Failed to start"/> @@ -17333,6 +17353,7 @@ <int value="2318" label="CSSSelectorWebkitTextfieldDecorationContainer"/> <int value="2319" label="CSSSelectorWebkitUnknownPseudo"/> <int value="2320" label="FilterAsContainingBlockMayChangeOutput"/> + <int value="2321" label="DispatchMouseUpDownEventOnDisabledFormControl"/> </enum> <enum name="FeedbackSource">
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml index 712a99e..36e7a5e 100644 --- a/tools/metrics/histograms/histograms.xml +++ b/tools/metrics/histograms/histograms.xml
@@ -2504,6 +2504,55 @@ </summary> </histogram> +<histogram name="Arc.BootContinueCodeInstallationResult" + enum="ArcBootContinueCodeInstallationResult"> + <owner>elijahtaylor@google.com</owner> + <owner>xzhou@google.com</owner> + <summary>Code installation result for ARC boot continue.</summary> +</histogram> + +<histogram name="Arc.CodeIntegrityCheckingTotalTime" units="ms"> + <owner>elijahtaylor@google.com</owner> + <owner>xzhou@google.com</owner> + <summary> + Total time needed to check the integrity of host generated code. If + signature checking fails, it also includes the time to regenerate and sign + the code. + </summary> +</histogram> + +<histogram name="Arc.CodeRelocationResult" enum="ArcCodeRelocationResult"> + <owner>elijahtaylor@google.com</owner> + <owner>xzhou@google.com</owner> + <summary>Host code relocation result.</summary> +</histogram> + +<histogram name="Arc.CodeRelocationTime" units="ms"> + <owner>elijahtaylor@google.com</owner> + <owner>xzhou@google.com</owner> + <summary>Time needed to relocate boot*.art files.</summary> +</histogram> + +<histogram name="Arc.CodeSigningTime" units="ms"> + <owner>elijahtaylor@google.com</owner> + <owner>xzhou@google.com</owner> + <summary>Time needed to sign boot*.art files.</summary> +</histogram> + +<histogram name="Arc.CodeVerificationResult" enum="ArcCodeVerificationResult"> + <owner>elijahtaylor@google.com</owner> + <owner>xzhou@google.com</owner> + <summary> + Code verification result for host generated code for boot for login screen. + </summary> +</histogram> + +<histogram name="Arc.CodeVerificationTime" units="ms"> + <owner>elijahtaylor@google.com</owner> + <owner>xzhou@google.com</owner> + <summary>Time needed to verify host generated code.</summary> +</histogram> + <histogram name="Arc.ComplianceReportSinceUpdateNotificationTime" units="ms"> <owner>alexchau@google.com</owner> <owner>emaxx@google.com</owner> @@ -36796,6 +36845,9 @@ <histogram name="Memory.Experimental.Browser.PrivateMemoryFootprint.MacOS" units="MB"> + <obsolete> + Deprecated 12/2017. Replaced by Memory.Browser.PrivateMemoryFootprint. + </obsolete> <owner>erikchen@chromium.org</owner> <summary> A rough estimate of the private memory footprint of the browser process. @@ -36882,6 +36934,9 @@ <histogram name="Memory.Experimental.Extension.PrivateMemoryFootprint.MacOS" units="MB"> + <obsolete> + Deprecated 12/2017. Replaced by Memory.Extension.PrivateMemoryFootprint. + </obsolete> <owner>erikchen@chromium.org</owner> <summary> A rough estimate of the private memory footprint of an extension process. @@ -36910,6 +36965,9 @@ <histogram name="Memory.Experimental.Gpu.PrivateMemoryFootprint.MacOS" units="MB"> + <obsolete> + Deprecated 12/2017. Replaced by Memory.Gpu.PrivateMemoryFootprint. + </obsolete> <owner>erikchen@chromium.org</owner> <summary> A rough estimate of the private memory footprint of the GPU process. @@ -37002,6 +37060,9 @@ <histogram name="Memory.Experimental.Renderer.PrivateMemoryFootprint.MacOS" units="MB"> + <obsolete> + Deprecated 12/2017. Replaced by Memory.Renderer.PrivateMemoryFootprint. + </obsolete> <owner>erikchen@chromium.org</owner> <summary> A rough estimate of the private memory footprint of a renderer process.
diff --git a/tools/metrics/ukm/ukm.xml b/tools/metrics/ukm/ukm.xml index ae40c92..907d53f 100644 --- a/tools/metrics/ukm/ukm.xml +++ b/tools/metrics/ukm/ukm.xml
@@ -516,6 +516,18 @@ Metrics related to a scroll action caused by the generated ScrollUpdate gesture event. </summary> + <metric name="IsMainThread"> + <summary> + Whether the event is handled on the main thread or not. + </summary> + </metric> + <metric name="TimeToHandled"> + <summary> + The time in microseconds between initial creation of a touch event and the + generated ScrollUpdate gesture event is handled on main/impl thread. If no + swap was induced by the ScrollUpdate gesture event, no recording is made. + </summary> + </metric> <metric name="TimeToScrollUpdateSwapBegin"> <summary> The time in microseconds between the initial creation of a touch event and @@ -532,6 +544,19 @@ Metrics related to first scroll action caused by the generated ScrollUpdate gesture event. </summary> + <metric name="IsMainThread"> + <summary> + Whether the event is handled on the main thread or not. + </summary> + </metric> + <metric name="TimeToHandled"> + <summary> + The time in microseconds between initial creation of a touch event and the + first generated ScrollUpdate gesture event in a given scroll gesture event + sequence is handled on main/impl thread. If no swap was induced by the + ScrollUpdate gesture event, no recording is made. + </summary> + </metric> <metric name="TimeToScrollUpdateSwapBegin"> <summary> The time in microseconds between initial creation of a touch event and the @@ -550,6 +575,19 @@ Metrics related to a scroll action caused by the generated ScrollUpdate gesture event. </summary> + <metric name="IsMainThread"> + <summary> + Whether the event is handled on the main thread or not. + </summary> + </metric> + <metric name="TimeToHandled"> + <summary> + The time in microseconds between initial creation of a wheel event and the + generated ScrollUpdate gesture event is handled on main/impl thread. If no + swap was induced by the ScrollUpdate gesture event, no recording is made. + The first GSU of every scrolling sequence is excluded from this metric. + </summary> + </metric> <metric name="TimeToScrollUpdateSwapBegin"> <summary> The time in microseconds between the initial creation of a wheel event and @@ -566,6 +604,19 @@ Metrics related to first scroll action caused by the generated ScrollUpdate gesture event. </summary> + <metric name="IsMainThread"> + <summary> + Whether the event is handled on the main thread or not. + </summary> + </metric> + <metric name="TimeToHandled"> + <summary> + The time in microseconds between initial creation of a wheel event and the + first generated ScrollUpdate gesture event in a given scroll gesture event + sequence is handled on main/impl thread. If no swap was induced by the + ScrollBegin gesture event, no recording is made. + </summary> + </metric> <metric name="TimeToScrollUpdateSwapBegin"> <summary> The time in microseconds between the initial creation of a wheel event and
diff --git a/tools/perf/expectations.config b/tools/perf/expectations.config index bd19245..570bfd9 100644 --- a/tools/perf/expectations.config +++ b/tools/perf/expectations.config
@@ -1,4 +1,6 @@ # Test Expectation file for telemetry tests. +# Instructions of how to use this file: +# https://chromium.googlesource.com/chromium/src/+/master/docs/speed/perf_bot_sheriffing.md#Disabling-Telemetry-Tests # tags: All Android_Svelte Android_Webview Android_but_not_webview Mac Win Linux # tags: ChromeOS Android Desktop Mobile Nexus_5 Nexus_5X Nexus_6 Nexus_6P @@ -192,6 +194,8 @@ crbug.com/738854 [ Nexus_5X ] system_health.common_mobile/load:tools:drive [ Skip ] crbug.com/738854 [ Android_Webview ] system_health.common_mobile/load:tools:drive [ Skip ] crbug.com/797261 [ Android_Webview ] system_health.common_mobile/load:games:spychase [ Skip ] +crbug.com/798536 [ Android ] system_health.common_mobile/background:news:nytimes [ Skip ] +crbug.com/798536 [ Android ] system_health.common_mobile/load:games:spychase [ Skip ] # Benchmark: system_health.memory_desktop crbug.com/728576 [ Mac ] system_health.memory_desktop/browse:news:cnn [ Skip ]
diff --git a/tools/perf/upload_perf_results.py b/tools/perf/upload_perf_results.py index 48a3da71..05b11a2 100755 --- a/tools/perf/upload_perf_results.py +++ b/tools/perf/upload_perf_results.py
@@ -45,6 +45,7 @@ parser.add_argument('-o', '--output-json', required=True) parser.add_argument('--build-properties', help=argparse.SUPPRESS) parser.add_argument('--summary-json', help=argparse.SUPPRESS) + parser.add_argument('--task-output-dir', help=argparse.SUPPRESS) parser.add_argument('--verbose', help=argparse.SUPPRESS) parser.add_argument('jsons_to_merge', nargs='*')
diff --git a/ui/aura/mus/window_tree_host_mus.cc b/ui/aura/mus/window_tree_host_mus.cc index 6d3a3f2..a146cfc 100644 --- a/ui/aura/mus/window_tree_host_mus.cc +++ b/ui/aura/mus/window_tree_host_mus.cc
@@ -15,6 +15,7 @@ #include "ui/aura/window_event_dispatcher.h" #include "ui/aura/window_tree_host_observer.h" #include "ui/base/class_property.h" +#include "ui/base/ui_base_switches_util.h" #include "ui/display/display.h" #include "ui/display/screen.h" #include "ui/events/event.h" @@ -56,7 +57,11 @@ // seems them at the time the window is created. for (auto& pair : init_params.properties) window_mus->SetPropertyFromServer(pair.first, &pair.second); - CreateCompositor(viz::FrameSinkId()); + // If window-server is hosting viz, then use the FrameSinkId from the server. + // In other cases, let a valid FrameSinkId be selected by + // context_factory_private(). + CreateCompositor(switches::IsMusHostingViz() ? window_mus->GetFrameSinkId() + : viz::FrameSinkId()); if (!init_params.uses_real_accelerated_widget) { gfx::AcceleratedWidget accelerated_widget; // We need accelerated widget numbers to be different for each window and
diff --git a/ui/aura/window.cc b/ui/aura/window.cc index 40f6fe9..063a286 100644 --- a/ui/aura/window.cc +++ b/ui/aura/window.cc
@@ -1091,6 +1091,12 @@ } viz::FrameSinkId Window::GetFrameSinkId() const { + if (IsRootWindow()) { + DCHECK(host_); + auto* compositor = host_->compositor(); + DCHECK(compositor); + return compositor->frame_sink_id(); + } return port_->GetFrameSinkId(); }
diff --git a/ui/aura/window_unittest.cc b/ui/aura/window_unittest.cc index 1560854..c9aec7a3 100644 --- a/ui/aura/window_unittest.cc +++ b/ui/aura/window_unittest.cc
@@ -3181,6 +3181,12 @@ animator->RemoveObserver(&observer); } +TEST_P(WindowTest, RootWindowUsesCompositorFrameSinkId) { + EXPECT_EQ(host()->compositor()->frame_sink_id(), + root_window()->GetFrameSinkId()); + EXPECT_TRUE(root_window()->GetFrameSinkId().is_valid()); +} + TEST_P(WindowTest, LocalSurfaceIdChanges) { Window window(nullptr); window.Init(ui::LAYER_NOT_DRAWN);
diff --git a/ui/gl/BUILD.gn b/ui/gl/BUILD.gn index 44c2225..c0160ff3 100644 --- a/ui/gl/BUILD.gn +++ b/ui/gl/BUILD.gn
@@ -219,7 +219,7 @@ ] } } - if (is_android || is_linux) { + if (is_android || is_linux || is_fuchsia) { sources += [ "gl_implementation_osmesa.cc", "gl_implementation_osmesa.h",
diff --git a/ui/gl/gl_implementation_osmesa.cc b/ui/gl/gl_implementation_osmesa.cc index 4a8bf6f..14fa648 100644 --- a/ui/gl/gl_implementation_osmesa.cc +++ b/ui/gl/gl_implementation_osmesa.cc
@@ -8,6 +8,7 @@ #include "base/logging.h" #include "base/native_library.h" #include "base/path_service.h" +#include "build/build_config.h" #include "ui/gl/gl_bindings.h" #include "ui/gl/gl_gl_api_implementation.h" #include "ui/gl/gl_implementation.h" @@ -17,10 +18,20 @@ bool InitializeStaticGLBindingsOSMesaGL() { base::FilePath module_path; + +#if !defined(OS_FUCHSIA) + // On all platforms except Fuchsia libosmesa.so is expected to be in the same + // directory as the chrome binary. Pass full path to dlopen() to ensure we + // load the right version. + // + // On Fuchsia libraries are normally in the lib directory. The loader service + // will load libosmesa.so that belongs to the chrome package when dlopen() is + // called with relative path. if (!PathService::Get(base::DIR_MODULE, &module_path)) { LOG(ERROR) << "PathService::Get failed."; return false; } +#endif // !defined(OS_FUCHSIA) base::FilePath library_path = module_path.Append("libosmesa.so"); base::NativeLibrary library = LoadLibraryAndPrintError(library_path);
diff --git a/ui/latency/latency_tracker.cc b/ui/latency/latency_tracker.cc index 3516fb54..45251bb 100644 --- a/ui/latency/latency_tracker.cc +++ b/ui/latency/latency_tracker.cc
@@ -108,11 +108,15 @@ void LatencyTracker::ReportUkmScrollLatency( const InputMetricEvent& metric_event, - const std::string& metric_name, const LatencyInfo::LatencyComponent& start_component, - const LatencyInfo::LatencyComponent& end_component, + const LatencyInfo::LatencyComponent& + time_to_scroll_update_swap_begin_component, + const LatencyInfo::LatencyComponent& time_to_handled_component, + bool is_main_thread, const ukm::SourceId ukm_source_id) { - CONFIRM_EVENT_TIMES_EXIST(start_component, end_component) + CONFIRM_EVENT_TIMES_EXIST(start_component, + time_to_scroll_update_swap_begin_component) + CONFIRM_EVENT_TIMES_EXIST(start_component, time_to_handled_component) // Only report a subset of this metric as the volume is too high. if (metric_sampling_ && @@ -141,10 +145,17 @@ std::unique_ptr<ukm::UkmEntryBuilder> builder = ukm_recorder->GetEntryBuilder(ukm_source_id, event_name.c_str()); builder->AddMetric( - metric_name.c_str(), - std::max(static_cast<int64_t>(0), (end_component.last_event_time - - start_component.first_event_time) - .InMicroseconds())); + "TimeToScrollUpdateSwapBegin", + std::max(static_cast<int64_t>(0), + (time_to_scroll_update_swap_begin_component.last_event_time - + start_component.first_event_time) + .InMicroseconds())); + builder->AddMetric("TimeToHandled", + std::max(static_cast<int64_t>(0), + (time_to_handled_component.last_event_time - + start_component.first_event_time) + .InMicroseconds())); + builder->AddMetric("IsMainThread", is_main_thread); } void LatencyTracker::ComputeEndToEndLatencyHistograms( @@ -181,12 +192,6 @@ ".TimeToScrollUpdateSwapBegin2", original_component, gpu_swap_begin_component); - ReportUkmScrollLatency(input_modality == "Touch" - ? InputMetricEvent::SCROLL_BEGIN_TOUCH - : InputMetricEvent::SCROLL_BEGIN_WHEEL, - "TimeToScrollUpdateSwapBegin", original_component, - gpu_swap_begin_component, latency.ukm_source_id()); - } else if (latency.FindLatency( ui::INPUT_EVENT_LATENCY_SCROLL_UPDATE_ORIGINAL_COMPONENT, &original_component)) { @@ -209,11 +214,6 @@ ".TimeToScrollUpdateSwapBegin2", original_component, gpu_swap_begin_component); - ReportUkmScrollLatency(input_modality == "Touch" - ? InputMetricEvent::SCROLL_UPDATE_TOUCH - : InputMetricEvent::SCROLL_UPDATE_WHEEL, - "TimeToScrollUpdateSwapBegin", original_component, - gpu_swap_begin_component, latency.ukm_source_id()); } else if (latency.FindLatency(ui::INPUT_EVENT_LATENCY_ORIGINAL_COMPONENT, 0, &original_component)) { if (input_modality == "KeyPress") { @@ -239,6 +239,23 @@ &rendering_scheduled_component); DCHECK_AND_RETURN_ON_FAIL(found_component); } + if (input_modality == "Touch" || input_modality == "Wheel") { + InputMetricEvent input_metric_event; + if (scroll_name == "ScrollBegin") { + input_metric_event = input_modality == "Touch" + ? InputMetricEvent::SCROLL_BEGIN_TOUCH + : InputMetricEvent::SCROLL_BEGIN_WHEEL; + } else { + DCHECK_EQ(scroll_name, "ScrollUpdate"); + input_metric_event = input_modality == "Touch" + ? InputMetricEvent::SCROLL_UPDATE_TOUCH + : InputMetricEvent::SCROLL_UPDATE_WHEEL; + } + ReportUkmScrollLatency( + input_metric_event, original_component, gpu_swap_begin_component, + rendering_scheduled_component, rendering_scheduled_on_main, + latency.ukm_source_id()); + } const std::string thread_name = rendering_scheduled_on_main ? "Main" : "Impl";
diff --git a/ui/latency/latency_tracker.h b/ui/latency/latency_tracker.h index 36577ae7..f0180ebc4 100644 --- a/ui/latency/latency_tracker.h +++ b/ui/latency/latency_tracker.h
@@ -46,9 +46,11 @@ void ReportUkmScrollLatency( const InputMetricEvent& metric_event, - const std::string& metric_name, const LatencyInfo::LatencyComponent& start_component, - const LatencyInfo::LatencyComponent& end_component, + const LatencyInfo::LatencyComponent& + time_to_scroll_update_swap_begin_component, + const LatencyInfo::LatencyComponent& time_to_handled_component, + bool is_main_thread, const ukm::SourceId ukm_source_id); void ComputeEndToEndLatencyHistograms(
diff --git a/ui/ozone/common/gl_ozone_osmesa.cc b/ui/ozone/common/gl_ozone_osmesa.cc index af19a96..395995d 100644 --- a/ui/ozone/common/gl_ozone_osmesa.cc +++ b/ui/ozone/common/gl_ozone_osmesa.cc
@@ -28,14 +28,7 @@ bool GLOzoneOSMesa::InitializeStaticGLBindings( gl::GLImplementation implementation) { -#if defined(OS_FUCHSIA) - // TODO(fuchsia): Enable this once there's EGL available, see - // https://crbug.com/750943. - NOTIMPLEMENTED(); - return false; -#else return gl::InitializeStaticGLBindingsOSMesaGL(); -#endif } void GLOzoneOSMesa::InitializeDebugGLBindings() {
diff --git a/ui/ozone/platform/headless/headless_surface_factory.cc b/ui/ozone/platform/headless/headless_surface_factory.cc index 3c1b9b0..6e64f51 100644 --- a/ui/ozone/platform/headless/headless_surface_factory.cc +++ b/ui/ozone/platform/headless/headless_surface_factory.cc
@@ -130,9 +130,7 @@ HeadlessSurfaceFactory::HeadlessSurfaceFactory(base::FilePath base_path) : base_path_(base_path) { CheckBasePath(); -#if !defined(OS_FUCHSIA) osmesa_implementation_ = std::make_unique<GLOzoneOSMesaHeadless>(this); -#endif } HeadlessSurfaceFactory::~HeadlessSurfaceFactory() = default; @@ -148,11 +146,7 @@ std::vector<gl::GLImplementation> HeadlessSurfaceFactory::GetAllowedGLImplementations() { -#if defined(OS_FUCHSIA) - return std::vector<gl::GLImplementation>{gl::kGLImplementationStubGL}; -#else return std::vector<gl::GLImplementation>{gl::kGLImplementationOSMesaGL}; -#endif } GLOzone* HeadlessSurfaceFactory::GetGLOzone(
diff --git a/ui/ozone/platform/wayland/wayland_pointer_unittest.cc b/ui/ozone/platform/wayland/wayland_pointer_unittest.cc index 239d7a4..a342306 100644 --- a/ui/ozone/platform/wayland/wayland_pointer_unittest.cc +++ b/ui/ozone/platform/wayland/wayland_pointer_unittest.cc
@@ -43,7 +43,7 @@ TEST_P(WaylandPointerTest, Leave) { MockPlatformWindowDelegate other_delegate; - WaylandWindow other_window(&other_delegate, &connection, + WaylandWindow other_window(&other_delegate, connection.get(), gfx::Rect(0, 0, 10, 10)); gfx::AcceleratedWidget other_widget = gfx::kNullAcceleratedWidget; EXPECT_CALL(other_delegate, OnAcceleratedWidgetAvailable(_, _))
diff --git a/ui/ozone/platform/wayland/wayland_surface_factory_unittest.cc b/ui/ozone/platform/wayland/wayland_surface_factory_unittest.cc index 0d48521..73512e2 100644 --- a/ui/ozone/platform/wayland/wayland_surface_factory_unittest.cc +++ b/ui/ozone/platform/wayland/wayland_surface_factory_unittest.cc
@@ -19,7 +19,7 @@ class WaylandSurfaceFactoryTest : public WaylandTest { public: - WaylandSurfaceFactoryTest() : surface_factory(&connection) {} + WaylandSurfaceFactoryTest() : surface_factory(connection.get()) {} ~WaylandSurfaceFactoryTest() override {}
diff --git a/ui/ozone/platform/wayland/wayland_test.cc b/ui/ozone/platform/wayland/wayland_test.cc index 9036ed1c..60328cb 100644 --- a/ui/ozone/platform/wayland/wayland_test.cc +++ b/ui/ozone/platform/wayland/wayland_test.cc
@@ -11,17 +11,22 @@ namespace ui { -WaylandTest::WaylandTest() - : window(&delegate, &connection, gfx::Rect(0, 0, 800, 600)) {} +WaylandTest::WaylandTest() { + // TODO(tonikitoo): Set the proper KeyboardLayoutEngine instance here, + // before the WaylandConnection is instantiated. + connection.reset(new WaylandConnection); + window = std::make_unique<WaylandWindow>(&delegate, connection.get(), + gfx::Rect(0, 0, 800, 600)); +} WaylandTest::~WaylandTest() {} void WaylandTest::SetUp() { ASSERT_TRUE(server.Start(GetParam())); - ASSERT_TRUE(connection.Initialize()); + ASSERT_TRUE(connection->Initialize()); EXPECT_CALL(delegate, OnAcceleratedWidgetAvailable(_, _)) .WillOnce(SaveArg<0>(&widget)); - ASSERT_TRUE(window.Initialize()); + ASSERT_TRUE(window->Initialize()); ASSERT_NE(widget, gfx::kNullAcceleratedWidget); // Wait for the client to flush all pending requests from initialization.
diff --git a/ui/ozone/platform/wayland/wayland_test.h b/ui/ozone/platform/wayland/wayland_test.h index 918f039..459422d 100644 --- a/ui/ozone/platform/wayland/wayland_test.h +++ b/ui/ozone/platform/wayland/wayland_test.h
@@ -37,9 +37,9 @@ wl::FakeServer server; wl::MockSurface* surface; - WaylandConnection connection; MockPlatformWindowDelegate delegate; - WaylandWindow window; + std::unique_ptr<WaylandConnection> connection; + std::unique_ptr<WaylandWindow> window; gfx::AcceleratedWidget widget = gfx::kNullAcceleratedWidget; private:
diff --git a/ui/ozone/platform/wayland/wayland_window_unittest.cc b/ui/ozone/platform/wayland/wayland_window_unittest.cc index 70790d5e..ca2df44 100644 --- a/ui/ozone/platform/wayland/wayland_window_unittest.cc +++ b/ui/ozone/platform/wayland/wayland_window_unittest.cc
@@ -90,7 +90,7 @@ TEST_P(WaylandWindowTest, SetTitle) { EXPECT_CALL(*GetXdgSurface(), SetTitle(StrEq("hello"))); - window.SetTitle(base::ASCIIToUTF16("hello")); + window->SetTitle(base::ASCIIToUTF16("hello")); } TEST_P(WaylandWindowTest, MaximizeAndRestore) { @@ -102,16 +102,16 @@ EXPECT_CALL(*GetXdgSurface(), SetMaximized()); EXPECT_CALL(*GetXdgSurface(), UnsetMaximized()); - window.Maximize(); + window->Maximize(); SendConfigureEvent(0, 0, serial, &states); Sync(); - window.Restore(); + window->Restore(); } TEST_P(WaylandWindowTest, Minimize) { EXPECT_CALL(*GetXdgSurface(), SetMinimized()); - window.Minimize(); + window->Minimize(); } TEST_P(WaylandWindowTest, SetFullscreenAndRestore) { @@ -122,11 +122,11 @@ EXPECT_CALL(*GetXdgSurface(), SetFullscreen()); EXPECT_CALL(*GetXdgSurface(), UnsetFullscreen()); - window.ToggleFullscreen(); + window->ToggleFullscreen(); SendConfigureEvent(0, 0, 1, &states); Sync(); - window.Restore(); + window->Restore(); } TEST_P(WaylandWindowTest, SetMaximizedFullscreenAndRestore) { @@ -138,31 +138,31 @@ EXPECT_CALL(*GetXdgSurface(), SetMaximized()); EXPECT_CALL(*GetXdgSurface(), UnsetMaximized()); - window.Maximize(); + window->Maximize(); SetWlArrayWithState(XDG_SURFACE_STATE_MAXIMIZED, &states); SendConfigureEvent(0, 0, 2, &states); Sync(); - window.ToggleFullscreen(); + window->ToggleFullscreen(); SetWlArrayWithState(XDG_SURFACE_STATE_FULLSCREEN, &states); SendConfigureEvent(0, 0, 3, &states); Sync(); - window.Restore(); + window->Restore(); } TEST_P(WaylandWindowTest, CanDispatchMouseEventDefault) { - EXPECT_FALSE(window.CanDispatchEvent(&test_mouse_event)); + EXPECT_FALSE(window->CanDispatchEvent(&test_mouse_event)); } TEST_P(WaylandWindowTest, CanDispatchMouseEventFocus) { - window.set_pointer_focus(true); - EXPECT_TRUE(window.CanDispatchEvent(&test_mouse_event)); + window->set_pointer_focus(true); + EXPECT_TRUE(window->CanDispatchEvent(&test_mouse_event)); } TEST_P(WaylandWindowTest, CanDispatchMouseEventUnfocus) { - window.set_pointer_focus(false); - EXPECT_FALSE(window.CanDispatchEvent(&test_mouse_event)); + window->set_pointer_focus(false); + EXPECT_FALSE(window->CanDispatchEvent(&test_mouse_event)); } ACTION_P(CloneEvent, ptr) { @@ -172,7 +172,7 @@ TEST_P(WaylandWindowTest, DispatchEvent) { std::unique_ptr<Event> event; EXPECT_CALL(delegate, DispatchEvent(_)).WillOnce(CloneEvent(&event)); - window.DispatchEvent(&test_mouse_event); + window->DispatchEvent(&test_mouse_event); ASSERT_TRUE(event); ASSERT_TRUE(event->IsMouseEvent()); auto* mouse_event = event->AsMouseEvent();