diff --git a/DEPS b/DEPS index 8344f20..b2a2fcf 100644 --- a/DEPS +++ b/DEPS
@@ -105,11 +105,11 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling Skia # and whatever else without interference from each other. - 'skia_revision': '43a5497bf64323031753fd40432c7f0b2de5cd50', + 'skia_revision': '9c37cd96e4c8158643dbde6fd3eda1b42e267bec', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling V8 # and whatever else without interference from each other. - 'v8_revision': '80d8889e4e4eead687e2aabe7dc60c23c17bd3a1', + 'v8_revision': 'f70aaa8ab2e8815505a6145c745e50d8328cd28c', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling swarming_client # and whatever else without interference from each other. @@ -137,7 +137,7 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling BoringSSL # and whatever else without interference from each other. - 'boringssl_revision': 'ce00828c89df3d4c40de7d715b1a032eb03c525c', + 'boringssl_revision': '2d98d49cf712ca7dc6f4b23b9c5f5542385d8dbe', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling google-toolbox-for-mac # and whatever else without interference from each other. @@ -165,7 +165,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': 'cd3378c32017c99062cd467a3ff601e0b57f0c23', + 'catapult_revision': 'c8b97e37ec9c447eee46830c6e0598af7b9bd539', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling libFuzzer # and whatever else without interference from each other. @@ -600,7 +600,7 @@ # Build tools for Chrome OS. Note: This depends on third_party/pyelftools. 'src/third_party/chromite': { - 'url': Var('chromium_git') + '/chromiumos/chromite.git' + '@' + 'abdecf34eac97c4f2b2d2e5b2d6bea5d4b97fee1', + 'url': Var('chromium_git') + '/chromiumos/chromite.git' + '@' + '7b5fdb9c2a7f35145dda05caf3bef1de8929c50b', 'condition': 'checkout_linux', }, @@ -1010,7 +1010,7 @@ }, 'src/third_party/re2/src': - Var('chromium_git') + '/external/github.com/google/re2.git' + '@' + '54ca2cd59219aab637e7a5e1e6d0f383a36df192', + Var('chromium_git') + '/external/github.com/google/re2.git' + '@' + '6272edcb53d3c8705f57df3b46b1f92e646e30bc', 'src/third_party/r8': { 'packages': [ @@ -1106,7 +1106,7 @@ Var('chromium_git') + '/external/khronosgroup/webgl.git' + '@' + '6d2f3f4cb8bac1f7c4a945c73d07a33df74f22f9', 'src/third_party/webrtc': - Var('webrtc_git') + '/src.git' + '@' + 'e8d2b1be1a7c39fd405a9f8061467008869f24bd', + Var('webrtc_git') + '/src.git' + '@' + 'f81170b48fd43fa4463d5cddd2815aaae6f30217', 'src/third_party/xdg-utils': { 'url': Var('chromium_git') + '/chromium/deps/xdg-utils.git' + '@' + 'd80274d5869b17b8c9067a1022e4416ee7ed5e0d', @@ -1137,7 +1137,7 @@ Var('chromium_git') + '/v8/v8.git' + '@' + Var('v8_revision'), 'src-internal': { - 'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@fbc78231d0587866b6ee16516308e11ec04823e7', + 'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@2146d0609ce9176edd452ec0bcbb225a4aca43c6', 'condition': 'checkout_src_internal', },
diff --git a/WATCHLISTS b/WATCHLISTS index 9e2b76b..8ee3606 100644 --- a/WATCHLISTS +++ b/WATCHLISTS
@@ -618,7 +618,7 @@ '|chrome/browser/resources/settings/', }, 'browsing_data': { - 'filepath': '/browsing_data/', + 'filepath': 'browsing_data|BrowsingData', }, 'bubble': { 'filepath': 'ui/views/bubble/|'\
diff --git a/ash/system/message_center/message_list_view.cc b/ash/system/message_center/message_list_view.cc index 698c202..6e2b5a2 100644 --- a/ash/system/message_center/message_list_view.cc +++ b/ash/system/message_center/message_list_view.cc
@@ -433,7 +433,7 @@ if (need_update) DoUpdateIfPossible(); - if (GetWidget()) + if (GetWidget() && !GetWidget()->IsClosed()) GetWidget()->SynthesizeMouseMoveEvent(); }
diff --git a/ash/system/message_center/new_unified_message_center_view.cc b/ash/system/message_center/new_unified_message_center_view.cc index bb99c34..7a03cc0 100644 --- a/ash/system/message_center/new_unified_message_center_view.cc +++ b/ash/system/message_center/new_unified_message_center_view.cc
@@ -96,7 +96,7 @@ PreferredSizeChanged(); ScrollToPositionFromBottom(); - if (GetWidget()) + if (GetWidget() && !GetWidget()->IsClosed()) GetWidget()->SynthesizeMouseMoveEvent(); }
diff --git a/ash/wm/splitview/split_view_controller_unittest.cc b/ash/wm/splitview/split_view_controller_unittest.cc index 293bec3..6e4019b 100644 --- a/ash/wm/splitview/split_view_controller_unittest.cc +++ b/ash/wm/splitview/split_view_controller_unittest.cc
@@ -44,6 +44,7 @@ #include "ui/compositor_extra/shadow.h" #include "ui/display/test/display_manager_test_api.h" #include "ui/events/test/event_generator.h" +#include "ui/views/bubble/bubble_dialog_delegate_view.h" #include "ui/views/widget/widget.h" #include "ui/wm/core/shadow_controller.h" #include "ui/wm/core/shadow_types.h" @@ -89,6 +90,17 @@ DISALLOW_COPY_AND_ASSIGN(OverviewStatesObserver); }; +// The test BubbleDialogDelegateView for bubbles. +class TestBubbleDialogDelegateView : public views::BubbleDialogDelegateView { + public: + explicit TestBubbleDialogDelegateView(views::View* anchor_view) + : BubbleDialogDelegateView(anchor_view, views::BubbleBorder::NONE) {} + ~TestBubbleDialogDelegateView() override {} + + private: + DISALLOW_COPY_AND_ASSIGN(TestBubbleDialogDelegateView); +}; + } // namespace class SplitViewControllerTest : public AshTestBase { @@ -1614,6 +1626,34 @@ EXPECT_FALSE(Shell::Get()->window_selector_controller()->IsSelecting()); } +// Tests that if a snapped window has a bubble transient child, the bubble's +// bounds should always align with the snapped window's bounds. +TEST_F(SplitViewControllerTest, AdjustTransientChildBounds) { + std::unique_ptr<views::Widget> widget(CreateTestWidget()); + aura::Window* window = widget->GetNativeWindow(); + window->SetProperty(aura::client::kResizeBehaviorKey, + ws::mojom::kResizeBehaviorCanResize | + ws::mojom::kResizeBehaviorCanMaximize); + split_view_controller()->SnapWindow(window, SplitViewController::LEFT); + const gfx::Rect window_bounds = window->GetBoundsInScreen(); + + // Create a bubble widget that's anchored to |widget|. + views::Widget* bubble_widget = views::BubbleDialogDelegateView::CreateBubble( + new TestBubbleDialogDelegateView(widget->GetContentsView())); + aura::Window* bubble_window = bubble_widget->GetNativeWindow(); + EXPECT_TRUE(::wm::HasTransientAncestor(bubble_window, window)); + // Test that the bubble is created inside its anchor widget. + EXPECT_TRUE(window_bounds.Contains(bubble_window->GetBoundsInScreen())); + + // Now try to manually move the bubble out of the snapped window. + bubble_window->SetBoundsInScreen( + split_view_controller()->GetSnappedWindowBoundsInScreen( + window, SplitViewController::RIGHT), + display::Screen::GetScreen()->GetDisplayNearestWindow(window)); + // Test that the bubble can't be moved outside of its anchor widget. + EXPECT_TRUE(window_bounds.Contains(bubble_window->GetBoundsInScreen())); +} + // Test the tab-dragging related functionalities in tablet mode. Tab(s) can be // dragged out of a window and then put in split view mode or merge into another // window.
diff --git a/ash/wm/splitview/split_view_divider.cc b/ash/wm/splitview/split_view_divider.cc index 8b957b2..2f80bdf 100644 --- a/ash/wm/splitview/split_view_divider.cc +++ b/ash/wm/splitview/split_view_divider.cc
@@ -25,7 +25,10 @@ #include "ui/views/view.h" #include "ui/views/view_targeter_delegate.h" #include "ui/views/widget/widget.h" +#include "ui/views/widget/widget_delegate.h" #include "ui/wm/core/coordinate_conversion.h" +#include "ui/wm/core/transient_window_manager.h" +#include "ui/wm/core/window_util.h" #include "ui/wm/public/activation_client.h" namespace ash { @@ -383,6 +386,7 @@ void SplitViewDivider::AddObservedWindow(aura::Window* window) { if (!base::ContainsValue(observed_windows_, window)) { window->AddObserver(this); + ::wm::TransientWindowManager::GetOrCreate(window)->AddObserver(this); observed_windows_.push_back(window); } } @@ -392,6 +396,7 @@ std::find(observed_windows_.begin(), observed_windows_.end(), window); if (iter != observed_windows_.end()) { window->RemoveObserver(this); + ::wm::TransientWindowManager::GetOrCreate(window)->RemoveObserver(this); observed_windows_.erase(iter); } } @@ -413,6 +418,33 @@ RemoveObservedWindow(window); } +void SplitViewDivider::OnWindowBoundsChanged(aura::Window* window, + const gfx::Rect& old_bounds, + const gfx::Rect& new_bounds, + ui::PropertyChangeReason reason) { + // We only care about the bounds change of windows in + // |transient_windows_observer_|. + if (!transient_windows_observer_.IsObserving(window)) + return; + + // |window|'s transient parent must be one of the windows in + // |observed_windows_|. + aura::Window* transient_parent = nullptr; + for (auto* observed_window : observed_windows_) { + if (::wm::HasTransientAncestor(window, observed_window)) { + transient_parent = observed_window; + break; + } + } + DCHECK(transient_parent); + + gfx::Rect transient_bounds = window->GetBoundsInScreen(); + transient_bounds.AdjustToFit(transient_parent->GetBoundsInScreen()); + window->SetBoundsInScreen( + transient_bounds, + display::Screen::GetScreen()->GetDisplayNearestWindow(window)); +} + void SplitViewDivider::OnWindowActivated(ActivationReason reason, aura::Window* gained_active, aura::Window* lost_active) { @@ -428,6 +460,26 @@ } } +void SplitViewDivider::OnTransientChildAdded(aura::Window* window, + aura::Window* transient) { + // For now, we only care about dialog bubbles type transient child. We may + // observe other types transient child window as well if need arises in the + // future. + views::Widget* widget = views::Widget::GetWidgetForNativeWindow(transient); + if (!widget || !widget->widget_delegate()->AsBubbleDialogDelegate()) + return; + + // At this moment, the transient window may not have the valid bounds yet. + // Start observe the transient window. + transient_windows_observer_.Add(transient); +} + +void SplitViewDivider::OnTransientChildRemoved(aura::Window* window, + aura::Window* transient) { + if (transient_windows_observer_.IsObserving(transient)) + transient_windows_observer_.Remove(transient); +} + void SplitViewDivider::CreateDividerWidget(aura::Window* root_window) { DCHECK(!divider_widget_); // Native widget owns this widget.
diff --git a/ash/wm/splitview/split_view_divider.h b/ash/wm/splitview/split_view_divider.h index aa9349dd..25a8f3e 100644 --- a/ash/wm/splitview/split_view_divider.h +++ b/ash/wm/splitview/split_view_divider.h
@@ -9,12 +9,14 @@ #include "ash/ash_export.h" #include "base/macros.h" +#include "base/scoped_observer.h" #include "ui/aura/window.h" #include "ui/aura/window_observer.h" #include "ui/display/display.h" #include "ui/gfx/geometry/point.h" #include "ui/gfx/geometry/rect.h" #include "ui/gfx/geometry/size.h" +#include "ui/wm/core/transient_window_observer.h" #include "ui/wm/public/activation_change_observer.h" namespace views { @@ -34,7 +36,8 @@ // to resize the left and right windows accordingly. The divider widget should // always placed above its observed windows to be able to receive events. class ASH_EXPORT SplitViewDivider : public aura::WindowObserver, - public ::wm::ActivationChangeObserver { + public ::wm::ActivationChangeObserver, + public ::wm::TransientWindowObserver { public: SplitViewDivider(SplitViewController* controller, aura::Window* root_window); ~SplitViewDivider() override; @@ -74,6 +77,16 @@ void OnWindowActivated(ActivationReason reason, aura::Window* gained_active, aura::Window* lost_active) override; + void OnWindowBoundsChanged(aura::Window* window, + const gfx::Rect& old_bounds, + const gfx::Rect& new_bounds, + ui::PropertyChangeReason reason) override; + + // ::wm::TransientWindowObserver: + void OnTransientChildAdded(aura::Window* window, + aura::Window* transient) override; + void OnTransientChildRemoved(aura::Window* window, + aura::Window* transient) override; views::Widget* divider_widget() { return divider_widget_; } @@ -101,6 +114,10 @@ // Tracks observed windows. aura::Window::Windows observed_windows_; + // Tracks observed transient windows. + ScopedObserver<aura::Window, aura::WindowObserver> + transient_windows_observer_{this}; + DISALLOW_COPY_AND_ASSIGN(SplitViewDivider); };
diff --git a/base/android/java/src/org/chromium/base/ApiCompatibilityUtils.java b/base/android/java/src/org/chromium/base/ApiCompatibilityUtils.java index 70177cd..197bdeb 100644 --- a/base/android/java/src/org/chromium/base/ApiCompatibilityUtils.java +++ b/base/android/java/src/org/chromium/base/ApiCompatibilityUtils.java
@@ -46,6 +46,7 @@ import android.view.inputmethod.InputMethodSubtype; import android.view.textclassifier.TextClassifier; import android.widget.ImageView; +import android.widget.PopupWindow; import android.widget.TextView; import java.io.File; @@ -326,6 +327,17 @@ } /** + * Set elevation if supported. + */ + @TargetApi(Build.VERSION_CODES.LOLLIPOP) + public static boolean setElevation(PopupWindow window, float elevationValue) { + if (!isElevationSupported()) return false; + + window.setElevation(elevationValue); + return true; + } + + /** * Gets an intent to start the Android system notification settings activity for an app. * * @param context Context of the app whose settings intent should be returned.
diff --git a/base/android/scoped_java_ref.h b/base/android/scoped_java_ref.h index 8bb18d4..5e8bc04 100644 --- a/base/android/scoped_java_ref.h +++ b/base/android/scoped_java_ref.h
@@ -36,42 +36,51 @@ }; // Forward declare the generic java reference template class. -template<typename T> class JavaRef; +template <typename T> +class JavaRef; // Template specialization of JavaRef, which acts as the base class for all // other JavaRef<> template types. This allows you to e.g. pass // ScopedJavaLocalRef<jstring> into a function taking const JavaRef<jobject>& -template<> +template <> class BASE_EXPORT JavaRef<jobject> { public: - // Initializes a null reference. Don't add anything else here; it's inlined. - constexpr JavaRef() : obj_(nullptr) {} + // Initializes a null reference. + constexpr JavaRef() {} // Allow nullptr to be converted to JavaRef. This avoids having to declare an // empty JavaRef just to pass null to a function, and makes C++ "nullptr" and // Java "null" equivalent. - constexpr JavaRef(std::nullptr_t) : JavaRef() {} + constexpr JavaRef(std::nullptr_t) {} // Public to allow destruction of null JavaRef objects. - // Don't add anything else here; it's inlined. ~JavaRef() {} + // TODO(torne): maybe rename this to get() for consistency with unique_ptr + // once there's fewer unnecessary uses of it in the codebase. jobject obj() const { return obj_; } + explicit operator bool() const { return obj_ != nullptr; } + + // Deprecated. Just use bool conversion. + // TODO(torne): replace usage and remove this. bool is_null() const { return obj_ == nullptr; } protected: - // Takes ownership of the |obj| reference passed; requires it to be a local - // reference type. +// Takes ownership of the |obj| reference passed; requires it to be a local +// reference type. #if DCHECK_IS_ON() // Implementation contains a DCHECK; implement out-of-line when DCHECK_IS_ON. JavaRef(JNIEnv* env, jobject obj); #else - // Don't add anything else here; it's inlined. JavaRef(JNIEnv* env, jobject obj) : obj_(obj) {} #endif - void swap(JavaRef& other) { std::swap(obj_, other.obj_); } + // Used for move semantics. obj_ must have been released first if non-null. + void steal(JavaRef&& other) { + obj_ = other.obj_; + other.obj_ = nullptr; + } // The following are implementation detail convenience methods, for // use by the sub-classes. @@ -82,7 +91,7 @@ jobject ReleaseInternal(); private: - jobject obj_; + jobject obj_ = nullptr; DISALLOW_COPY_AND_ASSIGN(JavaRef); }; @@ -90,11 +99,11 @@ // Generic base class for ScopedJavaLocalRef and ScopedJavaGlobalRef. Useful // for allowing functions to accept a reference without having to mandate // whether it is a local or global type. -template<typename T> +template <typename T> class JavaRef : public JavaRef<jobject> { public: - JavaRef() {} - JavaRef(std::nullptr_t) : JavaRef<jobject>(nullptr) {} + constexpr JavaRef() {} + constexpr JavaRef(std::nullptr_t) {} ~JavaRef() {} T obj() const { return static_cast<T>(JavaRef<jobject>::obj()); } @@ -110,7 +119,7 @@ // Method parameters should not be deleted, and so this class exists purely to // wrap them as a JavaRef<T> in the JNI binding generator. Do not create // instances manually. -template<typename T> +template <typename T> class JavaParamRef : public JavaRef<T> { public: // Assumes that |obj| is a parameter passed to a JNI method from Java. @@ -121,7 +130,7 @@ // methods directly from C++ and pass null for objects which are not actually // used by the implementation (e.g. the caller object); allow this to keep // working. - JavaParamRef(std::nullptr_t) : JavaRef<T>(nullptr) {} + JavaParamRef(std::nullptr_t) {} ~JavaParamRef() {} @@ -143,81 +152,126 @@ // single thread. If you wish to have the reference outlive the current // callstack (e.g. as a class member) or you wish to pass it across threads, // use a ScopedJavaGlobalRef instead. -template<typename T> +template <typename T> class ScopedJavaLocalRef : public JavaRef<T> { public: - constexpr ScopedJavaLocalRef() : env_(nullptr) {} - constexpr ScopedJavaLocalRef(std::nullptr_t) : env_(nullptr) {} - - // Non-explicit copy constructor, to allow ScopedJavaLocalRef to be returned - // by value as this is the normal usage pattern. - ScopedJavaLocalRef(const ScopedJavaLocalRef<T>& other) - : env_(other.env_) { - this->SetNewLocalRef(env_, other.obj()); + // Take ownership of a bare jobject. This does not create a new reference. + // This should only be used by JNI helper functions, or in cases where code + // must call JNIEnv methods directly. + static ScopedJavaLocalRef Adopt(JNIEnv* env, T obj) { + return ScopedJavaLocalRef(env, obj); } - ScopedJavaLocalRef(ScopedJavaLocalRef<T>&& other) : env_(other.env_) { - this->swap(other); + constexpr ScopedJavaLocalRef() {} + constexpr ScopedJavaLocalRef(std::nullptr_t) {} + + // Copy constructor. This is required in addition to the copy conversion + // constructor below. + ScopedJavaLocalRef(const ScopedJavaLocalRef& other) : env_(other.env_) { + JavaRef<T>::SetNewLocalRef(env_, other.obj()); } - explicit ScopedJavaLocalRef(const JavaRef<T>& other) : env_(nullptr) { - this->Reset(other); + // Copy conversion constructor. + template <typename U, + typename = std::enable_if_t<std::is_convertible<U, T>::value>> + ScopedJavaLocalRef(const ScopedJavaLocalRef<U>& other) : env_(other.env_) { + JavaRef<T>::SetNewLocalRef(env_, other.obj()); } + // Move constructor. This is required in addition to the move conversion + // constructor below. + ScopedJavaLocalRef(ScopedJavaLocalRef&& other) : env_(other.env_) { + JavaRef<T>::steal(std::move(other)); + } + + // Move conversion constructor. + template <typename U, + typename = std::enable_if_t<std::is_convertible<U, T>::value>> + ScopedJavaLocalRef(ScopedJavaLocalRef<U>&& other) : env_(other.env_) { + JavaRef<T>::steal(std::move(other)); + } + + // Constructor for other JavaRef types. + explicit ScopedJavaLocalRef(const JavaRef<T>& other) { Reset(other); } + // Assumes that |obj| is a local reference to a Java object and takes - // ownership of this local reference. - // TODO(torne): this shouldn't be used outside of JNI helper functions but - // there are currently some cases where there aren't helpers for things. + // ownership of this local reference. + // TODO(torne): make legitimate uses call Adopt() instead, and make this + // private. ScopedJavaLocalRef(JNIEnv* env, T obj) : JavaRef<T>(env, obj), env_(env) {} - ~ScopedJavaLocalRef() { - this->Reset(); + ~ScopedJavaLocalRef() { Reset(); } + + // Null assignment, for disambiguation. + ScopedJavaLocalRef& operator=(std::nullptr_t) { + Reset(); + return *this; } - // Overloaded assignment operator defined for consistency with the implicit - // copy constructor. - void operator=(const ScopedJavaLocalRef<T>& other) { - this->Reset(other); + // Copy assignment. + ScopedJavaLocalRef& operator=(const ScopedJavaLocalRef& other) { + Reset(other); + return *this; } - void operator=(ScopedJavaLocalRef<T>&& other) { + // Copy conversion assignment. + template <typename U, + typename = std::enable_if_t<std::is_convertible<U, T>::value>> + ScopedJavaLocalRef& operator=(const ScopedJavaLocalRef<U>& other) { + Reset(other); + return *this; + } + + // Move assignment. + template <typename U, + typename = std::enable_if_t<std::is_convertible<U, T>::value>> + ScopedJavaLocalRef& operator=(ScopedJavaLocalRef<U>&& other) { env_ = other.env_; - this->swap(other); + Reset(); + JavaRef<T>::steal(std::move(other)); + return *this; } - void Reset() { - this->ResetLocalRef(env_); + // Assignment for other JavaRef types. + ScopedJavaLocalRef& operator=(const JavaRef<T>& other) { + Reset(other); + return *this; } - void Reset(const ScopedJavaLocalRef<T>& other) { + void Reset() { JavaRef<T>::ResetLocalRef(env_); } + + template <typename U, + typename = std::enable_if_t<std::is_convertible<U, T>::value>> + void Reset(const ScopedJavaLocalRef<U>& other) { // We can copy over env_ here as |other| instance must be from the same // thread as |this| local ref. (See class comment for multi-threading // limitations, and alternatives). - this->Reset(other.env_, other.obj()); + Reset(other.env_, other.obj()); } void Reset(const JavaRef<T>& other) { // If |env_| was not yet set (is still null) it will be attached to the // current thread in SetNewLocalRef(). - this->Reset(env_, other.obj()); + Reset(env_, other.obj()); } // Creates a new local reference to the Java object, unlike the constructor // with the same parameters that takes ownership of the existing reference. - // TODO(torne): these should match as this is confusing. - void Reset(JNIEnv* env, T obj) { env_ = this->SetNewLocalRef(env, obj); } + // Deprecated. Don't use bare jobjects; use a JavaRef as the input. + // TODO(torne): fix existing usage and remove this. + void Reset(JNIEnv* env, T obj) { + env_ = JavaRef<T>::SetNewLocalRef(env, obj); + } // Releases the local reference to the caller. The caller *must* delete the // local reference when it is done with it. Note that calling a Java method // is *not* a transfer of ownership and Release() should not be used. - T Release() { - return static_cast<T>(this->ReleaseInternal()); - } + T Release() { return static_cast<T>(JavaRef<T>::ReleaseInternal()); } private: // This class is only good for use on the thread it was created on so // it's safe to cache the non-threadsafe JNIEnv* inside this object. - JNIEnv* env_; + JNIEnv* env_ = nullptr; // Prevent ScopedJavaLocalRef(JNIEnv*, T obj) from being used to take // ownership of a JavaParamRef's underlying object - parameters are not @@ -225,58 +279,112 @@ // TODO(torne): this can be removed once JavaParamRef no longer has an // implicit conversion back to T. ScopedJavaLocalRef(JNIEnv* env, const JavaParamRef<T>& other); + + // Friend required to get env_ from conversions. + template <typename U> + friend class ScopedJavaLocalRef; }; // Holds a global reference to a Java object. The global reference is scoped // to the lifetime of this object. This class does not hold onto any JNIEnv* // passed to it, hence it is safe to use across threads (within the constraints // imposed by the underlying Java object that it references). -template<typename T> +template <typename T> class ScopedJavaGlobalRef : public JavaRef<T> { public: constexpr ScopedJavaGlobalRef() {} constexpr ScopedJavaGlobalRef(std::nullptr_t) {} - ScopedJavaGlobalRef(const ScopedJavaGlobalRef<T>& other) { - this->Reset(other); + // Copy constructor. This is required in addition to the copy conversion + // constructor below. + ScopedJavaGlobalRef(const ScopedJavaGlobalRef& other) { Reset(other); } + + // Copy conversion constructor. + template <typename U, + typename = std::enable_if_t<std::is_convertible<U, T>::value>> + ScopedJavaGlobalRef(const ScopedJavaGlobalRef<U>& other) { + Reset(other); } - ScopedJavaGlobalRef(ScopedJavaGlobalRef<T>&& other) { this->swap(other); } - - ScopedJavaGlobalRef(JNIEnv* env, T obj) { this->Reset(env, obj); } - - explicit ScopedJavaGlobalRef(const JavaRef<T>& other) { this->Reset(other); } - - ~ScopedJavaGlobalRef() { - this->Reset(); + // Move constructor. This is required in addition to the move conversion + // constructor below. + ScopedJavaGlobalRef(ScopedJavaGlobalRef&& other) { + JavaRef<T>::steal(std::move(other)); } - // Overloaded assignment operator defined for consistency with the implicit - // copy constructor. - void operator=(const ScopedJavaGlobalRef<T>& other) { - this->Reset(other); + // Move conversion constructor. + template <typename U, + typename = std::enable_if_t<std::is_convertible<U, T>::value>> + ScopedJavaGlobalRef(ScopedJavaGlobalRef<U>&& other) { + JavaRef<T>::steal(std::move(other)); } - void operator=(ScopedJavaGlobalRef<T>&& other) { this->swap(other); } + // Conversion constructor for other JavaRef types. + explicit ScopedJavaGlobalRef(const JavaRef<T>& other) { Reset(other); } - void Reset() { - this->ResetGlobalRef(); + // Create a new global reference to the object. + // Deprecated. Don't use bare jobjects; use a JavaRef as the input. + ScopedJavaGlobalRef(JNIEnv* env, T obj) { Reset(env, obj); } + + ~ScopedJavaGlobalRef() { Reset(); } + + // Null assignment, for disambiguation. + ScopedJavaGlobalRef& operator=(std::nullptr_t) { + Reset(); + return *this; } - void Reset(const JavaRef<T>& other) { this->Reset(nullptr, other.obj()); } + // Copy assignment. + ScopedJavaGlobalRef& operator=(const ScopedJavaGlobalRef& other) { + Reset(other); + return *this; + } + // Copy conversion assignment. + template <typename U, + typename = std::enable_if_t<std::is_convertible<U, T>::value>> + ScopedJavaGlobalRef& operator=(const ScopedJavaGlobalRef<U>& other) { + Reset(other); + return *this; + } + + // Move assignment. + template <typename U, + typename = std::enable_if_t<std::is_convertible<U, T>::value>> + ScopedJavaGlobalRef& operator=(ScopedJavaGlobalRef<U>&& other) { + Reset(); + JavaRef<T>::steal(std::move(other)); + return *this; + } + + // Assignment for other JavaRef types. + ScopedJavaGlobalRef& operator=(const JavaRef<T>& other) { + Reset(other); + return *this; + } + + void Reset() { JavaRef<T>::ResetGlobalRef(); } + + template <typename U, + typename = std::enable_if_t<std::is_convertible<U, T>::value>> + void Reset(const ScopedJavaGlobalRef<U>& other) { + Reset(nullptr, other.obj()); + } + + void Reset(const JavaRef<T>& other) { Reset(nullptr, other.obj()); } + + // Deprecated. You can just use Reset(const JavaRef&). void Reset(JNIEnv* env, const JavaParamRef<T>& other) { - this->Reset(env, other.obj()); + Reset(env, other.obj()); } - void Reset(JNIEnv* env, T obj) { this->SetNewGlobalRef(env, obj); } + // Deprecated. Don't use bare jobjects; use a JavaRef as the input. + void Reset(JNIEnv* env, T obj) { JavaRef<T>::SetNewGlobalRef(env, obj); } // Releases the global reference to the caller. The caller *must* delete the // global reference when it is done with it. Note that calling a Java method // is *not* a transfer of ownership and Release() should not be used. - T Release() { - return static_cast<T>(this->ReleaseInternal()); - } + T Release() { return static_cast<T>(JavaRef<T>::ReleaseInternal()); } }; } // namespace android
diff --git a/base/android/scoped_java_ref_unittest.cc b/base/android/scoped_java_ref_unittest.cc index 99d035b..d46c5ac 100644 --- a/base/android/scoped_java_ref_unittest.cc +++ b/base/android/scoped_java_ref_unittest.cc
@@ -8,6 +8,9 @@ #include "base/android/jni_string.h" #include "testing/gtest/include/gtest/gtest.h" +#define EXPECT_SAME_OBJECT(a, b) \ + EXPECT_TRUE(env->IsSameObject(a.obj(), b.obj())) + namespace base { namespace android { @@ -69,13 +72,110 @@ JNIEnv* env = AttachCurrentThread(); ScopedJavaLocalRef<jstring> str = ConvertUTF8ToJavaString(env, "string"); ScopedJavaGlobalRef<jstring> global(str); + + // Contextual conversions to bool should be allowed. + EXPECT_TRUE(str); + EXPECT_FALSE(JavaRef<jobject>()); + + // All the types should convert from nullptr, even JavaRef. + { + JavaRef<jstring> null_ref(nullptr); + EXPECT_FALSE(null_ref); + ScopedJavaLocalRef<jobject> null_local(nullptr); + EXPECT_FALSE(null_local); + ScopedJavaGlobalRef<jarray> null_global(nullptr); + EXPECT_FALSE(null_global); + } + + // Local and global refs should {copy,move}-{construct,assign}. + // Moves should leave the source as null. + { + ScopedJavaLocalRef<jstring> str2(str); + EXPECT_SAME_OBJECT(str2, str); + ScopedJavaLocalRef<jstring> str3(std::move(str2)); + EXPECT_SAME_OBJECT(str3, str); + EXPECT_FALSE(str2); + ScopedJavaLocalRef<jstring> str4; + str4 = str; + EXPECT_SAME_OBJECT(str4, str); + ScopedJavaLocalRef<jstring> str5; + str5 = std::move(str4); + EXPECT_SAME_OBJECT(str5, str); + EXPECT_FALSE(str4); + } + { + ScopedJavaGlobalRef<jstring> str2(global); + EXPECT_SAME_OBJECT(str2, str); + ScopedJavaGlobalRef<jstring> str3(std::move(str2)); + EXPECT_SAME_OBJECT(str3, str); + EXPECT_FALSE(str2); + ScopedJavaGlobalRef<jstring> str4; + str4 = global; + EXPECT_SAME_OBJECT(str4, str); + ScopedJavaGlobalRef<jstring> str5; + str5 = std::move(str4); + EXPECT_SAME_OBJECT(str5, str); + EXPECT_FALSE(str4); + } + + // As above but going from jstring to jobject. + { + ScopedJavaLocalRef<jobject> obj2(str); + EXPECT_SAME_OBJECT(obj2, str); + ScopedJavaLocalRef<jobject> obj3(std::move(obj2)); + EXPECT_SAME_OBJECT(obj3, str); + EXPECT_FALSE(obj2); + ScopedJavaLocalRef<jobject> obj4; + obj4 = str; + EXPECT_SAME_OBJECT(obj4, str); + ScopedJavaLocalRef<jobject> obj5; + obj5 = std::move(obj4); + EXPECT_SAME_OBJECT(obj5, str); + EXPECT_FALSE(obj4); + } + { + ScopedJavaGlobalRef<jobject> obj2(global); + EXPECT_SAME_OBJECT(obj2, str); + ScopedJavaGlobalRef<jobject> obj3(std::move(obj2)); + EXPECT_SAME_OBJECT(obj3, str); + EXPECT_FALSE(obj2); + ScopedJavaGlobalRef<jobject> obj4; + obj4 = global; + EXPECT_SAME_OBJECT(obj4, str); + ScopedJavaGlobalRef<jobject> obj5; + obj5 = std::move(obj4); + EXPECT_SAME_OBJECT(obj5, str); + EXPECT_FALSE(obj4); + } + + // Explicit copy construction or assignment between global<->local is allowed, + // but not implicit conversions. + { + ScopedJavaLocalRef<jstring> new_local(global); + EXPECT_SAME_OBJECT(new_local, str); + new_local = global; + EXPECT_SAME_OBJECT(new_local, str); + ScopedJavaGlobalRef<jstring> new_global(str); + EXPECT_SAME_OBJECT(new_global, str); + new_global = str; + EXPECT_SAME_OBJECT(new_local, str); + static_assert(!std::is_convertible<ScopedJavaLocalRef<jobject>, + ScopedJavaGlobalRef<jobject>>::value, + ""); + static_assert(!std::is_convertible<ScopedJavaGlobalRef<jobject>, + ScopedJavaLocalRef<jobject>>::value, + ""); + } + + // Converting between local/global while also converting to jobject also works + // because JavaRef<jobject> is the base class. { ScopedJavaGlobalRef<jobject> global_obj(str); ScopedJavaLocalRef<jobject> local_obj(global); const JavaRef<jobject>& obj_ref1(str); const JavaRef<jobject>& obj_ref2(global); - EXPECT_TRUE(env->IsSameObject(obj_ref1.obj(), obj_ref2.obj())); - EXPECT_TRUE(env->IsSameObject(global_obj.obj(), obj_ref2.obj())); + EXPECT_SAME_OBJECT(obj_ref1, obj_ref2); + EXPECT_SAME_OBJECT(global_obj, obj_ref2); } global.Reset(str); const JavaRef<jstring>& str_ref = str; @@ -99,7 +199,7 @@ EXPECT_EQ(1, g_local_refs); EXPECT_EQ(2, g_global_refs); - ScopedJavaLocalRef<jstring> str2(env, str.Release()); + auto str2 = ScopedJavaLocalRef<jstring>::Adopt(env, str.Release()); EXPECT_EQ(1, g_local_refs); { ScopedJavaLocalRef<jstring> str3(str2);
diff --git a/base/bind_unittest.cc b/base/bind_unittest.cc index 48b23b24..438e75a 100644 --- a/base/bind_unittest.cc +++ b/base/bind_unittest.cc
@@ -1073,7 +1073,7 @@ using MoveOnlyVector = std::vector<std::unique_ptr<int>>; MoveOnlyVector v; - v.push_back(WrapUnique(new int(12345))); + v.push_back(std::make_unique<int>(12345)); // Early binding should work: base::Callback<MoveOnlyVector()> bound_cb =
diff --git a/base/cancelable_callback_unittest.cc b/base/cancelable_callback_unittest.cc index 373498c..42e753f 100644 --- a/base/cancelable_callback_unittest.cc +++ b/base/cancelable_callback_unittest.cc
@@ -9,7 +9,6 @@ #include "base/bind.h" #include "base/bind_helpers.h" #include "base/location.h" -#include "base/memory/ptr_util.h" #include "base/memory/ref_counted.h" #include "base/message_loop/message_loop.h" #include "base/run_loop.h" @@ -198,7 +197,7 @@ int result = 0; CancelableCallback<void(std::unique_ptr<int>)> cb( base::Bind(&OnMoveOnlyReceived, base::Unretained(&result))); - cb.callback().Run(base::WrapUnique(new int(kExpectedResult))); + cb.callback().Run(std::make_unique<int>(kExpectedResult)); EXPECT_EQ(kExpectedResult, result); }
diff --git a/base/containers/mru_cache_unittest.cc b/base/containers/mru_cache_unittest.cc index 07b0144..d4ee482 100644 --- a/base/containers/mru_cache_unittest.cc +++ b/base/containers/mru_cache_unittest.cc
@@ -7,7 +7,6 @@ #include <cstddef> #include <memory> -#include "base/memory/ptr_util.h" #include "base/trace_event/memory_usage_estimator.h" #include "testing/gtest/include/gtest/gtest.h" @@ -200,8 +199,8 @@ // First insert and item and then overwrite it. static const int kItem1Key = 1; - cache.Put(kItem1Key, WrapUnique(new CachedItem(20))); - cache.Put(kItem1Key, WrapUnique(new CachedItem(22))); + cache.Put(kItem1Key, std::make_unique<CachedItem>(20)); + cache.Put(kItem1Key, std::make_unique<CachedItem>(22)); // There should still be one item, and one extra live item. auto iter = cache.Get(kItem1Key); @@ -217,8 +216,8 @@ // go away. { Cache cache2(Cache::NO_AUTO_EVICT); - cache2.Put(1, WrapUnique(new CachedItem(20))); - cache2.Put(2, WrapUnique(new CachedItem(20))); + cache2.Put(1, std::make_unique<CachedItem>(20)); + cache2.Put(2, std::make_unique<CachedItem>(20)); } // There should be no objects leaked. @@ -227,8 +226,8 @@ // Check that Clear() also frees things correctly. { Cache cache2(Cache::NO_AUTO_EVICT); - cache2.Put(1, WrapUnique(new CachedItem(20))); - cache2.Put(2, WrapUnique(new CachedItem(20))); + cache2.Put(1, std::make_unique<CachedItem>(20)); + cache2.Put(2, std::make_unique<CachedItem>(20)); EXPECT_EQ(initial_count + 2, cached_item_live_count); cache2.Clear(); EXPECT_EQ(initial_count, cached_item_live_count);
diff --git a/base/debug/activity_analyzer.cc b/base/debug/activity_analyzer.cc index e82ef3d..31bb8fc 100644 --- a/base/debug/activity_analyzer.cc +++ b/base/debug/activity_analyzer.cc
@@ -12,7 +12,6 @@ #include "base/files/memory_mapped_file.h" #include "base/lazy_instance.h" #include "base/logging.h" -#include "base/memory/ptr_util.h" #include "base/metrics/histogram_macros.h" #include "base/stl_util.h" #include "base/strings/string_util.h" @@ -108,7 +107,7 @@ return nullptr; } - return WrapUnique(new GlobalActivityAnalyzer(std::move(allocator))); + return std::make_unique<GlobalActivityAnalyzer>(std::move(allocator)); } #if !defined(OS_NACL)
diff --git a/base/feature_list_unittest.cc b/base/feature_list_unittest.cc index 164997a..3a870ac 100644 --- a/base/feature_list_unittest.cc +++ b/base/feature_list_unittest.cc
@@ -11,7 +11,6 @@ #include "base/format_macros.h" #include "base/macros.h" -#include "base/memory/ptr_util.h" #include "base/metrics/field_trial.h" #include "base/metrics/persistent_memory_allocator.h" #include "base/strings/string_piece.h" @@ -45,7 +44,7 @@ class FeatureListTest : public testing::Test { public: FeatureListTest() : feature_list_(nullptr) { - RegisterFeatureListInstance(WrapUnique(new FeatureList)); + RegisterFeatureListInstance(std::make_unique<FeatureList>()); } ~FeatureListTest() override { ClearFeatureListInstance(); }
diff --git a/base/metrics/persistent_sample_map.cc b/base/metrics/persistent_sample_map.cc index f38b9d1..e07b7167 100644 --- a/base/metrics/persistent_sample_map.cc +++ b/base/metrics/persistent_sample_map.cc
@@ -5,7 +5,6 @@ #include "base/metrics/persistent_sample_map.h" #include "base/logging.h" -#include "base/memory/ptr_util.h" #include "base/metrics/histogram_macros.h" #include "base/metrics/persistent_histogram_allocator.h" #include "base/numerics/safe_conversions.h" @@ -154,7 +153,7 @@ // Have to override "const" in order to make sure all samples have been // loaded before trying to iterate over the map. const_cast<PersistentSampleMap*>(this)->ImportSamples(-1, true); - return WrapUnique(new PersistentSampleMapIterator(sample_counts_)); + return std::make_unique<PersistentSampleMapIterator>(sample_counts_); } // static
diff --git a/base/metrics/sample_map.cc b/base/metrics/sample_map.cc index b441afa..f9252386 100644 --- a/base/metrics/sample_map.cc +++ b/base/metrics/sample_map.cc
@@ -5,7 +5,6 @@ #include "base/metrics/sample_map.h" #include "base/logging.h" -#include "base/memory/ptr_util.h" #include "base/numerics/safe_conversions.h" #include "base/stl_util.h" @@ -106,7 +105,7 @@ } std::unique_ptr<SampleCountIterator> SampleMap::Iterator() const { - return WrapUnique(new SampleMapIterator(sample_counts_)); + return std::make_unique<SampleMapIterator>(sample_counts_); } bool SampleMap::AddSubtractImpl(SampleCountIterator* iter, Operator op) {
diff --git a/base/metrics/single_sample_metrics_unittest.cc b/base/metrics/single_sample_metrics_unittest.cc index d4d5913..974ba7e 100644 --- a/base/metrics/single_sample_metrics_unittest.cc +++ b/base/metrics/single_sample_metrics_unittest.cc
@@ -4,7 +4,6 @@ #include "base/metrics/single_sample_metrics.h" -#include "base/memory/ptr_util.h" #include "base/metrics/dummy_histogram.h" #include "base/test/gtest_util.h" #include "base/test/metrics/histogram_tester.h" @@ -42,14 +41,14 @@ EXPECT_EQ(factory, SingleSampleMetricsFactory::Get()); // Setting a factory after the default has been instantiated should fail. - EXPECT_DCHECK_DEATH(SingleSampleMetricsFactory::SetFactory( - WrapUnique<SingleSampleMetricsFactory>(nullptr))); + EXPECT_DCHECK_DEATH(SingleSampleMetricsFactory::SetFactory(nullptr)); } TEST_F(SingleSampleMetricsTest, CustomFactoryGetSet) { - SingleSampleMetricsFactory* factory = new DefaultSingleSampleMetricsFactory(); - SingleSampleMetricsFactory::SetFactory(WrapUnique(factory)); - EXPECT_EQ(factory, SingleSampleMetricsFactory::Get()); + auto factory = std::make_unique<DefaultSingleSampleMetricsFactory>(); + SingleSampleMetricsFactory* factory_raw = factory.get(); + SingleSampleMetricsFactory::SetFactory(std::move(factory)); + EXPECT_EQ(factory_raw, SingleSampleMetricsFactory::Get()); } TEST_F(SingleSampleMetricsTest, DefaultSingleSampleMetricNoValue) {
diff --git a/base/profiler/win32_stack_frame_unwinder.cc b/base/profiler/win32_stack_frame_unwinder.cc index a337c16..b5db93b4 100644 --- a/base/profiler/win32_stack_frame_unwinder.cc +++ b/base/profiler/win32_stack_frame_unwinder.cc
@@ -9,7 +9,6 @@ #include <utility> #include "base/macros.h" -#include "base/memory/ptr_util.h" namespace base { @@ -112,7 +111,7 @@ Win32StackFrameUnwinder::UnwindFunctions::UnwindFunctions() {} Win32StackFrameUnwinder::Win32StackFrameUnwinder() - : Win32StackFrameUnwinder(WrapUnique(new Win32UnwindFunctions)) {} + : Win32StackFrameUnwinder(std::make_unique<Win32UnwindFunctions>()) {} Win32StackFrameUnwinder::~Win32StackFrameUnwinder() {}
diff --git a/base/task/task_scheduler/scheduler_worker_stack_unittest.cc b/base/task/task_scheduler/scheduler_worker_stack_unittest.cc index a49dc895..40c70f2 100644 --- a/base/task/task_scheduler/scheduler_worker_stack_unittest.cc +++ b/base/task/task_scheduler/scheduler_worker_stack_unittest.cc
@@ -5,7 +5,6 @@ #include "base/task/task_scheduler/scheduler_worker_stack.h" #include "base/logging.h" -#include "base/memory/ptr_util.h" #include "base/memory/ref_counted.h" #include "base/task/task_scheduler/scheduler_worker.h" #include "base/task/task_scheduler/sequence.h" @@ -45,15 +44,15 @@ protected: void SetUp() override { worker_a_ = MakeRefCounted<SchedulerWorker>( - ThreadPriority::NORMAL, WrapUnique(new MockSchedulerWorkerDelegate), + ThreadPriority::NORMAL, std::make_unique<MockSchedulerWorkerDelegate>(), task_tracker_.GetTrackedRef()); ASSERT_TRUE(worker_a_); worker_b_ = MakeRefCounted<SchedulerWorker>( - ThreadPriority::NORMAL, WrapUnique(new MockSchedulerWorkerDelegate), + ThreadPriority::NORMAL, std::make_unique<MockSchedulerWorkerDelegate>(), task_tracker_.GetTrackedRef()); ASSERT_TRUE(worker_b_); worker_c_ = MakeRefCounted<SchedulerWorker>( - ThreadPriority::NORMAL, WrapUnique(new MockSchedulerWorkerDelegate), + ThreadPriority::NORMAL, std::make_unique<MockSchedulerWorkerDelegate>(), task_tracker_.GetTrackedRef()); ASSERT_TRUE(worker_c_); }
diff --git a/base/task/task_scheduler/task_scheduler_impl_unittest.cc b/base/task/task_scheduler/task_scheduler_impl_unittest.cc index 093f5ed..0b53e80 100644 --- a/base/task/task_scheduler/task_scheduler_impl_unittest.cc +++ b/base/task/task_scheduler/task_scheduler_impl_unittest.cc
@@ -16,7 +16,6 @@ #include "base/cfi_buildflags.h" #include "base/debug/stack_trace.h" #include "base/macros.h" -#include "base/memory/ptr_util.h" #include "base/metrics/field_trial.h" #include "base/metrics/field_trial_params.h" #include "base/synchronization/waitable_event.h" @@ -451,9 +450,9 @@ StartTaskScheduler(); std::vector<std::unique_ptr<ThreadPostingTasks>> threads_posting_tasks; for (const auto& traits_execution_mode_pair : GetTraitsExecutionModePairs()) { - threads_posting_tasks.push_back(WrapUnique( - new ThreadPostingTasks(&scheduler_, traits_execution_mode_pair.traits, - traits_execution_mode_pair.execution_mode))); + threads_posting_tasks.push_back(std::make_unique<ThreadPostingTasks>( + &scheduler_, traits_execution_mode_pair.traits, + traits_execution_mode_pair.execution_mode)); threads_posting_tasks.back()->Start(); }
diff --git a/base/test/trace_event_analyzer_unittest.cc b/base/test/trace_event_analyzer_unittest.cc index 6461b0fe..a23260d 100644 --- a/base/test/trace_event_analyzer_unittest.cc +++ b/base/test/trace_event_analyzer_unittest.cc
@@ -8,7 +8,6 @@ #include <stdint.h> #include "base/bind.h" -#include "base/memory/ptr_util.h" #include "base/memory/ref_counted_memory.h" #include "base/synchronization/waitable_event.h" #include "base/threading/platform_thread.h" @@ -103,7 +102,7 @@ event.arg_numbers["int"] = static_cast<double>(int_num); event.arg_numbers["double"] = double_num; event.arg_strings["string"] = str; - event.arg_values["dict"] = WrapUnique(new base::DictionaryValue()); + event.arg_values["dict"] = std::make_unique<base::DictionaryValue>(); ASSERT_TRUE(event.HasNumberArg("false")); ASSERT_TRUE(event.HasNumberArg("true"));
diff --git a/base/trace_event/memory_dump_manager_unittest.cc b/base/trace_event/memory_dump_manager_unittest.cc index f30a0e8..abfb5166 100644 --- a/base/trace_event/memory_dump_manager_unittest.cc +++ b/base/trace_event/memory_dump_manager_unittest.cc
@@ -16,7 +16,6 @@ #include "base/command_line.h" #include "base/debug/thread_heap_usage_tracker.h" #include "base/macros.h" -#include "base/memory/ptr_util.h" #include "base/run_loop.h" #include "base/single_thread_task_runner.h" #include "base/synchronization/waitable_event.h" @@ -425,11 +424,11 @@ // we will pop out one thread/MemoryDumpProvider, each MDP is supposed to be // invoked a number of times equal to its index. for (uint32_t i = kNumInitialThreads; i > 0; --i) { - threads.push_back(WrapUnique(new Thread("test thread"))); + threads.push_back(std::make_unique<Thread>("test thread")); auto* thread = threads.back().get(); thread->Start(); scoped_refptr<SingleThreadTaskRunner> task_runner = thread->task_runner(); - mdps.push_back(WrapUnique(new MockMemoryDumpProvider())); + mdps.push_back(std::make_unique<MockMemoryDumpProvider>()); auto* mdp = mdps.back().get(); RegisterDumpProvider(mdp, task_runner, kDefaultOptions); EXPECT_CALL(*mdp, OnMemoryDump(_, _)) @@ -602,9 +601,8 @@ std::vector<std::unique_ptr<MockMemoryDumpProvider>> mdps; for (int i = 0; i < 2; i++) { - threads.push_back( - WrapUnique(new TestIOThread(TestIOThread::kAutoStart))); - mdps.push_back(WrapUnique(new MockMemoryDumpProvider())); + threads.push_back(std::make_unique<TestIOThread>(TestIOThread::kAutoStart)); + mdps.push_back(std::make_unique<MockMemoryDumpProvider>()); RegisterDumpProvider(mdps.back().get(), threads.back()->task_runner(), kDefaultOptions); } @@ -651,9 +649,8 @@ std::vector<std::unique_ptr<MockMemoryDumpProvider>> mdps; for (int i = 0; i < 2; i++) { - threads.push_back( - WrapUnique(new TestIOThread(TestIOThread::kAutoStart))); - mdps.push_back(WrapUnique(new MockMemoryDumpProvider())); + threads.push_back(std::make_unique<TestIOThread>(TestIOThread::kAutoStart)); + mdps.push_back(std::make_unique<MockMemoryDumpProvider>()); RegisterDumpProvider(mdps.back().get(), threads.back()->task_runner(), kDefaultOptions); }
diff --git a/base/trace_event/trace_event_argument_unittest.cc b/base/trace_event/trace_event_argument_unittest.cc index 448b2d56..69d203a 100644 --- a/base/trace_event/trace_event_argument_unittest.cc +++ b/base/trace_event/trace_event_argument_unittest.cc
@@ -8,7 +8,6 @@ #include <utility> -#include "base/memory/ptr_util.h" #include "base/values.h" #include "testing/gtest/include/gtest/gtest.h" @@ -101,14 +100,14 @@ Value bool_value(true); Value double_value(42.0f); - auto dict_value = WrapUnique(new DictionaryValue); + auto dict_value = std::make_unique<DictionaryValue>(); dict_value->SetBoolean("bool", true); dict_value->SetInteger("int", 42); dict_value->SetDouble("double", 42.0f); dict_value->SetString("string", std::string("a") + "b"); dict_value->SetString("string", std::string("a") + "b"); - auto list_value = WrapUnique(new ListValue); + auto list_value = std::make_unique<ListValue>(); list_value->AppendBoolean(false); list_value->AppendInteger(1); list_value->AppendString("in_list");
diff --git a/base/values_unittest.cc b/base/values_unittest.cc index c9185fd..b9239744 100644 --- a/base/values_unittest.cc +++ b/base/values_unittest.cc
@@ -15,7 +15,6 @@ #include <vector> #include "base/containers/adapters.h" -#include "base/memory/ptr_util.h" #include "base/strings/string16.h" #include "base/strings/string_piece.h" #include "base/strings/utf_string_conversions.h" @@ -1208,7 +1207,7 @@ std::unique_ptr<ListValue> list(new ListValue); list->Append(std::make_unique<Value>()); - list->Append(WrapUnique(new DictionaryValue)); + list->Append(std::make_unique<DictionaryValue>()); auto list_copy = std::make_unique<Value>(list->Clone()); ListValue* list_weak = dv.SetList("f", std::move(list));
diff --git a/build/android/gyp/proguard.py b/build/android/gyp/proguard.py index 9462bfb..c90e5639 100755 --- a/build/android/gyp/proguard.py +++ b/build/android/gyp/proguard.py
@@ -6,6 +6,7 @@ import optparse import os +import shutil import sys import tempfile @@ -56,15 +57,23 @@ 'included by --proguard-configs, but that should ' 'not actually be included.') parser.add_option('--mapping', help='Path to proguard mapping to apply.') + parser.add_option('--mapping-output', + help='Path for proguard to output mapping file to.') parser.add_option('--classpath', action='append', help='Classpath for proguard.') parser.add_option('--enable-dangerous-optimizations', action='store_true', help='Enable optimizations which are known to have issues.') + parser.add_option('--main-dex-rules-path', action='append', + help='Paths to main dex rules for multidex' + '- only works with R8.') parser.add_option('--verbose', '-v', action='store_true', help='Print all proguard output') options, _ = parser.parse_args(args) + assert not options.main_dex_rules_path or options.r8_path, \ + "R8 must be enabled to pass main dex rules." + classpath = [] for arg in options.classpath: classpath += build_utils.ParseGnList(arg) @@ -79,16 +88,38 @@ options.input_paths = build_utils.ParseGnList(options.input_paths) + if not options.mapping_output: + options.mapping_output = options.output_path + ".mapping" + return options -def _CreateR8Command(options, map_output_path): +def _MoveTempDexFile(tmp_dex_dir, dex_path): + """Move the temp dex file out of |tmp_dex_dir|. + + Args: + tmp_dex_dir: Path to temporary directory created with tempfile.mkdtemp(). + The directory should have just a single file. + dex_path: Target path to move dex file to. + + Raises: + Exception if there are multiple files in |tmp_dex_dir|. + """ + tempfiles = os.listdir(tmp_dex_dir) + if len(tempfiles) > 1: + raise Exception('%d files created, expected 1' % len(tempfiles)) + + tmp_dex_path = os.path.join(tmp_dex_dir, tempfiles[0]) + shutil.move(tmp_dex_path, dex_path) + + +def _CreateR8Command(options, map_output_path, output_dir): # TODO: R8 needs -applymapping equivalent. cmd = [ 'java', '-jar', options.r8_path, '--no-desugaring', - '--classfile', - '--output', options.output_path, + '--no-data-resources', + '--output', output_dir, '--pg-map-output', map_output_path, ] @@ -101,6 +132,10 @@ for config_file in options.proguard_configs: cmd += ['--pg-conf', config_file] + if options.main_dex_rules_path: + for main_dex_rule in options.main_dex_rules_path: + cmd += ['--main-dex-rules', main_dex_rule] + cmd += options.input_paths return cmd @@ -114,6 +149,7 @@ proguard.configs(options.proguard_configs) proguard.config_exclusions(options.proguard_config_exclusions) proguard.outjar(options.output_path) + proguard.mapping_output(options.mapping_output) # If a jar is part of input no need to include it as library jar. classpath = [ @@ -127,12 +163,17 @@ # TODO(agrieve): Remove proguard usages. if options.r8_path: with tempfile.NamedTemporaryFile() as mapping_temp: - # R8 will output mapping file to this temp file - cmd = _CreateR8Command(options, mapping_temp.name) - build_utils.CheckOutput(cmd) + if options.output_path.endswith('.dex'): + with build_utils.TempDir() as tmp_dex_dir: + cmd = _CreateR8Command(options, mapping_temp.name, tmp_dex_dir) + build_utils.CheckOutput(cmd) + _MoveTempDexFile(tmp_dex_dir, options.output_path) + else: + cmd = _CreateR8Command(options, mapping_temp.name, options.output_path) + build_utils.CheckOutput(cmd) # Copy the mapping file back to where it should be. - map_path = options.output_path + ".mapping" + map_path = options.mapping_output with build_utils.AtomicOutput(map_path) as mapping: # Mapping files generated by R8 include comments that may break # some of our tooling so remove those.
diff --git a/build/android/gyp/util/proguard_util.py b/build/android/gyp/util/proguard_util.py index 8a6e785..bce124e 100644 --- a/build/android/gyp/util/proguard_util.py +++ b/build/android/gyp/util/proguard_util.py
@@ -51,6 +51,7 @@ self._configs = None self._config_exclusions = None self._outjar = None + self._mapping_output = None self._verbose = False self._disabled_optimizations = [] @@ -58,6 +59,10 @@ assert self._outjar is None self._outjar = path + def mapping_output(self, path): + assert self._mapping_output is None + self._mapping_output = path + def mapping(self, path): assert self._mapping is None assert os.path.exists(path), path @@ -124,7 +129,7 @@ '-outjars', self._outjar, '-printseeds', self._outjar + '.seeds', '-printusage', self._outjar + '.usage', - '-printmapping', self._outjar + '.mapping', + '-printmapping', self._mapping_output, ] if self._verbose: @@ -156,7 +161,7 @@ return [ self._outjar, self._outjar + '.flags', - self._outjar + '.mapping', + self._mapping_output, self._outjar + '.seeds', self._outjar + '.usage', ]
diff --git a/build/android/gyp/write_build_config.py b/build/android/gyp/write_build_config.py index a2387da7..f4d25bf 100755 --- a/build/android/gyp/write_build_config.py +++ b/build/android/gyp/write_build_config.py
@@ -860,7 +860,7 @@ help='Whether proguard is enabled for this apk or bundle module.') parser.add_option('--proguard-configs', help='GN-list of proguard flag files to use in final apk.') - parser.add_option('--proguard-output-jar-path', + parser.add_option('--proguard-mapping-path', help='Path to jar created by ProGuard step') parser.add_option('--fail', help='GN-list of error message lines to fail with.') @@ -1257,8 +1257,8 @@ deps_proguard_disabled)) else: deps_info['proguard_enabled'] = bool(options.proguard_enabled) - if options.proguard_output_jar_path: - deps_info['proguard_output_jar_path'] = options.proguard_output_jar_path + if options.proguard_mapping_path: + deps_info['proguard_mapping_path'] = options.proguard_mapping_path # The java code for an instrumentation test apk is assembled differently for # ProGuard vs. non-ProGuard. @@ -1287,7 +1287,7 @@ if p not in extra_jars) tested_apk_config = GetDepConfig(options.tested_apk_config) deps_info['proguard_under_test_mapping'] = ( - tested_apk_config['proguard_output_jar_path'] + '.mapping') + tested_apk_config['proguard_mapping_path']) elif options.proguard_enabled: # Not sure why you'd want to proguard the test apk when the under-test apk # is not proguarded, but it's easy enough to support.
diff --git a/build/android/stacktrace/java/org/chromium/build/FlushingReTrace.java b/build/android/stacktrace/java/org/chromium/build/FlushingReTrace.java index e54054cb..134a152 100644 --- a/build/android/stacktrace/java/org/chromium/build/FlushingReTrace.java +++ b/build/android/stacktrace/java/org/chromium/build/FlushingReTrace.java
@@ -34,13 +34,17 @@ // Eagerly match logcat prefix to avoid conflicting with the patterns below. LOGCAT_PREFIX + "(?:" - // Based on default ReTrace regex, but with "at" changed to to allow : - // E.g.: 06-22 13:58:02.895 4674 4674 E THREAD_STATE: bLA.a(PG:173) + // Based on default ReTrace regex, but with whitespaces allowed in file:line parentheses + // and "at" changed to to allow : + // E.g.: 06-22 13:58:02.895 4674 4674 E THREAD_STATE: bLA.a( PG : 173 ) // Normal stack trace lines look like: // \tat org.chromium.chrome.browser.tab.Tab.handleJavaCrash(Tab.java:682) - + "(?:.*?(?::|\\bat)\\s+%c\\.%m\\s*\\(%s(?::%l)?\\))|" + + "(?:.*?(?::|\\bat)\\s+%c\\.%m\\s*\\(\\s*%s(?:\\s*:\\s*%l\\s*)?\\))|" // E.g.: VFY: unable to resolve new-instance 3810 (LSome/Framework/Class;) in Lfoo/Bar; + "(?:.*L%C;.*)|" + // E.g.: Caused by: java.lang.NullPointerException: Attempt to read from field 'int bLA' + // on a null object reference + + "(?:.*NullPointerException.*[\"']%t\\s*%c\\.(?:%f|%m\\(%a\\))[\"'].*)|" // E.g.: END SomeTestClass#someMethod + "(?:.*?%c#%m.*?)|" // E.g.: The member "Foo.bar"
diff --git a/build/android/stacktrace/java_deobfuscate_test.py b/build/android/stacktrace/java_deobfuscate_test.py index 6ee40ce..fc11d97 100755 --- a/build/android/stacktrace/java_deobfuscate_test.py +++ b/build/android/stacktrace/java_deobfuscate_test.py
@@ -27,40 +27,56 @@ TEST_MAP = """\ this.was.Deobfuscated -> FOO: int[] FontFamily -> a - 1:3:void someMethod(int,android.os.Bundle):65:65 -> bar + 1:3:void someMethod(int,android.os.Bundle):65:67 -> bar """ -TEST_DATA = """\ -Here is a FOO -Here is a FOO baz -Here is a "FOO" baz -Here is a "FOO.bar" baz -Here it is: FOO -Here it is: FOO.bar -SomeError: SomeFrameworkClass in isTestClass for FOO -Here is a FOO.bar -Here is a FOO.bar baz -END FOO#bar -new-instance 3810 (LSome/Framework/Class;) in LFOO; -FOO: Error message -\tat FOO.bar(PG:1) -""".splitlines(True) +TEST_DATA = [ + "Here is a FOO", + "Here is a FOO baz", + "Here is a \"FOO\" baz", + "Here is a \"FOO.bar\" baz", + "Here it is: FOO", + "Here it is: FOO.bar", + "SomeError: SomeFrameworkClass in isTestClass for FOO", + "Here is a FOO.bar", + "Here is a FOO.bar baz", + "END FOO#bar", + "new-instance 3810 (LSome/Framework/Class;) in LFOO;", + "FOO: Error message", + "\tat FOO.bar(PG:1)", + "\t at\t FOO.bar\t (\t PG:\t 1\t )", + ("Unable to start activity ComponentInfo{garbage.in/here.test}:" + " java.lang.NullPointerException: Attempt to invoke interface method 'void" + " FOO.bar(int,android.os.Bundle)' on a null object reference"), + ("Caused by: java.lang.NullPointerException: Attempt to read from field" + " 'int[] FOO.a' on a null object reference"), +] -EXPECTED_OUTPUT = """\ -Here is a this.was.Deobfuscated -Here is a FOO baz -Here is a "this.was.Deobfuscated" baz -Here is a "this.was.Deobfuscated.someMethod" baz -Here it is: this.was.Deobfuscated -Here it is: this.was.Deobfuscated.someMethod -SomeError: SomeFrameworkClass in isTestClass for this.was.Deobfuscated -Here is a this.was.Deobfuscated.someMethod -Here is a FOO.bar baz -END this.was.Deobfuscated#someMethod -new-instance 3810 (LSome/Framework/Class;) in Lthis/was/Deobfuscated; -this.was.Deobfuscated: Error message -\tat this.was.Deobfuscated.someMethod(Deobfuscated.java:65) -""".splitlines(True) +EXPECTED_OUTPUT = [ + "Here is a this.was.Deobfuscated", + "Here is a FOO baz", + "Here is a \"this.was.Deobfuscated\" baz", + "Here is a \"this.was.Deobfuscated.someMethod\" baz", + "Here it is: this.was.Deobfuscated", + "Here it is: this.was.Deobfuscated.someMethod", + "SomeError: SomeFrameworkClass in isTestClass for this.was.Deobfuscated", + "Here is a this.was.Deobfuscated.someMethod", + "Here is a FOO.bar baz", + "END this.was.Deobfuscated#someMethod", + "new-instance 3810 (LSome/Framework/Class;) in Lthis/was/Deobfuscated;", + "this.was.Deobfuscated: Error message", + "\tat this.was.Deobfuscated.someMethod(Deobfuscated.java:65)", + ("\t at\t this.was.Deobfuscated.someMethod\t " + "(\t Deobfuscated.java:\t 65\t )"), + ("Unable to start activity ComponentInfo{garbage.in/here.test}:" + " java.lang.NullPointerException: Attempt to invoke interface method" + " 'void this.was.Deobfuscated.someMethod(int,android.os.Bundle)' on a null" + " object reference"), + ("Caused by: java.lang.NullPointerException: Attempt to read from field" + " 'int[] this.was.Deobfuscated.FontFamily' on a null object reference"), +] +TEST_DATA = [s + "\n" for s in TEST_DATA] +EXPECTED_OUTPUT = [s + "\n" for s in EXPECTED_OUTPUT] class JavaDeobfuscateTest(unittest.TestCase):
diff --git a/build/config/android/internal_rules.gni b/build/config/android/internal_rules.gni index d393bc6..6995161 100644 --- a/build/config/android/internal_rules.gni +++ b/build/config/android/internal_rules.gni
@@ -419,11 +419,10 @@ if (defined(invoker.proguard_enabled) && invoker.proguard_enabled) { args += [ "--proguard-enabled" ] } - if (defined(invoker.proguard_output_jar_path)) { - _rebased_proguard_output_jar_path = - rebase_path(invoker.proguard_output_jar_path, root_build_dir) - args += - [ "--proguard-output-jar-path=$_rebased_proguard_output_jar_path" ] + if (defined(invoker.proguard_mapping_path)) { + _rebased_proguard_mapping_path = + rebase_path(invoker.proguard_mapping_path, root_build_dir) + args += [ "--proguard-mapping-path=$_rebased_proguard_mapping_path" ] } if (defined(invoker.proguard_configs)) { _rebased_proguard_configs = @@ -944,7 +943,7 @@ # http://crbug.com/725224. Fix for bots running out of memory. pool = "//build/toolchain:link_pool($default_toolchain)" - _output_jar_path = invoker.output_jar_path + _output_path = invoker.output_path _proguard_jar_path = _default_proguard_jar_path if (defined(invoker.proguard_jar_path)) { _proguard_jar_path = invoker.proguard_jar_path @@ -957,10 +956,14 @@ if (defined(invoker.inputs)) { inputs += invoker.inputs } + _mapping_path = "$_output_path.mapping" + if (defined(invoker.proguard_mapping_path)) { + _mapping_path = invoker.proguard_mapping_path + } depfile = "${target_gen_dir}/${target_name}.d" outputs = [ - _output_jar_path, - "$_output_jar_path.mapping", + _output_path, + _mapping_path, ] _rebased_build_config = rebase_path(invoker.build_config, root_build_dir) args = [ @@ -969,7 +972,9 @@ "--proguard-path", rebase_path(_proguard_jar_path, root_build_dir), "--output-path", - rebase_path(_output_jar_path, root_build_dir), + rebase_path(_output_path, root_build_dir), + "--mapping-output", + rebase_path(_mapping_path, root_build_dir), "--classpath", "@FileArg($_rebased_build_config:deps_info:proguard_classpath_jars)", "--classpath", @@ -1058,72 +1063,198 @@ } template("dex") { - _enable_multidex = - defined(invoker.enable_multidex) && invoker.enable_multidex + assert(defined(invoker.output)) - if (_enable_multidex) { - _main_dex_list_path = invoker.output + ".main_dex_list" - _main_dex_list_target_name = "${target_name}__main_dex_list" - action_with_pydeps(_main_dex_list_target_name) { + _proguard_enabled = + defined(invoker.proguard_enabled) && invoker.proguard_enabled + _proguarding_with_r8 = _proguard_enabled && experimental_r8_path != "" + + assert(!(defined(invoker.input_jars) && _proguard_enabled), + "input_jars can't be specified when proguarding a dex.") + + if (!_proguarding_with_r8) { + _dexing_jars = [] + if (defined(invoker.input_jars)) { + _dexing_jars += invoker.input_jars + } + } + + if (_proguard_enabled) { + if (defined(invoker.enable_multidex)) { + assert(invoker.enable_multidex || !invoker.enable_multidex) + if (defined(invoker.extra_main_dex_proguard_config)) { + assert(invoker.extra_main_dex_proguard_config != []) + } + if (defined(invoker.negative_main_dex_globs)) { + assert(invoker.negative_main_dex_globs != []) + } + } + if (_proguarding_with_r8) { + _proguard_output_path = invoker.output + _proguard_target_name = target_name + } else { + _proguard_output_path = invoker.output + ".proguard.jar" + _proguard_target_name = "${target_name}__proguard" + _dexing_jars += [ _proguard_output_path ] + } + + proguard(_proguard_target_name) { + forward_variables_from(invoker, + [ + "proguard_jar_path", + "deps", + "build_config", + "proguard_mapping_path", + "testonly", + ]) + inputs = [] + if (defined(invoker.inputs)) { + inputs += invoker.inputs + } + if (defined(invoker.proguard_configs)) { + inputs += invoker.proguard_configs + } + + _rebased_build_config = rebase_path(build_config, root_build_dir) + args = [ + "--proguard-configs=@FileArg($_rebased_build_config:deps_info:proguard_all_configs)", + "--input-paths=@FileArg($_rebased_build_config:deps_info:java_runtime_classpath)", + ] + if (defined(invoker.proguard_config_exclusions)) { + _rebased_proguard_config_exclusions = + rebase_path(invoker.proguard_config_exclusions, root_build_dir) + args += [ + "--proguard-config-exclusions=$_rebased_proguard_config_exclusions", + ] + } + if (defined(invoker.proguard_args)) { + args += invoker.proguard_args + } + + output_path = _proguard_output_path + } + } + + if (!_proguarding_with_r8) { + _enable_multidex = + defined(invoker.enable_multidex) && invoker.enable_multidex + if (_enable_multidex) { + _main_dex_list_path = invoker.output + ".main_dex_list" + _main_dex_list_target_name = "${target_name}__main_dex_list" + action_with_pydeps(_main_dex_list_target_name) { + forward_variables_from(invoker, + [ + "deps", + "testonly", + ]) + + script = "//build/android/gyp/main_dex_list.py" + depfile = "$target_gen_dir/$target_name.d" + + # http://crbug.com/725224. Fix for bots running out of memory. + pool = "//build/toolchain:link_pool($default_toolchain)" + + main_dex_rules = "//build/android/main_dex_classes.flags" + + if (defined(invoker.proguard_jar_path)) { + _proguard_jar_path = invoker.proguard_jar_path + } else { + _proguard_jar_path = _default_proguard_jar_path + } + + _shrinked_android = "$android_sdk_build_tools/lib/shrinkedAndroid.jar" + _dx = "$android_sdk_build_tools/lib/dx.jar" + inputs = [ + main_dex_rules, + _dx, + _proguard_jar_path, + _shrinked_android, + ] + + outputs = [ + _main_dex_list_path, + ] + + args = [ + "--depfile", + rebase_path(depfile, root_build_dir), + "--dx-path", + rebase_path(_dx, root_build_dir), + "--shrinked-android-path", + rebase_path(_shrinked_android, root_build_dir), + "--main-dex-list-path", + rebase_path(_main_dex_list_path, root_build_dir), + "--main-dex-rules-path", + rebase_path(main_dex_rules, root_build_dir), + "--proguard-path", + rebase_path(_proguard_jar_path, root_build_dir), + ] + + if (defined(invoker.extra_main_dex_proguard_config)) { + inputs += [ invoker.extra_main_dex_proguard_config ] + args += [ + "--main-dex-rules-path", + rebase_path(invoker.extra_main_dex_proguard_config, + root_build_dir), + ] + } + + if (_proguard_enabled) { + deps += [ ":${_proguard_target_name}" ] + } + + if (defined(invoker.negative_main_dex_globs)) { + args += [ + "--negative-main-dex-globs=${invoker.negative_main_dex_globs}", + ] + } + + if (defined(invoker.input_jars_file_arg)) { + inputs += [ invoker.build_config ] + args += [ "--inputs=${invoker.input_jars_file_arg}" ] + } + + inputs += _dexing_jars + if (_dexing_jars != []) { + args += rebase_path(_dexing_jars, root_build_dir) + } + } + } + + action_with_pydeps(target_name) { forward_variables_from(invoker, [ "deps", "testonly", ]) - - script = "//build/android/gyp/main_dex_list.py" + script = "//build/android/gyp/dex.py" depfile = "$target_gen_dir/$target_name.d" - - # http://crbug.com/725224. Fix for bots running out of memory. - pool = "//build/toolchain:link_pool($default_toolchain)" - - main_dex_rules = "//build/android/main_dex_classes.flags" - - if (defined(invoker.proguard_jar_path)) { - _proguard_jar_path = invoker.proguard_jar_path - } else { - _proguard_jar_path = _default_proguard_jar_path - } - - _shrinked_android = "$android_sdk_build_tools/lib/shrinkedAndroid.jar" - _dx = "$android_sdk_build_tools/lib/dx.jar" - inputs = [ - main_dex_rules, - _dx, - _proguard_jar_path, - _shrinked_android, - ] - + inputs = [] outputs = [ - _main_dex_list_path, + invoker.output, ] + _rebased_output = rebase_path(invoker.output, root_build_dir) + args = [ "--depfile", rebase_path(depfile, root_build_dir), - "--dx-path", - rebase_path(_dx, root_build_dir), - "--shrinked-android-path", - rebase_path(_shrinked_android, root_build_dir), - "--main-dex-list-path", - rebase_path(_main_dex_list_path, root_build_dir), - "--main-dex-rules-path", - rebase_path(main_dex_rules, root_build_dir), - "--proguard-path", - rebase_path(_proguard_jar_path, root_build_dir), + "--dex-path", + _rebased_output, ] - if (defined(invoker.extra_main_dex_proguard_config)) { - inputs += [ invoker.extra_main_dex_proguard_config ] - args += [ - "--main-dex-rules-path", - rebase_path(invoker.extra_main_dex_proguard_config, root_build_dir), - ] + if (_proguard_enabled) { + deps += [ ":${_proguard_target_name}" ] } - if (defined(invoker.negative_main_dex_globs)) { - args += - [ "--negative-main-dex-globs=${invoker.negative_main_dex_globs}" ] + if (_enable_multidex) { + args += [ + "--multi-dex", + "--main-dex-list-path", + rebase_path(_main_dex_list_path, root_build_dir), + ] + deps += [ ":${_main_dex_list_target_name}" ] + inputs += [ _main_dex_list_path ] } if (defined(invoker.input_jars_file_arg)) { @@ -1131,94 +1262,46 @@ args += [ "--inputs=${invoker.input_jars_file_arg}" ] } - if (defined(invoker.input_jars)) { - inputs += invoker.input_jars - args += rebase_path(invoker.input_jars, root_build_dir) + inputs += _dexing_jars + if (_dexing_jars != []) { + args += rebase_path(_dexing_jars, root_build_dir) } - } - } - assert(defined(invoker.output)) - action_with_pydeps(target_name) { - forward_variables_from(invoker, - [ - "deps", - "testonly", - ]) - script = "//build/android/gyp/dex.py" - depfile = "$target_gen_dir/$target_name.d" - inputs = [] - outputs = [ - invoker.output, - ] + if (defined(invoker.dexlayout_profile)) { + args += [ + "--dexlayout-profile", + rebase_path(invoker.dexlayout_profile, root_build_dir), + "--dexlayout-path", + rebase_path(_dexlayout_path, root_build_dir), + "--profman-path", + rebase_path(_profman_path, root_build_dir), + ] + inputs += [ + _dexlayout_path, + _profman_path, + invoker.dexlayout_profile, + ] + inputs += _default_art_libs + } - if (defined(invoker.use_pool) && invoker.use_pool) { - pool = "//build/toolchain:link_pool($default_toolchain)" - } + if (!is_java_debug) { + args += [ "--release" ] + } - _rebased_output = rebase_path(invoker.output, root_build_dir) + if (defined(invoker.min_sdk_version)) { + args += [ + "--min-api", + "${invoker.min_sdk_version}", + ] + } - args = [ - "--depfile", - rebase_path(depfile, root_build_dir), - "--dex-path", - _rebased_output, - ] - - if (defined(invoker.dexlayout_profile)) { + _d8_path = "//third_party/r8/lib/d8.jar" + inputs += [ _d8_path ] args += [ - "--dexlayout-profile", - rebase_path(invoker.dexlayout_profile, root_build_dir), - "--dexlayout-path", - rebase_path(_dexlayout_path, root_build_dir), - "--profman-path", - rebase_path(_profman_path, root_build_dir), - ] - inputs += [ - _dexlayout_path, - _profman_path, - invoker.dexlayout_profile, - ] - inputs += _default_art_libs - } - - if (_enable_multidex) { - args += [ - "--multi-dex", - "--main-dex-list-path", - rebase_path(_main_dex_list_path, root_build_dir), - ] - deps += [ ":${_main_dex_list_target_name}" ] - inputs += [ _main_dex_list_path ] - } - - if (defined(invoker.input_jars_file_arg)) { - inputs += [ invoker.build_config ] - args += [ "--inputs=${invoker.input_jars_file_arg}" ] - } - - if (defined(invoker.input_jars)) { - inputs += invoker.input_jars - args += rebase_path(invoker.input_jars, root_build_dir) - } - - if (!is_java_debug) { - args += [ "--release" ] - } - - if (defined(invoker.min_sdk_version)) { - args += [ - "--min-api", - "${invoker.min_sdk_version}", + "--d8-jar-path", + rebase_path(_d8_path, root_build_dir), ] } - - _d8_path = "//third_party/r8/lib/d8.jar" - inputs += [ _d8_path ] - args += [ - "--d8-jar-path", - rebase_path(_d8_path, root_build_dir), - ] } } @@ -2786,7 +2869,7 @@ # output APK. # incremental_install_json_path: If incremental_allowed, path to the output # incremental install json configuration file. - # proguard_output_jar_path: Path to .jar file produced from ProGuard step. + # proguard_mapping_path: Path to .mapping file produced from ProGuard step. # shared_libraries_runtime_deps_file: Optional. Path to a file listing the # native shared libraries required at runtime by the APK. # secondary_abi_shared_libraries_runtime_deps_file: @@ -2982,7 +3065,7 @@ "main_class", "proguard_configs", "proguard_enabled", - "proguard_output_jar_path", + "proguard_mapping_path", "secondary_abi_loadable_modules", "type", ])
diff --git a/build/config/android/rules.gni b/build/config/android/rules.gni index c7693e0..d7e92f0a 100644 --- a/build/config/android/rules.gni +++ b/build/config/android/rules.gni
@@ -1406,18 +1406,12 @@ # # Variables: # output: Path to the output jar. - # dex_path: Path to dex()'ed output (optional). # override_build_config: Use a pre-existing .build_config. Must be of type # "apk". # use_interface_jars: Use all dependent interface .jars rather than # implementation .jars. # use_unprocessed_jars: Use unprocessed / undesugared .jars. # direct_deps_only: Do not recurse on deps. - # proguard_enabled: Whether to run ProGuard on resulting jar. - # proguard_configs: List of proguard configs. - # proguard_jar_path: The path to proguard.jar you wish to use. If undefined, - # the proguard used will be the checked in one in //third_party/proguard. - # alternative_android_sdk_jar: System jar to use when proguard is enabled. # # Example # dist_jar("lib_fatjar") { @@ -1435,29 +1429,16 @@ !defined(invoker.supports_android) || invoker.supports_android _requires_android = defined(invoker.requires_android) && invoker.requires_android - _proguard_enabled = - defined(invoker.proguard_enabled) && invoker.proguard_enabled _use_interface_jars = defined(invoker.use_interface_jars) && invoker.use_interface_jars _use_unprocessed_jars = defined(invoker.use_unprocessed_jars) && invoker.use_unprocessed_jars _direct_deps_only = defined(invoker.direct_deps_only) && invoker.direct_deps_only - assert(!(_proguard_enabled && _use_interface_jars), - "Cannot set both proguard_enabled and use_interface_jars") - assert(!(_proguard_enabled && _direct_deps_only), - "Cannot set both proguard_enabled and direct_deps_only") assert(!(_use_unprocessed_jars && _use_interface_jars), "Cannot set both use_interface_jars and use_unprocessed_jars") _jar_target_name = target_name - if (defined(invoker.dex_path)) { - if (_proguard_enabled) { - _jar_target_name = "${target_name}__proguard" - } else { - _jar_target_name = "${target_name}__dist_jar" - } - } _deps = [] if (defined(invoker.deps)) { @@ -1481,11 +1462,6 @@ write_build_config(_build_config_target_name) { type = "dist_jar" - forward_variables_from(invoker, - [ - "proguard_enabled", - "proguard_configs", - ]) supports_android = _supports_android requires_android = _requires_android possible_config_deps = _deps @@ -1496,89 +1472,99 @@ } _rebased_build_config = rebase_path(_build_config, root_build_dir) - if (_proguard_enabled) { - proguard(_jar_target_name) { - forward_variables_from(invoker, - [ - "data", - "proguard_jar_path", - ]) - build_config = _build_config - deps = _deps + action_with_pydeps(_jar_target_name) { + forward_variables_from(invoker, [ "data" ]) + script = "//build/android/gyp/create_dist_jar.py" + depfile = "$target_gen_dir/$target_name.d" + deps = _deps - # Although these will be listed as deps in the depfile, they must also - # appear here so that "gn analyze" knows about them. - # https://crbug.com/827197 - inputs = [] - if (defined(invoker.proguard_configs)) { - inputs += invoker.proguard_configs - } + inputs = [ + _build_config, + ] - output_jar_path = invoker.output - args = [ - "--proguard-configs=@FileArg($_rebased_build_config:deps_info:proguard_all_configs)", - "--input-paths=@FileArg($_rebased_build_config:deps_info:java_runtime_classpath)", - ] - if (defined(invoker.proguard_config_exclusions)) { - _rebased_proguard_config_exclusions = - rebase_path(invoker.proguard_config_exclusions, root_build_dir) + outputs = [ + invoker.output, + ] + + args = [ + "--depfile", + rebase_path(depfile, root_build_dir), + "--output", + rebase_path(invoker.output, root_build_dir), + ] + + if (_direct_deps_only) { + if (_use_interface_jars) { args += [ - "--proguard-config-exclusions=$_rebased_proguard_config_exclusions", + "--jars=@FileArg($_rebased_build_config:javac:interface_classpath)", ] - } - } - } else { - action_with_pydeps(_jar_target_name) { - forward_variables_from(invoker, [ "data" ]) - script = "//build/android/gyp/create_dist_jar.py" - depfile = "$target_gen_dir/$target_name.d" - deps = _deps - - inputs = [ - _build_config, - ] - - outputs = [ - invoker.output, - ] - - args = [ - "--depfile", - rebase_path(depfile, root_build_dir), - "--output", - rebase_path(invoker.output, root_build_dir), - ] - - if (_direct_deps_only) { - if (_use_interface_jars) { - args += [ "--jars=@FileArg($_rebased_build_config:javac:interface_classpath)" ] - } else if (_use_unprocessed_jars) { - args += - [ "--jars=@FileArg($_rebased_build_config:javac:classpath)" ] - } else { - assert( - false, - "direct_deps_only does not work without use_interface_jars or use_unprocessed_jars") - } + } else if (_use_unprocessed_jars) { + args += [ "--jars=@FileArg($_rebased_build_config:javac:classpath)" ] } else { - if (_use_interface_jars) { - args += [ "--jars=@FileArg($_rebased_build_config:dist_jar:all_interface_jars)" ] - } else if (_use_unprocessed_jars) { - args += [ "--jars=@FileArg($_rebased_build_config:deps_info:javac_full_classpath)" ] - } else { - args += [ "--jars=@FileArg($_rebased_build_config:deps_info:java_runtime_classpath)" ] - } + assert( + false, + "direct_deps_only does not work without use_interface_jars or use_unprocessed_jars") + } + } else { + if (_use_interface_jars) { + args += [ "--jars=@FileArg($_rebased_build_config:dist_jar:all_interface_jars)" ] + } else if (_use_unprocessed_jars) { + args += [ "--jars=@FileArg($_rebased_build_config:deps_info:javac_full_classpath)" ] + } else { + args += [ "--jars=@FileArg($_rebased_build_config:deps_info:java_runtime_classpath)" ] } } } - if (defined(invoker.dex_path)) { - dex(target_name) { - deps = [ - ":$_jar_target_name", - ] - input_jars = [ invoker.output ] - output = invoker.dex_path - } + } + + # Combines all dependent .jar files into a single proguarded .dex file. + # + # Variables: + # output: Path to the output dex. + # proguard_configs: List of proguard configs. + # proguard_jar_path: The path to proguard.jar you wish to use. If undefined, + # the proguard used will be the checked in one in //third_party/proguard. + # + # Example + # dist_dex("lib_fatjar") { + # deps = [ ":my_java_lib" ] + # output = "$root_build_dir/MyLibrary.jar" + # } + # dist_jar("sideloaded_dex") { + # deps = [ ":my_java_lib" ] + # output = "$root_build_dir/MyLibrary.jar" + # dex_path = "$root_build_dir/MyLibrary.dex" + # } + template("proguarded_dist_dex") { + _deps = [ + "//third_party/android_tools:android_sdk_java", + "//build/android/buildhooks:build_hooks_android_impl_java", + ] + if (defined(invoker.deps)) { + _deps += invoker.deps + } + + _build_config = "$target_gen_dir/$target_name.build_config" + _build_config_target_name = "${target_name}__build_config" + + write_build_config(_build_config_target_name) { + type = "dist_jar" + forward_variables_from(invoker, [ "proguard_configs" ]) + supports_android = true + requires_android = true + proguard_enabled = true + possible_config_deps = _deps + build_config = _build_config + } + + _deps += [ ":$_build_config_target_name" ] + + dex(target_name) { + deps = _deps + build_config = _build_config + proguard_enabled = true + forward_variables_from(invoker, [ "proguard_configs" ]) + output = invoker.output } } @@ -1923,11 +1909,7 @@ _enable_multidex = defined(invoker.enable_multidex) && invoker.enable_multidex - if (_enable_multidex) { - _final_dex_path = "$_gen_dir/classes.dex.zip" - } else { - _final_dex_path = "$_gen_dir/classes.dex" - } + _final_dex_path = "$_gen_dir/classes.dex.zip" if (defined(invoker.final_apk_path)) { _final_apk_path = invoker.final_apk_path @@ -2100,7 +2082,7 @@ _proguard_enabled = defined(invoker.proguard_enabled) && invoker.proguard_enabled if (_proguard_enabled) { - _proguard_output_jar_path = "$_base_path.proguard.jar" + _proguard_mapping_path = "$_final_apk_path.mapping" } # TODO(crbug.com/864142): Allow incremental installs of bundle modules. @@ -2403,7 +2385,7 @@ if (_enable_multidex) { proguard_configs += [ "//build/android/multidex.flags" ] } - proguard_output_jar_path = _proguard_output_jar_path + proguard_mapping_path = _proguard_mapping_path } # Don't depend on the runtime_deps target in order to avoid having to @@ -2446,66 +2428,42 @@ # place later due to synchronized proguarding. For more details, # read build/android/docs/android_app_bundles.md if (!(_is_bundle_module && _proguard_enabled)) { - if (_proguard_enabled) { - _proguard_target = "${_template_name}__proguard" - proguard(_proguard_target) { - forward_variables_from(invoker, [ "proguard_jar_path" ]) - build_config = _build_config - deps = _deps + [ - ":$_build_config_target", - ":$_compile_resources_target", - ":$_java_target", - ] - inputs = [ - _jar_path, - ] - - output_jar_path = _proguard_output_jar_path - args = [ - "--proguard-configs=@FileArg($_rebased_build_config:deps_info:proguard_all_configs)", - "--input-paths=@FileArg($_rebased_build_config:deps_info:java_runtime_classpath)", - ] - if (defined(invoker.proguard_config_exclusions)) { - _rebased_proguard_config_exclusions = - rebase_path(invoker.proguard_config_exclusions, root_build_dir) - args += [ "--proguard-config-exclusions=$_rebased_proguard_config_exclusions" ] - } - if (defined(invoker.apk_under_test)) { - args += [ "--mapping=@FileArg($_rebased_build_config:deps_info:proguard_under_test_mapping)" ] - deps += [ "${invoker.apk_under_test}__proguard" ] - } - } - _dex_sources = [ _proguard_output_jar_path ] - _dex_deps = [ ":$_proguard_target" ] - - _copy_proguard_mapping_target = - "${_template_name}__copy_proguard_mapping" - copy(_copy_proguard_mapping_target) { - sources = [ - "$_proguard_output_jar_path.mapping", - ] - outputs = [ - "$_final_apk_path.mapping", - ] - deps = [ - ":$_proguard_target", - ] - } - } else { - if (_enable_multidex) { - # .jar already included in java_runtime_classpath. - _dex_sources = [] - } else { - _dex_sources = [ _lib_dex_path ] - } - _dex_deps = [ ":$_java_target" ] - } - _final_dex_target_name = "${_template_name}__final_dex" - dex("$_final_dex_target_name") { - forward_variables_from(invoker, [ "min_sdk_version" ]) - deps = _dex_deps + [ ":$_build_config_target" ] - input_jars = _dex_sources + dex(_final_dex_target_name) { + forward_variables_from(invoker, + [ + "min_sdk_version", + "dexlayout_profile", + ]) + proguard_enabled = _proguard_enabled + build_config = _build_config + deps = [ + ":$_build_config_target", + ":$_java_target", + ] + if (_proguard_enabled) { + forward_variables_from(invoker, [ "proguard_jar_path" ]) + deps += _deps + [ ":$_compile_resources_target" ] + proguard_configs = [ _jar_path ] + if (defined(invoker.apk_under_test)) { + proguard_args = [ "--mapping=@FileArg($_rebased_build_config:deps_info:proguard_under_test_mapping)" ] + deps += [ "${invoker.apk_under_test}__final_dex" ] + } + proguard_mapping_path = _proguard_mapping_path + } else { + if (_enable_multidex) { + # .jar already included in java_runtime_classpath. + input_jars = [] + _dex_arg_key = + "${_rebased_build_config}:deps_info:java_runtime_classpath" + } else { + input_jars = [ _lib_dex_path ] + _dex_arg_key = + "${_rebased_build_config}:final_dex:dependency_dex_files" + } + input_jars_file_arg = "@FileArg($_dex_arg_key)" + } + output = _final_dex_path enable_multidex = _enable_multidex @@ -2514,24 +2472,6 @@ extra_main_dex_proguard_config = _generated_proguard_main_dex_config deps += [ ":$_compile_resources_target" ] } - - forward_variables_from(invoker, [ "dexlayout_profile" ]) - - # All deps are already included in _dex_sources when proguard is used. - if (!_proguard_enabled) { - if (_enable_multidex) { - _dex_arg_key = - "${_rebased_build_config}:deps_info:java_runtime_classpath" - } else { - _dex_arg_key = - "${_rebased_build_config}:final_dex:dependency_dex_files" - } - build_config = _build_config - input_jars_file_arg = "@FileArg($_dex_arg_key)" - } - - # http://crbug.com/725224. Fix for bots running out of memory. - use_pool = true } } else { # A small sanity check to help developers with a subtle point! @@ -2792,13 +2732,6 @@ # Generate apk related operations at runtime. public_deps += _apk_operations - - # Make the proguard .mapping file easy to find by putting it beside the .apk. - if (_proguard_enabled && !_is_bundle_module) { - deps = [ - ":$_copy_proguard_mapping_target", - ] - } } } @@ -3827,7 +3760,7 @@ build_config = _build_config deps = _module_targets + [ ":$_build_config_target" ] - output_jar_path = _proguard_output_jar_path + output_path = _proguard_output_jar_path args = [ "--proguard-configs=@FileArg($_rebased_build_config:deps_info:proguard_all_configs)", "--input-paths=@FileArg($_rebased_build_config:deps_info:java_runtime_classpath)", @@ -3885,9 +3818,6 @@ input_jars = [ _module_jar_path ] output = _module_final_dex_path - # http://crbug.com/725224. Fix for bots running out of memory. - use_pool = true - if (_enable_multidex && _module.name == "base") { enable_multidex = _enable_multidex extra_main_dex_proguard_config =
diff --git a/cc/layers/surface_layer.cc b/cc/layers/surface_layer.cc index 6b9e900..89dca4b 100644 --- a/cc/layers/surface_layer.cc +++ b/cc/layers/surface_layer.cc
@@ -68,6 +68,9 @@ } void SurfaceLayer::SetFallbackSurfaceId(const viz::SurfaceId& surface_id) { + // The fallback should never move backwards. + DCHECK(!surface_range_.start() || + !surface_range_.start()->IsNewerThan(surface_id)); if (surface_range_.start() == surface_id) return; TRACE_EVENT_WITH_FLOW2(
diff --git a/chrome/android/BUILD.gn b/chrome/android/BUILD.gn index 1279138c..d1c30fdd 100644 --- a/chrome/android/BUILD.gn +++ b/chrome/android/BUILD.gn
@@ -1501,7 +1501,9 @@ } version_name = chrome_version_name - enable_multidex = true + if (experimental_r8_path == "") { + enable_multidex = true + } } } @@ -1849,7 +1851,9 @@ base_module_target = ":monochrome_public_base_module" if (!is_java_debug) { proguard_enabled = true - enable_multidex = true + if (experimental_r8_path == "") { + enable_multidex = true + } proguard_android_sdk_dep = webview_framework_dep } if (modularize_ar) {
diff --git a/chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/FeedNewTabPage.java b/chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/FeedNewTabPage.java index 2d7ed73..e97b534 100644 --- a/chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/FeedNewTabPage.java +++ b/chrome/android/feed/core/java/src/org/chromium/chrome/browser/feed/FeedNewTabPage.java
@@ -244,12 +244,9 @@ @Override protected void initializeMainView(Context context) { int topPadding = context.getResources().getDimensionPixelOffset(R.dimen.tab_strip_height); - int bottomPadding = mTab.getActivity().getFullscreenManager().getBottomControlsHeight(); mRootView = new RootView(context); - mRootView.setLayoutParams(new FrameLayout.LayoutParams( - FrameLayout.LayoutParams.MATCH_PARENT, FrameLayout.LayoutParams.MATCH_PARENT)); - mRootView.setPadding(0, topPadding, 0, bottomPadding); + mRootView.setPadding(0, topPadding, 0, 0); mUiConfig = new UiConfig(mRootView); }
diff --git a/chrome/android/java/res/drawable/ic_article_blue_24dp.xml b/chrome/android/java/res/drawable/ic_article_blue_24dp.xml new file mode 100644 index 0000000..223976ff --- /dev/null +++ b/chrome/android/java/res/drawable/ic_article_blue_24dp.xml
@@ -0,0 +1,11 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright 2018 The Chromium Authors. All rights reserved. + Use of this source code is governed by a BSD-style license that can be + found in the LICENSE file. --> + +<vector xmlns:tools="http://schemas.android.com/tools" tools:targetApi="21" + android:autoMirrored="true" android:height="24dp" + android:viewportHeight="24" android:viewportWidth="24" + android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android"> + <path android:fillColor="@color/default_icon_color_blue" android:pathData="M19,3L5,3c-1.1,0 -2,0.9 -2,2v14c0,1.1 0.9,2 2,2h14c1.1,0 2,-0.9 2,-2L21,5c0,-1.1 -0.9,-2 -2,-2zM14,17L7,17v-2h7v2zM17,13L7,13v-2h10v2zM17,9L7,9L7,7h10v2z"/> +</vector>
diff --git a/chrome/android/java/res/drawable/ic_restaurant_menu_blue_24dp.xml b/chrome/android/java/res/drawable/ic_restaurant_menu_blue_24dp.xml deleted file mode 100644 index 681c872..0000000 --- a/chrome/android/java/res/drawable/ic_restaurant_menu_blue_24dp.xml +++ /dev/null
@@ -1,11 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- Copyright 2018 The Chromium Authors. All rights reserved. - Use of this source code is governed by a BSD-style license that can be - found in the LICENSE file. --> - -<vector xmlns:tools="http://schemas.android.com/tools" tools:targetApi="21" - xmlns:android="http://schemas.android.com/apk/res/android" - android:height="24dp" android:width="24dp" - android:viewportHeight="24.0" android:viewportWidth="24.0"> - <path android:fillColor="@color/default_icon_color_blue" android:pathData="M8.1,13.34l2.83,-2.83L3.91,3.5c-1.56,1.56 -1.56,4.09 0,5.66l4.19,4.18zM14.88,11.53c1.53,0.71 3.68,0.21 5.27,-1.38 1.91,-1.91 2.28,-4.65 0.81,-6.12 -1.46,-1.46 -4.2,-1.1 -6.12,0.81 -1.59,1.59 -2.09,3.74 -1.38,5.27L3.7,19.87l1.41,1.41L12,14.41l6.88,6.88 1.41,-1.41L13.41,13l1.47,-1.47z"/> -</vector>
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 8ec885a..2bccbc0 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/ChromeActivity.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/ChromeActivity.java
@@ -1440,6 +1440,8 @@ mManualFillingController.initialize(getWindowAndroid(), new DeferredViewStubInflationProvider<>(accessoryBarStub), new DeferredViewStubInflationProvider<>(accessorySheetStub)); + getCompositorViewHolder().setKeyboardExtensionView( + mManualFillingController.getKeyboardExtensionSizeManager()); } // Create after native initialization so subclasses that override this method have a chance @@ -2022,10 +2024,7 @@ @Override public void onTrimMemory(int level) { super.onTrimMemory(level); - // The conditions are expressed using ranges to capture intermediate levels possibly added - // to the API in the future. - if ((level >= TRIM_MEMORY_RUNNING_LOW && level < TRIM_MEMORY_UI_HIDDEN) - || level >= TRIM_MEMORY_MODERATE) { + if (ChromeApplication.isSevereMemorySignal(level)) { mReferencePool.drain(); clearToolbarResourceCache(); }
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 ddf0450..91185f2b 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/ChromeApplication.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/ChromeApplication.java
@@ -137,14 +137,19 @@ @Override public void onTrimMemory(int level) { super.onTrimMemory(level); + if (isSevereMemorySignal(level) && mReferencePool != null) mReferencePool.drain(); + CustomTabsConnection.onTrimMemory(level); + } + + /** + * Determines whether the given memory signal is considered severe. + * @param level The type of signal as defined in {@link android.content.ComponentCallbacks2}. + */ + public static boolean isSevereMemorySignal(int level) { // The conditions are expressed using ranges to capture intermediate levels possibly added // to the API in the future. - if ((level >= TRIM_MEMORY_RUNNING_LOW && level < TRIM_MEMORY_UI_HIDDEN) - || level >= TRIM_MEMORY_MODERATE) { - if (mReferencePool != null) mReferencePool.drain(); - - CustomTabsConnection.trimMemory(); - } + return (level >= TRIM_MEMORY_RUNNING_LOW && level < TRIM_MEMORY_UI_HIDDEN) + || level >= TRIM_MEMORY_MODERATE; } /**
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ChromeFeatureList.java b/chrome/android/java/src/org/chromium/chrome/browser/ChromeFeatureList.java index d23df88..15ea63a 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/ChromeFeatureList.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/ChromeFeatureList.java
@@ -147,6 +147,8 @@ } // Alphabetical: + public static final String AUTOFILL_ALLOW_NON_HTTP_ACTIVATION = + "AutofillAllowNonHttpActivation"; public static final String ADJUST_WEBAPK_INSTALLATION_SPACE = "AdjustWebApkInstallationSpace"; public static final String ANDROID_PAY_INTEGRATION_V1 = "AndroidPayIntegrationV1"; public static final String ANDROID_PAY_INTEGRATION_V2 = "AndroidPayIntegrationV2"; @@ -167,6 +169,8 @@ public static final String CCT_POST_MESSAGE_API = "CCTPostMessageAPI"; public static final String CCT_REDIRECT_PRECONNECT = "CCTRedirectPreconnect"; public static final String CCT_RESOURCE_PREFETCH = "CCTResourcePrefetch"; + public static final String CCT_REPORT_PARALLEL_REQUEST_STATUS = + "CCTReportParallelRequestStatus"; public static final String CHROME_DUET = "ChromeDuet"; // TODO(mdjones): Remove CHROME_HOME_SWIPE_VELOCITY_FEATURE or rename. public static final String CHROME_HOME_SWIPE_VELOCITY_FEATURE = "ChromeHomeSwipeLogicVelocity";
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 aa249f3..0fdadf9 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java
@@ -2027,10 +2027,7 @@ @Override public void onTrimMemory(int level) { super.onTrimMemory(level); - // The conditions are expressed using ranges to capture intermediate levels possibly added - // to the API in the future. - if ((level >= TRIM_MEMORY_RUNNING_LOW && level < TRIM_MEMORY_UI_HIDDEN) - || level >= TRIM_MEMORY_MODERATE) { + if (ChromeApplication.isSevereMemorySignal(level)) { NativePageAssassin.getInstance().freezeAllHiddenPages(); } }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/KeyboardExtensionSizeManager.java b/chrome/android/java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/KeyboardExtensionSizeManager.java new file mode 100644 index 0000000..a9d2d08c --- /dev/null +++ b/chrome/android/java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/KeyboardExtensionSizeManager.java
@@ -0,0 +1,67 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package org.chromium.chrome.browser.autofill.keyboard_accessory; + +import android.support.annotation.Px; + +import org.chromium.base.ObserverList; + +/** + * This class holds the size of any extension to or even replacement for a keyboard. + * For example, it is used by {@link ManualFillingCoordinator} to provide the combined height of + * {@link KeyboardAccessoryCoordinator} and {@link AccessorySheetCoordinator}. + * The height can then be used to either compute an offset for bottom bars (e.g. CCTs or PWAs) or to + * push up the content area. + */ +public class KeyboardExtensionSizeManager { + private int mHeight; + private final ObserverList<Observer> mObservers = new ObserverList<>(); + + /** + * Observers are notified when the size of the keyboard extension changes. + */ + public interface Observer { + /** + * Called when the extension height changes. + * @param keyboardHeight The new height of the keyboard extension. + */ + void onKeyboardExtensionHeightChanged(@Px int keyboardHeight); + } + + /** + * Returns the height of the keyboard extension. + * @return A height in pixels. + */ + public @Px int getKeyboardExtensionHeight() { + return mHeight; + } + + /** + * Registered observers are called whenever the extension size changes until unregistered. Does + * not guarantee order. + * @param observer a {@link KeyboardExtensionSizeManager.Observer}. + */ + public void addObserver(Observer observer) { + mObservers.addObserver(observer); + } + + /** + * Removes a registered observer if present. + * @param observer a registered {@link KeyboardExtensionSizeManager.Observer}. + */ + public void removeObserver(Observer observer) { + mObservers.removeObserver(observer); + } + + /** + * Sets a new extension height and notifies observers if its value changed. + * @param newKeyboardExtensionHeight The height in pixels. + */ + void setKeyboardExtensionHeight(@Px int newKeyboardExtensionHeight) { + if (mHeight == newKeyboardExtensionHeight) return; + mHeight = newKeyboardExtensionHeight; + for (Observer observer : mObservers) observer.onKeyboardExtensionHeightChanged(mHeight); + } +} \ No newline at end of file
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/ManualFillingCoordinator.java b/chrome/android/java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/ManualFillingCoordinator.java index c97d6818..300f5db 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/ManualFillingCoordinator.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/ManualFillingCoordinator.java
@@ -99,6 +99,14 @@ mMediator.registerPasswordProvider(itemProvider); } + public void showWhenKeyboardIsVisible() { + mMediator.showWhenKeyboardIsVisible(); + } + + public void hide() { + mMediator.hide(); + } + public void onResume() { mMediator.resume(); } @@ -107,6 +115,16 @@ mMediator.pause(); } + /** + * Returns a size manager that allows to access the combined height of + * {@link KeyboardAccessoryCoordinator} and {@link AccessorySheetCoordinator}, and to be + * notified when it changes. + * @return A {@link KeyboardExtensionSizeManager}. + */ + public KeyboardExtensionSizeManager getKeyboardExtensionSizeManager() { + return mMediator.getKeyboardExtensionSizeManager(); + } + // TODO(fhorschig): Should be @VisibleForTesting. /** * Allows access to the keyboard accessory. This can be used to explicitly modify the the bar of
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/ManualFillingMediator.java b/chrome/android/java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/ManualFillingMediator.java index 3be9b62..32e289d 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/ManualFillingMediator.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/ManualFillingMediator.java
@@ -30,7 +30,6 @@ import org.chromium.chrome.browser.tabmodel.TabModel; import org.chromium.chrome.browser.tabmodel.TabModelObserver; import org.chromium.chrome.browser.tabmodel.TabModelSelectorTabModelObserver; -import org.chromium.chrome.browser.webapps.WebappActivity; import org.chromium.ui.DropdownPopupWindow; import org.chromium.ui.base.WindowAndroid; @@ -44,10 +43,12 @@ class ManualFillingMediator extends EmptyTabObserver implements KeyboardAccessoryCoordinator.VisibilityDelegate { private WindowAndroid mWindowAndroid; - private @Px int mPreviousControlHeight; private final WindowAndroid.KeyboardVisibilityListener mVisibilityListener = this::onKeyboardVisibilityChanged; private Supplier<InsetObserverView> mInsetObserverViewSupplier; + private boolean mShouldShow = false; + private final KeyboardExtensionSizeManager mKeyboardExtensionSizeManager = + new KeyboardExtensionSizeManager(); /** * Provides a cache for a given Provider which can repeat the last notification to all @@ -146,8 +147,6 @@ void initialize(KeyboardAccessoryCoordinator keyboardAccessory, AccessorySheetCoordinator accessorySheet, WindowAndroid windowAndroid) { assert windowAndroid.getActivity().get() != null; - // Abort initialization for PWAs: https://crbug.com/881536. - if (windowAndroid.getActivity().get() instanceof WebappActivity) return; mWindowAndroid = windowAndroid; mKeyboardAccessory = keyboardAccessory; mAccessorySheet = accessorySheet; @@ -160,7 +159,6 @@ @Override public void didSelectTab(Tab tab, @TabModel.TabSelectionType int type, int lastId) { mActiveBrowserTab = tab; - mPreviousControlHeight = mActivity.getFullscreenManager().getBottomControlsHeight(); restoreCachedState(tab); } @@ -193,18 +191,9 @@ void onKeyboardVisibilityChanged(boolean isShowing) { if (!mKeyboardAccessory.hasContents()) return; // Exit early to not affect the layout. if (isShowing) { - // Don't open the accessory inside the contextual search panel. - ContextualSearchManager contextualSearchManager = - mActivity.getContextualSearchManager(); - if (contextualSearchManager != null && contextualSearchManager.isSearchPanelOpened()) { - return; + if (mShouldShow) { + displayKeyboardAccessory(); } - mKeyboardAccessory.requestShowing(); - mActivity.getFullscreenManager().setBottomControlsHeight(calculateAccessoryBarHeight()); - mKeyboardAccessory.closeActiveTab(); - updateInfobarState(true); - mKeyboardAccessory.setBottomOffset(0); - mAccessorySheet.hide(); } else { mKeyboardAccessory.close(); onBottomControlSpaceChanged(); @@ -262,6 +251,20 @@ mPopup = popup; } + void showWhenKeyboardIsVisible() { + if (!isInitialized() || !mKeyboardAccessory.hasContents() || mShouldShow) return; + mShouldShow = true; + ViewGroup contentView = getContentView(); + if (mWindowAndroid.getKeyboardDelegate().isKeyboardShowing(mActivity, contentView)) { + displayKeyboardAccessory(); + } + } + + void hide() { + mShouldShow = false; + pause(); + } + public void pause() { if (!isInitialized()) return; mKeyboardAccessory.dismiss(); @@ -273,6 +276,24 @@ restoreCachedState(mActiveBrowserTab); } + private void displayKeyboardAccessory() { + // Don't open the accessory inside the contextual search panel. + ContextualSearchManager contextualSearchManager = mActivity.getContextualSearchManager(); + if (contextualSearchManager != null && contextualSearchManager.isSearchPanelOpened()) { + return; + } + mKeyboardAccessory.requestShowing(); + mKeyboardExtensionSizeManager.setKeyboardExtensionHeight(calculateAccessoryBarHeight()); + mKeyboardAccessory.closeActiveTab(); + updateInfobarState(true); + mKeyboardAccessory.setBottomOffset(0); + mAccessorySheet.hide(); + } + + KeyboardExtensionSizeManager getKeyboardExtensionSizeManager() { + return mKeyboardExtensionSizeManager; + } + @Override public void onChangeAccessorySheet(int tabIndex) { assert mActivity != null : "ManualFillingMediator needs initialization."; @@ -294,7 +315,7 @@ if (mWindowAndroid.getKeyboardDelegate().isKeyboardShowing(mActivity, contentView)) { return; // If the keyboard is showing or is starting to show, the sheet closes gently. } - mActivity.getFullscreenManager().setBottomControlsHeight(mPreviousControlHeight); + mKeyboardExtensionSizeManager.setKeyboardExtensionHeight(0); mKeyboardAccessory.closeActiveTab(); updateInfobarState(false); mKeyboardAccessory.setBottomOffset(0); @@ -311,7 +332,7 @@ @Override public void onOpenKeyboard() { assert mActivity != null : "ManualFillingMediator needs initialization."; - mActivity.getFullscreenManager().setBottomControlsHeight(calculateAccessoryBarHeight()); + mKeyboardExtensionSizeManager.setKeyboardExtensionHeight(calculateAccessoryBarHeight()); if (mActivity.getCurrentFocus() != null) { mWindowAndroid.getKeyboardDelegate().showKeyboard(mActivity.getCurrentFocus()); } @@ -326,8 +347,9 @@ newControlsOffset += mAccessorySheet.getHeight(); } mKeyboardAccessory.setBottomOffset(newControlsOffset); - mActivity.getFullscreenManager().setBottomControlsHeight( - mKeyboardAccessory.isShown() ? newControlsHeight : mPreviousControlHeight); + mKeyboardExtensionSizeManager.setKeyboardExtensionHeight( + mKeyboardAccessory.isShown() ? newControlsHeight : 0); + mActivity.getFullscreenManager().updateViewportSize(); } /**
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/PasswordAccessoryBridge.java b/chrome/android/java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/PasswordAccessoryBridge.java index 145fb92..b9ddbce 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/PasswordAccessoryBridge.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/PasswordAccessoryBridge.java
@@ -71,6 +71,16 @@ } @CalledByNative + void showWhenKeyboardIsVisible() { + mManualFillingCoordinator.showWhenKeyboardIsVisible(); + } + + @CalledByNative + void hide() { + mManualFillingCoordinator.hide(); + } + + @CalledByNative private void closeAccessorySheet() { mManualFillingCoordinator.closeAccessorySheet(); }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantUiDelegate.java b/chrome/android/java/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantUiDelegate.java index 8e7e2bb..f9e7432 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantUiDelegate.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantUiDelegate.java
@@ -4,7 +4,6 @@ package org.chromium.chrome.browser.autofill_assistant; -import android.app.Activity; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.drawable.Drawable; @@ -23,8 +22,11 @@ import org.chromium.base.Promise; import org.chromium.chrome.R; +import org.chromium.chrome.browser.ChromeActivity; import org.chromium.chrome.browser.autofill.PersonalDataManager.AutofillProfile; import org.chromium.chrome.browser.autofill.PersonalDataManager.CreditCard; +import org.chromium.chrome.browser.help.HelpAndFeedback; +import org.chromium.chrome.browser.profiles.Profile; import java.io.InputStream; import java.net.URL; @@ -36,13 +38,16 @@ /** Delegate to interact with the assistant UI. */ class AutofillAssistantUiDelegate { + private static final String FEEDBACK_CATEGORY_TAG = + "com.android.chrome.USER_INITIATED_FEEDBACK_REPORT_AUTOFILL_ASSISTANT"; + // TODO(crbug.com/806868): Use correct user locale. private static final SimpleDateFormat sDetailsTimeFormat = new SimpleDateFormat("H:mma", Locale.getDefault()); private static final SimpleDateFormat sDetailsDateFormat = new SimpleDateFormat("EEE, MMM d", Locale.getDefault()); - private final Activity mActivity; + private final ChromeActivity mActivity; private final Client mClient; private final View mFullContainer; private final View mOverlay; @@ -160,10 +165,10 @@ /** * Constructs an assistant UI delegate. * - * @param activity The Activity + * @param activity The ChromeActivity * @param client The client to forward events to */ - public AutofillAssistantUiDelegate(Activity activity, Client client) { + public AutofillAssistantUiDelegate(ChromeActivity activity, Client client) { mActivity = activity; mClient = client; @@ -178,9 +183,9 @@ mBottomBar.findViewById(R.id.close_button).setOnClickListener(unusedView -> shutdown()); mBottomBar.findViewById(R.id.feedback_button) .setOnClickListener(unusedView - -> { - // TODO(crbug.com/806868): Send feedback. - }); + -> HelpAndFeedback.getInstance(mActivity).showFeedback(mActivity, + Profile.getLastUsedProfile(), mActivity.getActivityTab().getUrl(), + FEEDBACK_CATEGORY_TAG)); mChipsViewContainer = mBottomBar.findViewById(R.id.carousel); mStatusMessageView = mBottomBar.findViewById(R.id.status_message);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/compositor/CompositorViewHolder.java b/chrome/android/java/src/org/chromium/chrome/browser/compositor/CompositorViewHolder.java index 8b32f05..216df02 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/compositor/CompositorViewHolder.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/compositor/CompositorViewHolder.java
@@ -14,6 +14,8 @@ import android.os.Build; import android.os.Bundle; import android.os.Handler; +import android.support.annotation.Nullable; +import android.support.annotation.Px; import android.support.v4.view.ViewCompat; import android.support.v4.view.accessibility.AccessibilityEventCompat; import android.support.v4.view.accessibility.AccessibilityNodeInfoCompat; @@ -32,6 +34,7 @@ import org.chromium.base.TraceEvent; import org.chromium.chrome.R; import org.chromium.chrome.browser.InsetObserverView; +import org.chromium.chrome.browser.autofill.keyboard_accessory.KeyboardExtensionSizeManager; import org.chromium.chrome.browser.compositor.Invalidator.Client; import org.chromium.chrome.browser.compositor.layouts.LayoutManager; import org.chromium.chrome.browser.compositor.layouts.LayoutManagerHost; @@ -72,7 +75,8 @@ */ public class CompositorViewHolder extends FrameLayout implements ContentOffsetProvider, LayoutManagerHost, LayoutRenderHost, Invalidator.Host, - FullscreenListener, InsetObserverView.WindowInsetObserver { + FullscreenListener, InsetObserverView.WindowInsetObserver, + KeyboardExtensionSizeManager.Observer { private static final long SYSTEM_UI_VIEWPORT_UPDATE_DELAY_MS = 500; private boolean mIsKeyboardShowing; @@ -103,6 +107,7 @@ /** The toolbar control container. **/ private ControlContainer mControlContainer; + private @Nullable KeyboardExtensionSizeManager mKeyboardExtensionSizeManager; private InsetObserverView mInsetObserverView; private boolean mShowingFullscreen; private Runnable mSystemUiFullscreenResizeRunnable; @@ -374,6 +379,38 @@ public void onSafeAreaChanged(Rect area) {} /** + * Allows to set (or unset if called with null) the {@link KeyboardExtensionSizeManager} that + * provides the dimensions of any keyboard extensions or replacements. Registers an observer to + * react to size changes immediately. + * @param manager A {@link KeyboardExtensionSizeManager}. Optional. + */ + public void setKeyboardExtensionView(@Nullable KeyboardExtensionSizeManager manager) { + if (mKeyboardExtensionSizeManager != null) { + mKeyboardExtensionSizeManager.removeObserver(this); + } + mKeyboardExtensionSizeManager = manager; + if (mKeyboardExtensionSizeManager != null) { + mKeyboardExtensionSizeManager.addObserver(this); + onViewportChanged(); + } + } + + @Override + public void onKeyboardExtensionHeightChanged(int keyboardHeight) { + onUpdateViewportSize(); + } + + /** + * Returns the combined height of all extensions to or replacements of the keyboard which + * consume space at the bottom of the content area. + * @return the full height in pixels. + */ + public @Px int getKeyboardExtensionsHeight() { + if (mKeyboardExtensionSizeManager == null) return 0; + return mKeyboardExtensionSizeManager.getKeyboardExtensionHeight(); + } + + /** * Should be called for cleanup when the CompositorView instance is no longer used. */ public void shutDown() { @@ -572,6 +609,7 @@ int controlsHeight = controlsResizeView() ? getTopControlsHeightPixels() + getBottomControlsHeightPixels() : 0; + controlsHeight += getKeyboardExtensionsHeight(); if (isAttachedToWindow(view)) { webContents.setSize(w, h - controlsHeight); } else {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/contacts_picker/PickerCategoryView.java b/chrome/android/java/src/org/chromium/chrome/browser/contacts_picker/PickerCategoryView.java index 2e84b3cb..30fee587 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/contacts_picker/PickerCategoryView.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/contacts_picker/PickerCategoryView.java
@@ -338,7 +338,7 @@ * @param contacts The contacts that were selected (if any). */ private void executeAction( - ContactsPickerListener.ContactsPickerAction action, String contacts) { + @ContactsPickerListener.ContactsPickerAction int action, String contacts) { mListener.onContactsPickerUserAction(action, contacts); mDialog.dismiss(); UiUtils.onContactsPickerDismissed();
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabActivity.java index 22939f1..9de3cae 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabActivity.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabActivity.java
@@ -1009,7 +1009,7 @@ moduleComponentName = mIntentDataProvider.getModuleComponentName(); } if (moduleComponentName != null) { - mConnection.getModuleLoader(moduleComponentName).maybeUnloadModule(); + mConnection.getModuleLoader(moduleComponentName).decrementModuleUseCount(); } if (mIncognitoTabHost != null) { IncognitoTabHostRegistry.getInstance().unregister(mIncognitoTabHost);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabBottomBarDelegate.java b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabBottomBarDelegate.java index 72e8199..1b000251 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabBottomBarDelegate.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabBottomBarDelegate.java
@@ -334,6 +334,24 @@ } @Override + public void onUpdateViewportSize() { + if (mBottomBarView == null) return; // Check bottom bar view but don't inflate it. + // Hide the container of the bottom bar while the extension is showing. This doesn't + // affect the content. + boolean keyboardExtensionHidesBottomBar = mActivity.getManualFillingController() + .getKeyboardExtensionSizeManager() + .getKeyboardExtensionHeight() + > 0; + if (keyboardExtensionHidesBottomBar) { + getBottomBarView().setVisibility(View.GONE); + mFullscreenManager.setBottomControlsHeight(0); + } else { + getBottomBarView().setVisibility(View.VISIBLE); + mFullscreenManager.setBottomControlsHeight(getBottomBarHeight()); + } + } + + @Override public void onContentOffsetChanged(float offset) { } @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 f31fedc..ff25d22 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
@@ -37,6 +37,7 @@ import org.chromium.base.TimeUtils; import org.chromium.base.TraceEvent; import org.chromium.base.VisibleForTesting; +import org.chromium.base.annotations.CalledByNative; import org.chromium.base.annotations.JNINamespace; import org.chromium.base.library_loader.LibraryProcessType; import org.chromium.base.library_loader.ProcessInitException; @@ -96,6 +97,7 @@ private static final String TAG = "ChromeConnection"; private static final String LOG_SERVICE_REQUESTS = "custom-tabs-log-service-requests"; + // Callback names for |extraCallback()|. @VisibleForTesting static final String PAGE_LOAD_METRICS_CALLBACK = "NavigationMetrics"; static final String BOTTOM_BAR_SCROLL_STATE_CALLBACK = "onBottomBarScrollStateChanged"; @@ -103,6 +105,10 @@ static final String OPEN_IN_BROWSER_CALLBACK = "onOpenInBrowser"; @VisibleForTesting static final String ON_WARMUP_COMPLETED = "onWarmupCompleted"; + @VisibleForTesting + static final String ON_DETACHED_REQUEST_REQUESTED = "onDetachedRequestRequested"; + @VisibleForTesting + static final String ON_DETACHED_REQUEST_COMPLETED = "onDetachedRequestCompleted"; // For CustomTabs.SpeculationStatusOnStart, see tools/metrics/enums.xml. Append only. private static final int SPECULATION_STATUS_ON_START_ALLOWED = 0; @@ -876,6 +882,19 @@ if (mLogRequests) { Log.w(TAG, "handleParallelRequest() = " + PARALLEL_REQUEST_MESSAGES[status]); } + + if ((status != ParallelRequestStatus.NO_REQUEST) + && (status != ParallelRequestStatus.FAILURE_NOT_INITIALIZED) + && (status != ParallelRequestStatus.FAILURE_NOT_AUTHORIZED) + && ChromeFeatureList.isEnabled( + ChromeFeatureList.CCT_REPORT_PARALLEL_REQUEST_STATUS)) { + Bundle args = new Bundle(); + Uri url = intent.getParcelableExtra(PARALLEL_REQUEST_URL_KEY); + args.putParcelable("url", url); + args.putInt("status", status); + safeExtraCallback(session, ON_DETACHED_REQUEST_REQUESTED, args); + } + return status; } @@ -914,11 +933,13 @@ String urlString = url.toString(); String referrerString = referrer.toString(); - nativeCreateAndStartDetachedResourceRequest(Profile.getLastUsedProfile(), urlString, - referrerString, policy, DetachedResourceRequestMotivation.PARALLEL_REQUEST); + nativeCreateAndStartDetachedResourceRequest(Profile.getLastUsedProfile(), session, + urlString, referrerString, policy, + DetachedResourceRequestMotivation.PARALLEL_REQUEST); if (mLogRequests) { Log.w(TAG, "startParallelRequest(%s, %s, %d)", urlString, referrerString, policy); } + return ParallelRequestStatus.SUCCESS; } @@ -951,8 +972,10 @@ String urlString = url.toString(); if (urlString.isEmpty() || !isValid(url)) continue; - nativeCreateAndStartDetachedResourceRequest(Profile.getLastUsedProfile(), urlString, - referrerString, policy, DetachedResourceRequestMotivation.RESOURCE_PREFETCH); + // Session is null because we don't need completion notifications. + nativeCreateAndStartDetachedResourceRequest(Profile.getLastUsedProfile(), null, + urlString, referrerString, policy, + DetachedResourceRequestMotivation.RESOURCE_PREFETCH); ++requestsSent; if (mLogRequests) { @@ -1333,11 +1356,15 @@ /** * Discards substantial objects that are not currently in use. + * @param level The type of signal as defined in {@link android.content.ComponentCallbacks2}. */ - public static void trimMemory() { + public static void onTrimMemory(int level) { if (!hasInstance()) return; - getInstance().mClientManager.cleanupUnusedSessions(); - if (getInstance().mModuleLoader != null) getInstance().mModuleLoader.trimMemory(); + + if (ChromeApplication.isSevereMemorySignal(level)) { + getInstance().mClientManager.cleanupUnusedSessions(); + } + if (getInstance().mModuleLoader != null) getInstance().mModuleLoader.onTrimMemory(level); } @VisibleForTesting @@ -1485,7 +1512,8 @@ } private static native void nativeCreateAndStartDetachedResourceRequest(Profile profile, - String url, String origin, @WebReferrerPolicy int referrerPolicy, + CustomTabsSessionToken session, String url, String origin, + @WebReferrerPolicy int referrerPolicy, @DetachedResourceRequestMotivation int motivation); public ModuleLoader getModuleLoader(ComponentName componentName) { @@ -1502,4 +1530,16 @@ ActivityDelegate activityDelegate, int moduleVersion) { mClientManager.setActivityDelegateForSession(sessionToken, activityDelegate, moduleVersion); } + + @CalledByNative + public static void notifyClientOfDetachedRequestCompletion( + CustomTabsSessionToken session, String url, int status) { + if (!ChromeFeatureList.isEnabled(ChromeFeatureList.CCT_REPORT_PARALLEL_REQUEST_STATUS)) { + return; + } + Bundle args = new Bundle(); + args.putParcelable("url", Uri.parse(url)); + args.putInt("net_error", status); + getInstance().safeExtraCallback(session, ON_DETACHED_REQUEST_COMPLETED, args); + } }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/dynamicmodule/ModuleLoader.java b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/dynamicmodule/ModuleLoader.java index afcf3f725..e829ece 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/dynamicmodule/ModuleLoader.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/dynamicmodule/ModuleLoader.java
@@ -4,6 +4,7 @@ package org.chromium.chrome.browser.customtabs.dynamicmodule; +import android.content.ComponentCallbacks2; import android.content.ComponentName; import android.content.Context; import android.content.pm.PackageInfo; @@ -16,9 +17,11 @@ import org.chromium.base.ContextUtils; import org.chromium.base.Log; import org.chromium.base.task.AsyncTask; +import org.chromium.chrome.browser.ChromeApplication; import org.chromium.chrome.browser.ChromeFeatureList; import org.chromium.chrome.browser.crash.CrashKeyIndex; import org.chromium.chrome.browser.crash.CrashKeys; +import org.chromium.chrome.browser.customtabs.dynamicmodule.ModuleMetrics.DestructionReason; /** * Dynamically loads a module from another apk. @@ -29,7 +32,30 @@ /** Specifies the module package name and entry point class name. */ private final ComponentName mComponentName; private final String mModuleId; + + /** + * Tracks the number of usages of the module. If it is no longer used, it may be destroyed, but + * the time of destruction depends on the caching policy. + */ private int mModuleUseCount; + + /** + * The timestamp of the moment the module became unused. This is used to determine whether or + * not to continue caching it. A value of -1 indicates there is no usable value. + */ + private long mModuleUnusedTimeMs = -1; + + /** + * The name of the experiment parameter for setting the caching time limit. + */ + private static final String MODULE_CACHE_TIME_LIMIT_MS_NAME = "cct_module_cache_time_limit_ms"; + + /** + * The default time limit for caching an unused module under mild memory pressure, in + * milliseconds. + */ + private static final int MODULE_CACHE_TIME_LIMIT_MS_DEFAULT = 300000; // 5 minutes + @Nullable private ModuleEntryPoint mModuleEntryPoint; @@ -75,6 +101,7 @@ public Runnable loadModule(Callback<ModuleEntryPoint> callback) { if (mModuleEntryPoint != null) { mModuleUseCount++; + mModuleUnusedTimeMs = -1; ModuleMetrics.recordLoadResult(ModuleMetrics.LoadResult.SUCCESS_CACHED); callback.onResult(mModuleEntryPoint); return null; @@ -97,25 +124,52 @@ }; } - public void maybeUnloadModule() { + public void decrementModuleUseCount() { if (mModuleEntryPoint == null) return; mModuleUseCount--; - if (mModuleUseCount == 0 - && !ChromeFeatureList.isEnabled(ChromeFeatureList.CCT_MODULE_CACHE)) { - destroyModule(); + if (mModuleUseCount == 0) { + mModuleUnusedTimeMs = ModuleMetrics.now(); + if (!ChromeFeatureList.isEnabled(ChromeFeatureList.CCT_MODULE_CACHE)) { + destroyModule(DestructionReason.NO_CACHING_UNUSED); + } } } - public void trimMemory() { + /** + * Destroys the unused cached module (if present) under certain circumstances. If the memory + * signal is considered severe, the module will always be destroyed. If the memory signal is + * considered mild, the module will only be destroyed if the time limit has passed. + * @param level The type of signal as defined in {@link ComponentCallbacks2}. + */ + public void onTrimMemory(int level) { if (mModuleEntryPoint == null || mModuleUseCount > 0) return; - destroyModule(); + + if (ChromeApplication.isSevereMemorySignal(level)) { + destroyModule(DestructionReason.CACHED_SEVERE_MEMORY_PRESSURE); + } else if (cacheExceededTimeLimit()) { + if (level == ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN) { + destroyModule(DestructionReason.CACHED_UI_HIDDEN_TIME_EXCEEDED); + } else { + destroyModule(DestructionReason.CACHED_MILD_MEMORY_PRESSURE_TIME_EXCEEDED); + } + } } - private void destroyModule() { + private boolean cacheExceededTimeLimit() { + if (mModuleUnusedTimeMs == -1) return false; + long limit = ChromeFeatureList.getFieldTrialParamByFeatureAsInt( + ChromeFeatureList.CCT_MODULE_CACHE, MODULE_CACHE_TIME_LIMIT_MS_NAME, + MODULE_CACHE_TIME_LIMIT_MS_DEFAULT); + return ModuleMetrics.now() - mModuleUnusedTimeMs > limit; + } + + private void destroyModule(@DestructionReason int reason) { assert mModuleEntryPoint != null; + ModuleMetrics.recordDestruction(reason); mModuleEntryPoint.onDestroy(); CrashKeys.getInstance().set(CrashKeyIndex.ACTIVE_DYNAMIC_MODULE, null); mModuleEntryPoint = null; + mModuleUnusedTimeMs = -1; } /** @@ -200,6 +254,7 @@ ModuleMetrics.recordLoadResult(ModuleMetrics.LoadResult.SUCCESS_NEW); mModuleEntryPoint = entryPoint; mModuleUseCount = 1; + mModuleUnusedTimeMs = -1; mCallback.onResult(entryPoint); return; } catch (Exception e) {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/dynamicmodule/ModuleMetrics.java b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/dynamicmodule/ModuleMetrics.java index 06573fa0..199af3e 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/dynamicmodule/ModuleMetrics.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/dynamicmodule/ModuleMetrics.java
@@ -67,6 +67,38 @@ } /** + * Possible reasons for destroying a dynamic module. Keep in sync with the + * CustomTabs.DynamicModule.DestructionReason enum in histograms.xml. Do not remove + * or change existing values other than NUM_ENTRIES. + */ + @IntDef({DestructionReason.NO_CACHING_UNUSED, DestructionReason.CACHED_SEVERE_MEMORY_PRESSURE, + DestructionReason.CACHED_MILD_MEMORY_PRESSURE_TIME_EXCEEDED, + DestructionReason.CACHED_UI_HIDDEN_TIME_EXCEEDED}) + @Retention(RetentionPolicy.SOURCE) + public @interface DestructionReason { + /** No caching enabled and the module is unused. */ + int NO_CACHING_UNUSED = 0; + /** Cached and severe memory pressure. */ + int CACHED_SEVERE_MEMORY_PRESSURE = 1; + /** Cached and mild memory pressure and time exceeded. */ + int CACHED_MILD_MEMORY_PRESSURE_TIME_EXCEEDED = 2; + /** Cached and app hidden and time exceeded. */ + int CACHED_UI_HIDDEN_TIME_EXCEEDED = 3; + /** Upper bound for legal sample values - all sample values have to be strictly lower. */ + int NUM_ENTRIES = 4; + } + + /** + * Records the reason for destroying a dynamic module. + * @param reason reason key, one of {@link DestructionReason}'s values. + */ + public static void recordDestruction(@DestructionReason int reason) { + RecordHistogram.recordEnumeratedHistogram("CustomTabs.DynamicModule.DestructionReason", + reason, DestructionReason.NUM_ENTRIES); + Log.d(TAG, "Destroyed module, reason: %s", reason); + } + + /** * SystemClock.uptimeMillis() is used here as it uses the same system call as all the native * side of Chrome, and this is the same clock used for page load metrics. *
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/explore_sites/ExploreSitesSection.java b/chrome/android/java/src/org/chromium/chrome/browser/explore_sites/ExploreSitesSection.java index 62537a44..92ca8998 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/explore_sites/ExploreSitesSection.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/explore_sites/ExploreSitesSection.java
@@ -78,11 +78,11 @@ private List<ExploreSitesCategory> createDefaultCategoryTiles() { List<ExploreSitesCategory> categoryList = new ArrayList<>(); - // Sport category. + // News category. ExploreSitesCategory category = - new ExploreSitesCategory(-1 /* category_id */, CategoryType.SPORT, - getContext().getString(R.string.explore_sites_default_category_sports)); - category.setDrawable(getVectorDrawable(R.drawable.ic_directions_run_blue_24dp)); + new ExploreSitesCategory(-1 /* category_id */, CategoryType.NEWS, + getContext().getString(R.string.explore_sites_default_category_news)); + category.setDrawable(getVectorDrawable(R.drawable.ic_article_blue_24dp)); categoryList.add(category); // Shopping category. @@ -91,11 +91,12 @@ category.setDrawable(getVectorDrawable(R.drawable.ic_shopping_basket_blue_24dp)); categoryList.add(category); - // Food category. - category = new ExploreSitesCategory(-1 /* category_id */, CategoryType.FOOD, - getContext().getString(R.string.explore_sites_default_category_cooking)); - category.setDrawable(getVectorDrawable(R.drawable.ic_restaurant_menu_blue_24dp)); + // Sport category. + category = new ExploreSitesCategory(-1 /* category_id */, CategoryType.SPORT, + getContext().getString(R.string.explore_sites_default_category_sports)); + category.setDrawable(getVectorDrawable(R.drawable.ic_directions_run_blue_24dp)); categoryList.add(category); + return categoryList; }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/media/MediaCaptureNotificationService.java b/chrome/android/java/src/org/chromium/chrome/browser/media/MediaCaptureNotificationService.java index cb9fc64..3f1359e4 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/media/MediaCaptureNotificationService.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/media/MediaCaptureNotificationService.java
@@ -18,12 +18,14 @@ import org.chromium.base.ContextUtils; import org.chromium.base.Log; import org.chromium.chrome.R; +import org.chromium.chrome.browser.ChromeFeatureList; import org.chromium.chrome.browser.notifications.ChromeNotificationBuilder; import org.chromium.chrome.browser.notifications.NotificationBuilderFactory; import org.chromium.chrome.browser.notifications.NotificationUmaTracker; import org.chromium.chrome.browser.notifications.channels.ChannelDefinitions; import org.chromium.chrome.browser.tab.Tab; import org.chromium.chrome.browser.tab.TabWebContentsDelegateAndroid; +import org.chromium.chrome.browser.tabmodel.TabWindowManager; import java.net.MalformedURLException; import java.net.URL; @@ -43,6 +45,7 @@ private static final String NOTIFICATION_NAMESPACE = "MediaCaptureNotificationService"; private static final String NOTIFICATION_ID_EXTRA = "NotificationId"; + private static final String NOTIFICATION_MEDIA_IS_INCOGNITO = "NotificationIsIncognito"; private static final String NOTIFICATION_MEDIA_TYPE_EXTRA = "NotificationMediaType"; private static final String NOTIFICATION_MEDIA_URL_EXTRA = "NotificationMediaUrl"; @@ -96,9 +99,10 @@ int notificationId = intent.getIntExtra(NOTIFICATION_ID_EXTRA, Tab.INVALID_TAB_ID); int mediaType = intent.getIntExtra(NOTIFICATION_MEDIA_TYPE_EXTRA, MEDIATYPE_NO_MEDIA); String url = intent.getStringExtra(NOTIFICATION_MEDIA_URL_EXTRA); + boolean isIncognito = intent.getBooleanExtra(NOTIFICATION_MEDIA_IS_INCOGNITO, false); if (ACTION_MEDIA_CAPTURE_UPDATE.equals(action)) { - updateNotification(notificationId, mediaType, url); + updateNotification(notificationId, mediaType, url, isIncognito); } else if (ACTION_SCREEN_CAPTURE_STOP.equals(action)) { // Notify native to stop screen capture when the STOP button in notification // is clicked. @@ -132,14 +136,15 @@ * @param mediaType Media type of the notification. * @param url Url of the current webrtc call. */ - private void updateNotification(int notificationId, int mediaType, String url) { + private void updateNotification( + int notificationId, int mediaType, String url, boolean isIncognito) { if (doesNotificationExist(notificationId) && !doesNotificationNeedUpdate(notificationId, mediaType)) { return; } destroyNotification(notificationId); if (mediaType != MEDIATYPE_NO_MEDIA) { - createNotification(notificationId, mediaType, url); + createNotification(notificationId, mediaType, url, isIncognito); } if (mNotifications.size() == 0) stopSelf(); } @@ -162,7 +167,8 @@ * @param mediaType Media type of the notification. * @param url Url of the current webrtc call. */ - private void createNotification(int notificationId, int mediaType, String url) { + private void createNotification( + int notificationId, int mediaType, String url, boolean isIncognito) { final String channelId = mediaType == MEDIATYPE_SCREEN_CAPTURE ? ChannelDefinitions.ChannelId.SCREEN_CAPTURE : ChannelDefinitions.ChannelId.MEDIA; @@ -172,13 +178,9 @@ .createChromeNotificationBuilder(true /* preferCompat */, channelId) .setAutoCancel(false) .setOngoing(true) - .setContentTitle( - ContextUtils.getApplicationContext().getString(R.string.app_name)) .setSmallIcon(getNotificationIconId(mediaType)) .setLocalOnly(true); - StringBuilder contentText = - new StringBuilder(getNotificationContentText(mediaType, url)).append('.'); Intent tabIntent = Tab.createBringTabToFrontIntent(notificationId); if (tabIntent != null) { PendingIntent contentIntent = PendingIntent.getActivity( @@ -193,17 +195,40 @@ ContextUtils.getApplicationContext().getResources().getString( R.string.accessibility_stop), buildStopCapturePendingIntent(notificationId)); - } else { - contentText.append(" ").append( + } + } + + boolean hideUserData = isIncognito + && ChromeFeatureList.isEnabled( + ChromeFeatureList.HIDE_USER_DATA_FROM_INCOGNITO_NOTIFICATIONS); + + StringBuilder descriptionText = + new StringBuilder(getNotificationContentText(mediaType, url, hideUserData)) + .append('.'); + + String contentText; + if (hideUserData) { + builder.setSubText(ContextUtils.getApplicationContext().getResources().getString( + R.string.notification_incognito_tab)); + builder.setContentTitle(descriptionText.toString()); + contentText = ContextUtils.getApplicationContext().getResources().getString( + R.string.media_notification_link_text_incognito); + } else { + if (tabIntent == null) { + descriptionText.append(" ").append(url); + } else if (mediaType != MEDIATYPE_SCREEN_CAPTURE) { + descriptionText.append(" ").append( ContextUtils.getApplicationContext().getResources().getString( R.string.media_notification_link_text, url)); } - } else { - contentText.append(" ").append(url); - } - builder.setContentText(contentText.toString()); - Notification notification = builder.buildWithBigTextStyle(contentText.toString()); + builder.setContentTitle( + ContextUtils.getApplicationContext().getString(R.string.app_name)); + contentText = descriptionText.toString(); + } + builder.setContentText(contentText); + + Notification notification = builder.buildWithBigTextStyle(contentText); mNotificationManager.notify(NOTIFICATION_NAMESPACE, notificationId, notification); mNotifications.put(notificationId, mediaType); updateSharedPreferencesEntry(notificationId, false); @@ -217,19 +242,27 @@ * @param url Url of the current webrtc call. * @return A string builder initialized to the contents of the specified string. */ - private String getNotificationContentText(int mediaType, String url) { + private String getNotificationContentText(int mediaType, String url, boolean hideUserData) { if (mediaType == MEDIATYPE_SCREEN_CAPTURE) { - return ContextUtils.getApplicationContext().getResources().getString( - R.string.screen_capture_notification_text, url); + return ContextUtils.getApplicationContext().getResources().getString(hideUserData + ? R.string.screen_capture_incognito_notification_text + : R.string.screen_capture_notification_text, + url); } int notificationContentTextId = 0; if (mediaType == MEDIATYPE_AUDIO_AND_VIDEO) { - notificationContentTextId = R.string.video_audio_call_notification_text_2; + notificationContentTextId = hideUserData + ? R.string.video_audio_call_incognito_notification_text_2 + : R.string.video_audio_call_notification_text_2; } else if (mediaType == MEDIATYPE_VIDEO_ONLY) { - notificationContentTextId = R.string.video_call_notification_text_2; + notificationContentTextId = hideUserData + ? R.string.video_call_incognito_notification_text_2 + : R.string.video_call_notification_text_2; } else if (mediaType == MEDIATYPE_AUDIO_ONLY) { - notificationContentTextId = R.string.audio_call_notification_text_2; + notificationContentTextId = hideUserData + ? R.string.audio_call_incognito_notification_text_2 + : R.string.audio_call_notification_text_2; } return ContextUtils.getApplicationContext().getResources().getString( @@ -347,6 +380,10 @@ } intent.putExtra(NOTIFICATION_MEDIA_URL_EXTRA, baseUrl); intent.putExtra(NOTIFICATION_MEDIA_TYPE_EXTRA, mediaType); + if (TabWindowManager.getInstance().getTabById(tabId) != null) { + intent.putExtra(NOTIFICATION_MEDIA_IS_INCOGNITO, + TabWindowManager.getInstance().getTabById(tabId).isIncognito()); + } context.startService(intent); }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ntp/IncognitoNewTabPageViewMD.java b/chrome/android/java/src/org/chromium/chrome/browser/ntp/IncognitoNewTabPageViewMD.java index abd3de3..dcc72bb6 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/ntp/IncognitoNewTabPageViewMD.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/ntp/IncognitoNewTabPageViewMD.java
@@ -7,6 +7,7 @@ import static org.chromium.chrome.browser.util.ViewUtils.dpToPx; import android.content.Context; +import android.content.res.Configuration; import android.graphics.Canvas; import android.graphics.Paint; import android.support.annotation.IdRes; @@ -17,7 +18,6 @@ import android.text.style.BulletSpan; import android.text.style.ForegroundColorSpan; import android.util.AttributeSet; -import android.util.DisplayMetrics; import android.view.Gravity; import android.view.View; import android.widget.ImageView; @@ -35,7 +35,6 @@ */ public class IncognitoNewTabPageViewMD extends IncognitoNewTabPageView { private final Context mContext; - private final DisplayMetrics mMetrics; private int mWidthDp; private int mHeightDp; @@ -68,21 +67,15 @@ public IncognitoNewTabPageViewMD(Context context, AttributeSet attrs) { super(context, attrs); mContext = context; - mMetrics = mContext.getResources().getDisplayMetrics(); - } - - private int pxToDp(int px) { - return (int) Math.ceil(px / mMetrics.density); - } - - private int spToPx(int sp) { - return (int) Math.ceil(sp * mMetrics.scaledDensity); } @Override protected void onFinishInflate() { super.onFinishInflate(); + mWidthDp = mContext.getResources().getConfiguration().screenWidthDp; + mHeightDp = mContext.getResources().getConfiguration().screenHeightDp; + populateBulletpoints(R.id.new_tab_incognito_features, R.string.new_tab_otr_not_saved); populateBulletpoints(R.id.new_tab_incognito_warning, R.string.new_tab_otr_visible); @@ -95,21 +88,28 @@ (TextView) findViewById(R.id.new_tab_incognito_warning), mLearnMore}; mBulletpointsContainer = (LinearLayout) findViewById(R.id.new_tab_incognito_bulletpoints_container); + + adjustView(); + } + + private void adjustView() { + adjustIcon(); + adjustLayout(); + adjustLearnMore(); } @Override - protected void onLayout(boolean changed, int left, int top, int right, int bottom) { - super.onLayout(changed, left, top, right, bottom); - - if (changed) { - mWidthDp = pxToDp(getMeasuredWidth()); - mHeightDp = pxToDp(getMeasuredHeight()); - - adjustTypography(); - adjustIcon(); - adjustLayout(); - adjustLearnMore(); + public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + // View#onConfigurationChanged() doesn't get called when resizing this view in + // multi-window mode, so #onMeasure() is used instead. + Configuration config = getContext().getResources().getConfiguration(); + if (mWidthDp != config.screenWidthDp || mHeightDp != config.screenHeightDp) { + mWidthDp = config.screenWidthDp; + mHeightDp = config.screenHeightDp; + adjustView(); } + + super.onMeasure(widthMeasureSpec, heightMeasureSpec); } /** @@ -152,25 +152,6 @@ new SpanApplier.SpanInfo("<li3>", "</li3>", new IncognitoBulletSpan()))); } - /** Adjusts the font settings. */ - private void adjustTypography() { - if (mWidthDp <= 240 || mHeightDp <= 320) { - // Small text on small screens. - mHeader.setTextSize(20 /* sp */); - mHeader.setLineSpacing(spToPx(4) /* add */, 1 /* mult */); // 20sp + 4sp = 24sp - - for (TextView paragraph : mParagraphs) paragraph.setTextSize(12 /* sp */); - } else { - // Large text on large screens. - mHeader.setTextSize(24 /* sp */); - mHeader.setLineSpacing(spToPx(8) /* add */, 1 /* mult */); // 24sp + 8sp = 32sp - - for (TextView paragraph : mParagraphs) paragraph.setTextSize(14 /* sp */); - } - - // Paragraph line spacing is constant +6sp, defined in R.layout.new_tab_page_incognito_md. - } - /** Adjusts the paddings, margins, and the orientation of bulletpoints. */ private void adjustLayout() { int paddingHorizontalDp; @@ -187,8 +168,6 @@ mContainer.setGravity(Gravity.START); // Decide the bulletpoints orientation. - // TODO (thildebr): This is never set to anything but false, check if we can remove - // related code. bulletpointsArrangedHorizontally = false; // The subtitle is sized automatically, but not wider than CONTENT_WIDTH_DP. @@ -212,16 +191,9 @@ mContainer.setGravity(Gravity.CENTER_HORIZONTAL); // Decide the bulletpoints orientation. - int totalBulletpointsWidthDp = pxToDp(mBulletpointsContainer.getChildAt(0).getWidth()) - + pxToDp(mBulletpointsContainer.getChildAt(1).getWidth()) - + BULLETPOINTS_HORIZONTAL_SPACING_DP; - bulletpointsArrangedHorizontally = totalBulletpointsWidthDp <= CONTENT_WIDTH_DP; + bulletpointsArrangedHorizontally = true; - // The subtitle width is equal to the two sets of bulletpoints if they are arranged - // horizontally. If not, use the default CONTENT_WIDTH_DP. - int contentWidthPx = bulletpointsArrangedHorizontally - ? dpToPx(mContext, totalBulletpointsWidthDp) - : dpToPx(mContext, CONTENT_WIDTH_DP); + int contentWidthPx = dpToPx(mContext, CONTENT_WIDTH_DP); mSubtitle.setLayoutParams(new LinearLayout.LayoutParams( contentWidthPx, LinearLayout.LayoutParams.WRAP_CONTENT)); mBulletpointsContainer.setLayoutParams(new LinearLayout.LayoutParams(
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ntp/NewTabPage.java b/chrome/android/java/src/org/chromium/chrome/browser/ntp/NewTabPage.java index 7e5042b7..bf8c4536 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/ntp/NewTabPage.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/ntp/NewTabPage.java
@@ -15,6 +15,7 @@ import android.text.TextUtils; import android.view.LayoutInflater; import android.view.View; +import android.view.ViewGroup; import org.chromium.base.ApiCompatibilityUtils; import org.chromium.base.DiscardableReferencePool; @@ -54,10 +55,12 @@ import org.chromium.chrome.browser.tabmodel.TabModel.TabSelectionType; import org.chromium.chrome.browser.tabmodel.TabModelSelector; import org.chromium.chrome.browser.util.ColorUtils; +import org.chromium.chrome.browser.util.FeatureUtilities; import org.chromium.chrome.browser.util.UrlUtilities; import org.chromium.chrome.browser.vr.VrModuleProvider; import org.chromium.content_public.browser.NavigationController; import org.chromium.content_public.browser.NavigationEntry; +import org.chromium.content_public.common.BrowserControlsState; import org.chromium.net.NetworkChangeNotifier; import org.chromium.ui.mojom.WindowOpenDisposition; @@ -312,6 +315,11 @@ public void onPageLoadStarted(Tab tab, String url) { saveLastScrollPosition(); } + + @Override + public void onBrowserControlsConstraintsUpdated(Tab tab, int constraints) { + updateMargins(constraints); + } }; mTab.addObserver(mTabObserver); updateSearchProviderHasLogo(); @@ -368,6 +376,28 @@ index, NAVIGATION_ENTRY_SCROLL_POSITION_KEY, Integer.toString(scrollPosition)); } + /** Update the margins for the content when browser controls constraints are changed. */ + protected void updateMargins(@BrowserControlsState int constraints) { + // TODO(mdjones): can this be merged with BasicNativePage's updateMargins? + + View view = getView(); + ViewGroup.MarginLayoutParams layoutParams = + ((ViewGroup.MarginLayoutParams) view.getLayoutParams()); + if (layoutParams == null) { + // We could be updating the margin before the root view is attached to window. + layoutParams = new ViewGroup.MarginLayoutParams( + ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT); + view.setLayoutParams(layoutParams); + } + + int bottomMargin = 0; + if (FeatureUtilities.isBottomToolbarEnabled() + && constraints != BrowserControlsState.HIDDEN) { + bottomMargin = mTab.getActivity().getFullscreenManager().getBottomControlsHeight(); + } + layoutParams.bottomMargin = bottomMargin; + } + /** @return The view container for the new tab page. */ @VisibleForTesting public NewTabPageView getNewTabPageView() {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ntp/NewTabPageView.java b/chrome/android/java/src/org/chromium/chrome/browser/ntp/NewTabPageView.java index 884fa69..230416a3a 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/ntp/NewTabPageView.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/ntp/NewTabPageView.java
@@ -28,7 +28,6 @@ import org.chromium.chrome.browser.suggestions.SuggestionsUiDelegate; import org.chromium.chrome.browser.suggestions.TileGroup; import org.chromium.chrome.browser.tab.Tab; -import org.chromium.chrome.browser.util.FeatureUtilities; import org.chromium.chrome.browser.util.ViewUtils; import org.chromium.chrome.browser.widget.displaystyle.UiConfig; @@ -277,11 +276,6 @@ // immediately attached to the window if the RecyclerView is scrolled when the NTP // is refocused. if (mManager.isLocationBarShownInNTP()) mNewTabPageLayout.updateSearchBoxOnScroll(); - - if (FeatureUtilities.isBottomToolbarEnabled()) { - ((MarginLayoutParams) getLayoutParams()).bottomMargin = - getResources().getDimensionPixelSize(R.dimen.bottom_toolbar_height); - } } /**
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/photo_picker/PhotoPickerDialog.java b/chrome/android/java/src/org/chromium/chrome/browser/photo_picker/PhotoPickerDialog.java index df0b902..d86fa2c3 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/photo_picker/PhotoPickerDialog.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/photo_picker/PhotoPickerDialog.java
@@ -55,9 +55,10 @@ // PhotoPickerListener: @Override - public void onPhotoPickerUserAction(Action action, String[] photos) { + public void onPhotoPickerUserAction(@PhotoPickerAction int action, String[] photos) { mExternalIntentSelected = false; - if (action == Action.LAUNCH_GALLERY || action == Action.LAUNCH_CAMERA) { + if (action == PhotoPickerAction.LAUNCH_GALLERY + || action == PhotoPickerAction.LAUNCH_CAMERA) { mExternalIntentSelected = true; }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/photo_picker/PickerCategoryView.java b/chrome/android/java/src/org/chromium/chrome/browser/photo_picker/PickerCategoryView.java index 2bc0c5d..6df7d7f 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/photo_picker/PickerCategoryView.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/photo_picker/PickerCategoryView.java
@@ -216,7 +216,7 @@ mDialog.setOnCancelListener(new DialogInterface.OnCancelListener() { @Override public void onCancel(DialogInterface dialog) { - executeAction(PhotoPickerListener.Action.CANCEL, null, ACTION_CANCEL); + executeAction(PhotoPickerListener.PhotoPickerAction.CANCEL, null, ACTION_CANCEL); } }); } @@ -264,7 +264,7 @@ if (view.getId() == R.id.done) { notifyPhotosSelected(); } else { - executeAction(PhotoPickerListener.Action.CANCEL, null, ACTION_CANCEL); + executeAction(PhotoPickerListener.PhotoPickerAction.CANCEL, null, ACTION_CANCEL); } } @@ -320,14 +320,14 @@ * Notifies the listener that the user selected to launch the gallery. */ public void showGallery() { - executeAction(PhotoPickerListener.Action.LAUNCH_GALLERY, null, ACTION_BROWSE); + executeAction(PhotoPickerListener.PhotoPickerAction.LAUNCH_GALLERY, null, ACTION_BROWSE); } /** * Notifies the listener that the user selected to launch the camera intent. */ public void showCamera() { - executeAction(PhotoPickerListener.Action.LAUNCH_CAMERA, null, ACTION_NEW_PHOTO); + executeAction(PhotoPickerListener.PhotoPickerAction.LAUNCH_CAMERA, null, ACTION_NEW_PHOTO); } /** @@ -381,7 +381,8 @@ photos[i++] = bitmap.getFilePath(); } - executeAction(PhotoPickerListener.Action.PHOTOS_SELECTED, photos, ACTION_PHOTO_PICKED); + executeAction( + PhotoPickerListener.PhotoPickerAction.PHOTOS_SELECTED, photos, ACTION_PHOTO_PICKED); } /** @@ -427,7 +428,8 @@ * @param photos The photos that were selected (if any). * @param umaId The UMA value to record with the action. */ - private void executeAction(PhotoPickerListener.Action action, String[] photos, int umaId) { + private void executeAction( + @PhotoPickerListener.PhotoPickerAction int action, String[] photos, int umaId) { mListener.onPhotoPickerUserAction(action, photos); mDialog.dismiss(); UiUtils.onPhotoPickerDismissed();
diff --git a/chrome/android/java/strings/android_chrome_strings.grd b/chrome/android/java/strings/android_chrome_strings.grd index 37a5b95..c0ead26 100644 --- a/chrome/android/java/strings/android_chrome_strings.grd +++ b/chrome/android/java/strings/android_chrome_strings.grd
@@ -2857,15 +2857,15 @@ <message name="IDS_NTP_EXPLORE_SITES_MORE" desc="Text on a button leading to a complete view of all categories for all popular websites"> More categories </message> + <message name="IDS_EXPLORE_SITES_DEFAULT_CATEGORY_NEWS" desc="The caption for a button that when clicked opens a UI in this tab that shows a list of websites with content related to news. [CHAR-LIMIT=12]"> + News + </message> <message name="IDS_EXPLORE_SITES_DEFAULT_CATEGORY_SPORTS" desc="The caption for a button that when clicked opens a UI in this tab that shows a list of websites with content related to sports. For example, soccer, cricket, football, running [CHAR-LIMIT=12]"> Sports </message> <message name="IDS_EXPLORE_SITES_DEFAULT_CATEGORY_SHOPPING" desc="The caption for a button that when clicked opens a UI in this tab that shows a list of websites with content related to shopping. [CHAR-LIMIT=12]"> Shopping </message> - <message name="IDS_EXPLORE_SITES_DEFAULT_CATEGORY_COOKING" desc="The caption for a button that when clicked opens a UI in this tab that shows a list of websites with content related to food and cooking. [CHAR-LIMIT=12]"> - Cooking - </message> <message name="IDS_EXPLORE_SITES_LOADING_FROM_NET" desc="Caption for an indeterminate loading spinner indicating that we are loading the data from the internet"> Finding the best from the web. </message> @@ -3314,6 +3314,9 @@ <message name="IDS_MEDIA_NOTIFICATION_LINK_TEXT" desc="Url of the current tab. The notification will display this text for the user to identify the tab to return to."> Touch to return to <ph name="URL_OF_THE_CURRENT_TAB">%1$s<ex>https://apprtc.appspot.com</ex></ph> </message> + <message name="IDS_MEDIA_NOTIFICATION_LINK_TEXT_INCOGNITO" desc="The notification will display this text for the user to return to the incognito tab which has created the notification."> + Tap to go to site + </message> <message name="IDS_MEDIA_NOTIFICATION_INCOGNITO" desc="Text used as a placeholder for media notifications content, when notification is shown from incognito tab."> A site is playing media </message> @@ -3323,6 +3326,9 @@ <message name="IDS_SCREEN_CAPTURE_NOTIFICATION_TEXT" desc="Text to be shown as a notification when screen capture is in progress."> <ph name="URL_OF_THE_CURRENT_TAB">%1$s<ex>https://apprtc.appspot.com</ex></ph> is sharing your screen </message> + <message name="IDS_SCREEN_CAPTURE_INCOGNITO_NOTIFICATION_TEXT" desc="Text to be shown as a notification when screen capture is in progress in incognito mode."> + A site is sharing your screen + </message> <message name="IDS_NEW_TAB_INCOGNITO_HEADER" desc="Header shown when a user opens an incognito tab explaining incognito mode"> You’ve gone incognito. </message>
diff --git a/chrome/android/java/strings/android_chrome_strings_grd/IDS_EXPLORE_SITES_DEFAULT_CATEGORY_COOKING.png.sha1 b/chrome/android/java/strings/android_chrome_strings_grd/IDS_EXPLORE_SITES_DEFAULT_CATEGORY_COOKING.png.sha1 deleted file mode 100644 index 3650503..0000000 --- a/chrome/android/java/strings/android_chrome_strings_grd/IDS_EXPLORE_SITES_DEFAULT_CATEGORY_COOKING.png.sha1 +++ /dev/null
@@ -1 +0,0 @@ -3dbcd93f6154cce922e8285a06d6d7eccbf42e71 \ No newline at end of file
diff --git a/chrome/android/java/strings/android_chrome_strings_grd/IDS_EXPLORE_SITES_DEFAULT_CATEGORY_NEWS.png.sha1 b/chrome/android/java/strings/android_chrome_strings_grd/IDS_EXPLORE_SITES_DEFAULT_CATEGORY_NEWS.png.sha1 new file mode 100644 index 0000000..daa7908 --- /dev/null +++ b/chrome/android/java/strings/android_chrome_strings_grd/IDS_EXPLORE_SITES_DEFAULT_CATEGORY_NEWS.png.sha1
@@ -0,0 +1 @@ +549c3db2e92edce8c13b3da616116daf893fc7e7 \ No newline at end of file
diff --git a/chrome/android/java_sources.gni b/chrome/android/java_sources.gni index c5bd8060..36bcc41 100644 --- a/chrome/android/java_sources.gni +++ b/chrome/android/java_sources.gni
@@ -109,6 +109,7 @@ "java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/KeyboardAccessoryView.java", "java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/KeyboardAccessoryViewBinder.java", "java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/ManualFillingCoordinator.java", + "java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/KeyboardExtensionSizeManager.java", "java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/ManualFillingMediator.java", "java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/PasswordAccessoryBridge.java", "java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/PasswordAccessorySheetCoordinator.java",
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/autofill/AutofillPopupTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/autofill/AutofillPopupTest.java index 99a7fdd..9593417 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/autofill/AutofillPopupTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/autofill/AutofillPopupTest.java
@@ -20,10 +20,12 @@ import org.chromium.base.test.util.RetryOnFailure; import org.chromium.base.test.util.UrlUtils; import org.chromium.chrome.browser.ChromeActivity; +import org.chromium.chrome.browser.ChromeFeatureList; import org.chromium.chrome.browser.ChromeSwitches; import org.chromium.chrome.browser.autofill.PersonalDataManager.AutofillProfile; import org.chromium.chrome.test.ChromeActivityTestRule; import org.chromium.chrome.test.ChromeJUnit4ClassRunner; +import org.chromium.chrome.test.util.browser.Features; import org.chromium.content_public.browser.ImeAdapter; import org.chromium.content_public.browser.WebContents; import org.chromium.content_public.browser.test.util.Criteria; @@ -141,6 +143,9 @@ AutofillLogger.setLoggerForTesting( logEntry -> mAutofillLoggedEntries.add(logEntry) ); + // TODO(crbug.com/894428) - fix this suite to use the embedded test server instead of + // data urls. + Features.getInstance().enable(ChromeFeatureList.AUTOFILL_ALLOW_NON_HTTP_ACTIVATION); } private void loadAndFillForm(final String formDataUrl, final String inputText)
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/autofill/AutofillPopupWithKeyboardTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/autofill/AutofillPopupWithKeyboardTest.java index 32258d8..cad2681 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/autofill/AutofillPopupWithKeyboardTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/autofill/AutofillPopupWithKeyboardTest.java
@@ -8,6 +8,7 @@ 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; @@ -18,10 +19,12 @@ import org.chromium.base.test.util.RetryOnFailure; import org.chromium.base.test.util.UrlUtils; import org.chromium.chrome.browser.ChromeActivity; +import org.chromium.chrome.browser.ChromeFeatureList; import org.chromium.chrome.browser.ChromeSwitches; import org.chromium.chrome.browser.autofill.PersonalDataManager.AutofillProfile; import org.chromium.chrome.test.ChromeActivityTestRule; import org.chromium.chrome.test.ChromeJUnit4ClassRunner; +import org.chromium.chrome.test.util.browser.Features; import org.chromium.content_public.browser.WebContents; import org.chromium.content_public.browser.test.util.Criteria; import org.chromium.content_public.browser.test.util.CriteriaHelper; @@ -43,6 +46,13 @@ public ChromeActivityTestRule<ChromeActivity> mActivityTestRule = new ChromeActivityTestRule<>(ChromeActivity.class); + @Before + public void setUp() throws Exception { + // TODO(crbug.com/894428) - fix this suite to use the embedded test server instead of + // data urls. + Features.getInstance().enable(ChromeFeatureList.AUTOFILL_ALLOW_NON_HTTP_ACTIVATION); + } + /** * Test that showing autofill popup and keyboard will not hide the autofill popup. */
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/autofill/keyboard_accessory/ManualFillingIntegrationTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/autofill/keyboard_accessory/ManualFillingIntegrationTest.java index a06f34a..07a87afc 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/autofill/keyboard_accessory/ManualFillingIntegrationTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/autofill/keyboard_accessory/ManualFillingIntegrationTest.java
@@ -25,6 +25,7 @@ import android.view.ViewGroup; import org.junit.After; +import org.junit.Before; import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; @@ -65,6 +66,13 @@ private final ManualFillingTestHelper mHelper = new ManualFillingTestHelper(mActivityTestRule); + @Before + public void setUp() throws Exception { + // TODO(crbug.com/894428) - fix this suite to use the embedded test server instead of + // data urls. + Features.getInstance().enable(ChromeFeatureList.AUTOFILL_ALLOW_NON_HTTP_ACTIVATION); + } + @After public void tearDown() { mHelper.clear(); @@ -214,9 +222,11 @@ "", "80666", "", "Disneyland", "1", "a.turing@enigma.com", "DE")); mHelper.createTestTab(); - // Focus the field to bring up the accessory. - mHelper.clickEmailField(); + // Focus the field to bring up the autofill popup. We force a accessory here because the + // autofill popup doesn't trigger on password fields. + mHelper.clickEmailField(true); mHelper.waitForKeyboard(); + DropdownPopupWindowInterface popup = mHelper.waitForAutofillPopup("a.tu"); assertThat(popup.isShowing(), is(true)); @@ -231,6 +241,24 @@ @Test @SmallTest + @Features.DisableFeatures({ChromeFeatureList.AUTOFILL_KEYBOARD_ACCESSORY}) + public void testSelectingNonPasswordInputDismissesAccessory() + throws InterruptedException, TimeoutException, ExecutionException { + mHelper.loadTestPage(false); + mHelper.createTestTab(); + + // Focus the password field to bring up the accessory. + mHelper.clickPasswordField(); + mHelper.waitForKeyboard(); + whenDisplayed(withId(R.id.tabs)); + + // Clicking the email field hides the accessory again. + mHelper.clickEmailField(false); + mHelper.waitToBeHidden(withId(R.id.keyboard_accessory)); + } + + @Test + @SmallTest @Restriction(UiRestriction.RESTRICTION_TYPE_PHONE) public void testInvokingTabSwitcherHidesAccessory() throws InterruptedException, TimeoutException { @@ -284,7 +312,7 @@ () -> { mActivityTestRule.getActivity().onResumeWithNative(); }); // Clicking the field should bring the accessory back up. - mHelper.clickEmailField(); + mHelper.clickPasswordField(); mHelper.waitForKeyboard(); // Click the tab to show the sheet and hide the keyboard.
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/autofill/keyboard_accessory/ManualFillingTestHelper.java b/chrome/android/javatests/src/org/chromium/chrome/browser/autofill/keyboard_accessory/ManualFillingTestHelper.java index 903cc48..b2b1ec7 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/autofill/keyboard_accessory/ManualFillingTestHelper.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/autofill/keyboard_accessory/ManualFillingTestHelper.java
@@ -24,7 +24,6 @@ import android.support.test.espresso.UiController; import android.support.test.espresso.ViewAction; import android.support.test.espresso.ViewInteraction; -import android.support.v7.content.res.AppCompatResources; import android.view.View; import android.view.ViewGroup; @@ -168,11 +167,18 @@ public void clickPasswordField() throws TimeoutException, InterruptedException { DOMUtils.clickNode(mWebContentsRef.get(), "password"); + requestShowKeyboardAccessory(); mKeyboard.showKeyboard(null); } - public void clickEmailField() throws TimeoutException, InterruptedException { + public void clickEmailField(boolean forceAccessory) + throws TimeoutException, InterruptedException { DOMUtils.clickNode(mWebContentsRef.get(), "email"); + if (forceAccessory) { + requestShowKeyboardAccessory(); + } else { + requestHideKeyboardAccessory(); + } mKeyboard.showKeyboard(null); } @@ -220,15 +226,17 @@ } /** - * Creates and adds an empty tab without listener to keyboard accessory and sheet. + * Creates and adds a password tab to keyboard accessory and sheet. */ public void createTestTab() { - mActivityTestRule.getActivity().getManualFillingController().getMediatorForTesting().addTab( - new KeyboardAccessoryData.Tab( - AppCompatResources.getDrawable(InstrumentationRegistry.getContext(), - android.R.drawable.ic_lock_lock), - "TestTabDescription", R.layout.empty_accessory_sheet, AccessoryTabType.ALL, - null)); + KeyboardAccessoryData.Provider<KeyboardAccessoryData.Item> provider = + new KeyboardAccessoryData.PropertyProvider<>(); + mActivityTestRule.getActivity().getManualFillingController().registerPasswordProvider( + provider); + provider.notifyObservers(new KeyboardAccessoryData.Item[] { + KeyboardAccessoryData.Item.createSuggestion("TestName", "", false, null, null), + KeyboardAccessoryData.Item.createSuggestion( + "TestPassword", "", false, (item) -> {}, null)}); } /** @@ -277,4 +285,30 @@ waitForView((ViewGroup) r, matcher, VIEW_INVISIBLE | VIEW_NULL | VIEW_GONE); }); } + + /** + * In order to make sure the keyboard accessory is only shown on appropriate fields, a request + * to show is usually sent from the native side. This method simulates that request. + */ + private void requestShowKeyboardAccessory() { + ThreadUtils.runOnUiThreadBlocking(() -> { + mActivityTestRule.getActivity() + .getManualFillingController() + .getMediatorForTesting() + .showWhenKeyboardIsVisible(); + }); + } + + /** + * In order to make sure the keyboard accessory is only shown on appropriate fields, a request + * from the native side can request to hide it. This method simulates that request. + */ + private void requestHideKeyboardAccessory() { + ThreadUtils.runOnUiThreadBlocking(() -> { + mActivityTestRule.getActivity() + .getManualFillingController() + .getMediatorForTesting() + .hide(); + }); + } }
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/autofill/keyboard_accessory/PasswordAccessoryIntegrationTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/autofill/keyboard_accessory/PasswordAccessoryIntegrationTest.java index 1fb4391..2f1cefd 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/autofill/keyboard_accessory/PasswordAccessoryIntegrationTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/autofill/keyboard_accessory/PasswordAccessoryIntegrationTest.java
@@ -32,6 +32,7 @@ import org.hamcrest.Matcher; import org.junit.After; import org.junit.Assert; +import org.junit.Before; import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; @@ -46,6 +47,7 @@ import org.chromium.chrome.browser.autofill.keyboard_accessory.KeyboardAccessoryData.Item; import org.chromium.chrome.test.ChromeJUnit4ClassRunner; import org.chromium.chrome.test.ChromeTabbedActivityTestRule; +import org.chromium.chrome.test.util.browser.Features; import org.chromium.chrome.test.util.browser.Features.DisableFeatures; import org.chromium.chrome.test.util.browser.Features.EnableFeatures; @@ -66,6 +68,13 @@ private final ManualFillingTestHelper mHelper = new ManualFillingTestHelper(mActivityTestRule); + @Before + public void setUp() throws Exception { + // TODO(crbug.com/894428) - fix this suite to use the embedded test server instead of + // data urls. + Features.getInstance().enable(ChromeFeatureList.AUTOFILL_ALLOW_NON_HTTP_ACTIVATION); + } + @After public void tearDown() { mHelper.clear();
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/contacts_picker/ContactsPickerDialogTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/contacts_picker/ContactsPickerDialogTest.java index c3090a6..ef7bf33 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/contacts_picker/ContactsPickerDialogTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/contacts_picker/ContactsPickerDialogTest.java
@@ -66,7 +66,7 @@ private SelectionDelegate<ContactDetails> mSelectionDelegate; // The last action recorded in the dialog (e.g. photo selected). - private ContactsPickerAction mLastActionRecorded; + private @ContactsPickerAction int mLastActionRecorded; // The final set of contacts picked by the dialog (json string). private String mLastSelectedContacts; @@ -101,7 +101,7 @@ // ContactsPickerDialog.ContactsPickerListener: @Override - public void onContactsPickerUserAction(ContactsPickerAction action, String contacts) { + public void onContactsPickerUserAction(@ContactsPickerAction int action, String contacts) { mLastActionRecorded = action; mLastSelectedContacts = contacts; onActionCallback.notifyCalled(); @@ -158,7 +158,7 @@ } private void clickDone() throws Exception { - mLastActionRecorded = null; + mLastActionRecorded = ContactsPickerAction.NUM_ENTRIES; ContactsPickerToolbar toolbar = (ContactsPickerToolbar) mDialog.findViewById(R.id.action_bar); @@ -170,7 +170,7 @@ } public void clickCancel() throws Exception { - mLastActionRecorded = null; + mLastActionRecorded = ContactsPickerAction.NUM_ENTRIES; PickerCategoryView categoryView = mDialog.getCategoryViewForTesting(); View cancel = new View(mActivityTestRule.getActivity()); @@ -181,8 +181,8 @@ } private void clickActionButton(final int expectedSelectionCount, - final ContactsPickerAction expectedAction) throws Exception { - mLastActionRecorded = null; + final @ContactsPickerAction int expectedAction) throws Exception { + mLastActionRecorded = ContactsPickerAction.NUM_ENTRIES; ContactsPickerToolbar toolbar = (ContactsPickerToolbar) mDialog.findViewById(R.id.action_bar);
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/DetachedResourceRequestTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/DetachedResourceRequestTest.java index 3a73720..76bca0e 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/DetachedResourceRequestTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/DetachedResourceRequestTest.java
@@ -7,7 +7,11 @@ import android.content.Context; import android.content.Intent; import android.net.Uri; +import android.os.Bundle; +import android.support.customtabs.CustomTabsCallback; +import android.support.customtabs.CustomTabsIntent; import android.support.customtabs.CustomTabsService; +import android.support.customtabs.CustomTabsSession; import android.support.customtabs.CustomTabsSessionToken; import android.support.test.InstrumentationRegistry; import android.support.test.filters.SmallTest; @@ -17,6 +21,7 @@ import org.junit.Before; import org.junit.Rule; import org.junit.Test; +import org.junit.rules.TestRule; import org.junit.runner.RunWith; import org.chromium.base.PathUtils; @@ -33,11 +38,13 @@ import org.chromium.chrome.browser.preferences.PrefServiceBridge; import org.chromium.chrome.browser.tab.Tab; import org.chromium.chrome.test.ChromeJUnit4ClassRunner; +import org.chromium.chrome.test.util.browser.Features; import org.chromium.chrome.test.util.browser.Features.EnableFeatures; import org.chromium.components.safe_browsing.SafeBrowsingApiBridge; import org.chromium.content_public.browser.WebContents; import org.chromium.content_public.browser.test.util.CriteriaHelper; import org.chromium.content_public.browser.test.util.JavaScriptUtils; +import org.chromium.net.NetError; import org.chromium.net.test.EmbeddedTestServer; import java.util.ArrayList; @@ -50,6 +57,8 @@ public class DetachedResourceRequestTest { @Rule public CustomTabActivityTestRule mCustomTabActivityTestRule = new CustomTabActivityTestRule(); + @Rule + public TestRule mProcessor = new Features.InstrumentationProcessor(); private CustomTabsConnection mConnection; private Context mContext; @@ -57,6 +66,7 @@ private static final String PRIVATE_DATA_DIRECTORY_SUFFIX = "chrome"; private static final Uri ORIGIN = Uri.parse("http://cats.google.com"); + private static final int NET_OK = 0; @Before public void setUp() throws Exception { @@ -78,7 +88,6 @@ @Test @SmallTest - @EnableFeatures(ChromeFeatureList.CCT_PARALLEL_REQUEST) public void testCanDoParallelRequest() throws Exception { CustomTabsSessionToken session = CustomTabsSessionToken.createMockSessionTokenForTesting(); Assert.assertTrue(mConnection.newSession(session)); @@ -126,7 +135,6 @@ @Test @SmallTest - @EnableFeatures(ChromeFeatureList.CCT_PARALLEL_REQUEST) public void testStartParallelRequestValidation() throws Exception { CustomTabsSessionToken session = prepareSession(); @@ -203,9 +211,8 @@ @Test @SmallTest - @EnableFeatures(ChromeFeatureList.CCT_PARALLEL_REQUEST) + @EnableFeatures(ChromeFeatureList.CCT_REPORT_PARALLEL_REQUEST_STATUS) public void testCanStartParallelRequest() throws Exception { - CustomTabsSessionToken session = prepareSession(); final CallbackHelper cb = new CallbackHelper(); setUpTestServerWithListener(new EmbeddedTestServer.ConnectionListener() { @Override @@ -213,18 +220,71 @@ cb.notifyCalled(); } }); - Uri url = Uri.parse(mServer.getURL("/echotitle")); + + DetachedResourceRequestCheckCallback customTabsCallback = + new DetachedResourceRequestCheckCallback( + url, CustomTabsConnection.ParallelRequestStatus.SUCCESS, NET_OK); + CustomTabsSessionToken session = prepareSession(ORIGIN, customTabsCallback); + ThreadUtils.runOnUiThread(() -> { Assert.assertEquals(CustomTabsConnection.ParallelRequestStatus.SUCCESS, mConnection.handleParallelRequest(session, prepareIntent(url, ORIGIN))); }); + customTabsCallback.waitForRequest(); cb.waitForCallback(0, 1); + customTabsCallback.waitForCompletion(); } @Test @SmallTest - @EnableFeatures(ChromeFeatureList.CCT_RESOURCE_PREFETCH) + @EnableFeatures(ChromeFeatureList.CCT_REPORT_PARALLEL_REQUEST_STATUS) + public void testParallelRequestFailureCallback() throws Exception { + Uri url = Uri.parse("http://request-url"); + int status = + CustomTabsConnection.ParallelRequestStatus.FAILURE_INVALID_REFERRER_FOR_SESSION; + DetachedResourceRequestCheckCallback customTabsCallback = + new DetachedResourceRequestCheckCallback(url, status, 0); + CustomTabsSessionToken session = prepareSession(ORIGIN, customTabsCallback); + + ThreadUtils.runOnUiThread(() -> { + Assert.assertEquals(status, + mConnection.handleParallelRequest( + session, prepareIntent(url, Uri.parse("http://not-the-right-origin")))); + }); + customTabsCallback.waitForRequest(); + } + + @Test + @SmallTest + @EnableFeatures(ChromeFeatureList.CCT_REPORT_PARALLEL_REQUEST_STATUS) + public void testParallelRequestCompletionFailureCallback() throws Exception { + final CallbackHelper cb = new CallbackHelper(); + setUpTestServerWithListener(new EmbeddedTestServer.ConnectionListener() { + @Override + public void readFromSocket(long socketId) { + cb.notifyCalled(); + } + }); + Uri url = Uri.parse(mServer.getURL("/close-socket")); + + DetachedResourceRequestCheckCallback customTabsCallback = + new DetachedResourceRequestCheckCallback(url, + CustomTabsConnection.ParallelRequestStatus.SUCCESS, + Math.abs(NetError.ERR_EMPTY_RESPONSE)); + CustomTabsSessionToken session = prepareSession(ORIGIN, customTabsCallback); + + ThreadUtils.runOnUiThread(() -> { + Assert.assertEquals(CustomTabsConnection.ParallelRequestStatus.SUCCESS, + mConnection.handleParallelRequest(session, prepareIntent(url, ORIGIN))); + }); + customTabsCallback.waitForRequest(); + cb.waitForCallback(0, 1); + customTabsCallback.waitForCompletion(); + } + + @Test + @SmallTest public void testCanStartResourcePrefetch() throws Exception { CustomTabsSessionToken session = prepareSession(); final CallbackHelper cb = new CallbackHelper(); @@ -249,15 +309,22 @@ @Test @SmallTest - @EnableFeatures(ChromeFeatureList.CCT_PARALLEL_REQUEST) + @EnableFeatures(ChromeFeatureList.CCT_REPORT_PARALLEL_REQUEST_STATUS) public void testCanSetCookie() throws Exception { - CustomTabsSessionToken session = prepareSession(); mServer = EmbeddedTestServer.createAndStartServer(mContext); final Uri url = Uri.parse(mServer.getURL("/set-cookie?acookie")); + + DetachedResourceRequestCheckCallback customTabsCallback = + new DetachedResourceRequestCheckCallback( + url, CustomTabsConnection.ParallelRequestStatus.SUCCESS, NET_OK); + CustomTabsSessionToken session = prepareSession(ORIGIN, customTabsCallback); + ThreadUtils.runOnUiThreadBlocking(() -> { Assert.assertEquals(CustomTabsConnection.ParallelRequestStatus.SUCCESS, mConnection.handleParallelRequest(session, prepareIntent(url, ORIGIN))); }); + customTabsCallback.waitForRequest(); + customTabsCallback.waitForCompletion(); String echoUrl = mServer.getURL("/echoheader?Cookie"); Intent intent = CustomTabsTestUtils.createMinimalCustomTabIntent(mContext, echoUrl); @@ -275,7 +342,6 @@ */ @Test @SmallTest - @EnableFeatures(ChromeFeatureList.CCT_PARALLEL_REQUEST) public void testSafeBrowsingMainResource() throws Exception { SafeBrowsingApiBridge.setSafeBrowsingHandlerType( new MockSafeBrowsingApiHandler().getClass()); @@ -309,7 +375,6 @@ */ @Test @SmallTest - @EnableFeatures(ChromeFeatureList.CCT_PARALLEL_REQUEST) public void testSafeBrowsingSubresource() throws Exception { SafeBrowsingApiBridge.setSafeBrowsingHandlerType( new MockSafeBrowsingApiHandler().getClass()); @@ -337,7 +402,6 @@ @Test @SmallTest - @EnableFeatures(ChromeFeatureList.CCT_PARALLEL_REQUEST) public void testCanBlockThirdPartyCookies() throws Exception { CustomTabsSessionToken session = prepareSession(); mServer = EmbeddedTestServer.createAndStartServer(mContext); @@ -364,7 +428,6 @@ @Test @SmallTest - @EnableFeatures(ChromeFeatureList.CCT_PARALLEL_REQUEST) public void testThirdPartyCookieBlockingAllowsFirstParty() throws Exception { CustomTabsTestUtils.warmUpAndWait(); mServer = EmbeddedTestServer.createAndStartServer(mContext); @@ -393,22 +456,28 @@ } private CustomTabsSessionToken prepareSession() throws Exception { - return prepareSession(ORIGIN); + return prepareSession(ORIGIN, null); } private CustomTabsSessionToken prepareSession(Uri origin) throws Exception { - final CustomTabsSessionToken session = - CustomTabsSessionToken.createMockSessionTokenForTesting(); - Assert.assertTrue(mConnection.newSession(session)); - mConnection.mClientManager.setAllowParallelRequestForSession(session, true); - mConnection.mClientManager.setAllowResourcePrefetchForSession(session, true); + return prepareSession(origin, null); + } + + private CustomTabsSessionToken prepareSession(Uri origin, CustomTabsCallback callback) + throws Exception { + CustomTabsSession session = CustomTabsTestUtils.bindWithCallback(callback); + Intent intent = (new CustomTabsIntent.Builder(session)).build().intent; + CustomTabsSessionToken token = CustomTabsSessionToken.getSessionTokenFromIntent(intent); + Assert.assertTrue(mConnection.newSession(token)); + mConnection.mClientManager.setAllowParallelRequestForSession(token, true); + mConnection.mClientManager.setAllowResourcePrefetchForSession(token, true); CustomTabsTestUtils.warmUpAndWait(); ThreadUtils.runOnUiThreadBlocking(() -> { OriginVerifier.addVerifiedOriginForPackage(mContext.getPackageName(), new Origin(origin.toString()), CustomTabsService.RELATION_USE_AS_ORIGIN); - Assert.assertTrue(mConnection.canDoParallelRequest(session, origin)); + Assert.assertTrue(mConnection.canDoParallelRequest(token, origin)); }); - return session; + return token; } private void setUpTestServerWithListener(EmbeddedTestServer.ConnectionListener listener) @@ -456,4 +525,45 @@ intent.putExtra(CustomTabsConnection.PARALLEL_REQUEST_REFERRER_KEY, referrer); return intent; } + + private static class DetachedResourceRequestCheckCallback extends CustomTabsCallback { + private final Uri mExpectedUrl; + private final int mExpectedRequestStatus; + private final int mExpectedFinalStatus; + private final CallbackHelper mRequestedWaiter = new CallbackHelper(); + private final CallbackHelper mCompletionWaiter = new CallbackHelper(); + + public DetachedResourceRequestCheckCallback( + Uri expectedUrl, int expectedRequestStatus, int expectedFinalStatus) { + super(); + mExpectedUrl = expectedUrl; + mExpectedRequestStatus = expectedRequestStatus; + mExpectedFinalStatus = expectedFinalStatus; + } + + @Override + public void extraCallback(String callbackName, Bundle args) { + if (CustomTabsConnection.ON_DETACHED_REQUEST_REQUESTED.equals(callbackName)) { + Uri url = args.getParcelable("url"); + int status = args.getInt("status"); + Assert.assertEquals(mExpectedUrl, url); + Assert.assertEquals(mExpectedRequestStatus, status); + mRequestedWaiter.notifyCalled(); + } else if (CustomTabsConnection.ON_DETACHED_REQUEST_COMPLETED.equals(callbackName)) { + Uri url = args.getParcelable("url"); + int status = args.getInt("net_error"); + Assert.assertEquals(mExpectedUrl, url); + Assert.assertEquals(mExpectedFinalStatus, status); + mCompletionWaiter.notifyCalled(); + } + } + + public void waitForRequest() throws InterruptedException, TimeoutException { + mRequestedWaiter.waitForCallback(0, 1); + } + + public void waitForCompletion() throws InterruptedException, TimeoutException { + mCompletionWaiter.waitForCallback(0, 1); + } + } }
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/download/DownloadMediaParserTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/download/DownloadMediaParserTest.java index b39060d..addf0d169 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/download/DownloadMediaParserTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/download/DownloadMediaParserTest.java
@@ -15,7 +15,6 @@ import org.chromium.base.ThreadUtils; import org.chromium.base.test.BaseJUnit4ClassRunner; import org.chromium.base.test.util.Feature; -import org.chromium.base.test.util.RetryOnFailure; import org.chromium.base.test.util.UrlUtils; import org.chromium.chrome.browser.test.ChromeBrowserTestRule; import org.chromium.content_public.browser.test.util.Criteria; @@ -82,7 +81,6 @@ @Test @LargeTest @Feature({"Download"}) - @RetryOnFailure /** * Verify that the metadata from audio file can be retrieved correctly. * @throws InterruptedException @@ -96,7 +94,6 @@ @Test @LargeTest @Feature({"Download"}) - @RetryOnFailure /** * Verify metadata and thumbnail can be retrieved correctly from h264 video file. * @throws InterruptedException @@ -114,7 +111,6 @@ @Test @LargeTest @Feature({"Download"}) - @RetryOnFailure /** * Verify metadata and thumbnail can be retrieved correctly from vp8 video file. * @throws InterruptedException @@ -132,7 +128,6 @@ @Test @LargeTest @Feature({"Download"}) - @RetryOnFailure /** * Verify metadata and thumbnail can be retrieved correctly from vp8 video file with alpha * plane. @@ -147,4 +142,17 @@ Assert.assertTrue( "Failed to retrieve thumbnail.", result.mediaData.thumbnail.getHeight() > 0); } + + @Test + @LargeTest + @Feature({"Download"}) + /** + * Verify graceful failure on parsing invalid video file. + * @throws InterruptedException + */ + public void testParseInvalidVideoFile() throws Exception { + File invalidFile = File.createTempFile("test", "webm"); + MediaParserResult result = parseMediaFile(invalidFile.getAbsolutePath(), "video/webm"); + Assert.assertTrue("Should fail to parse invalid video.", result.mediaData == null); + } }
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/photo_picker/PhotoPickerDialogTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/photo_picker/PhotoPickerDialogTest.java index ab05ac3..76f8377 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/photo_picker/PhotoPickerDialogTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/photo_picker/PhotoPickerDialogTest.java
@@ -64,7 +64,7 @@ private SelectionDelegate<PickerBitmap> mSelectionDelegate; // The last action recorded in the dialog (e.g. photo selected). - private Action mLastActionRecorded; + private @PhotoPickerAction int mLastActionRecorded; // The final set of photos picked by the dialog. Can be an empty array, if // nothing was selected. @@ -100,7 +100,7 @@ // PhotoPickerDialog.PhotoPickerListener: @Override - public void onPhotoPickerUserAction(Action action, String[] photos) { + public void onPhotoPickerUserAction(@PhotoPickerAction int action, String[] photos) { mLastActionRecorded = action; mLastSelectedPhotos = photos != null ? photos.clone() : null; if (mLastSelectedPhotos != null) Arrays.sort(mLastSelectedPhotos); @@ -169,25 +169,25 @@ } private void clickDone() throws Exception { - mLastActionRecorded = null; + mLastActionRecorded = PhotoPickerAction.NUM_ENTRIES; PhotoPickerToolbar toolbar = (PhotoPickerToolbar) mDialog.findViewById(R.id.action_bar); Button done = (Button) toolbar.findViewById(R.id.done); int callCount = onActionCallback.getCallCount(); TouchCommon.singleClickView(done); onActionCallback.waitForCallback(callCount, 1); - Assert.assertEquals(PhotoPickerListener.Action.PHOTOS_SELECTED, mLastActionRecorded); + Assert.assertEquals(PhotoPickerAction.PHOTOS_SELECTED, mLastActionRecorded); } public void clickCancel() throws Exception { - mLastActionRecorded = null; + mLastActionRecorded = PhotoPickerAction.NUM_ENTRIES; PickerCategoryView categoryView = mDialog.getCategoryViewForTesting(); View cancel = new View(mActivityTestRule.getActivity()); int callCount = onActionCallback.getCallCount(); categoryView.onClick(cancel); onActionCallback.waitForCallback(callCount, 1); - Assert.assertEquals(PhotoPickerListener.Action.CANCEL, mLastActionRecorded); + Assert.assertEquals(PhotoPickerAction.CANCEL, mLastActionRecorded); } private void dismissDialog() { @@ -212,7 +212,7 @@ clickCancel(); Assert.assertNull(mLastSelectedPhotos); - Assert.assertEquals(PhotoPickerListener.Action.CANCEL, mLastActionRecorded); + Assert.assertEquals(PhotoPickerAction.CANCEL, mLastActionRecorded); dismissDialog(); } @@ -232,7 +232,7 @@ clickDone(); Assert.assertEquals(1, mLastSelectedPhotos.length); - Assert.assertEquals(PhotoPickerListener.Action.PHOTOS_SELECTED, mLastActionRecorded); + Assert.assertEquals(PhotoPickerAction.PHOTOS_SELECTED, mLastActionRecorded); Assert.assertEquals(mTestFiles.get(1).getFilePath(), mLastSelectedPhotos[0]); dismissDialog(); @@ -254,7 +254,7 @@ clickDone(); Assert.assertEquals(3, mLastSelectedPhotos.length); - Assert.assertEquals(PhotoPickerListener.Action.PHOTOS_SELECTED, mLastActionRecorded); + Assert.assertEquals(PhotoPickerAction.PHOTOS_SELECTED, mLastActionRecorded); Assert.assertEquals(mTestFiles.get(0).getFilePath(), mLastSelectedPhotos[0]); Assert.assertEquals(mTestFiles.get(2).getFilePath(), mLastSelectedPhotos[1]); Assert.assertEquals(mTestFiles.get(4).getFilePath(), mLastSelectedPhotos[2]);
diff --git a/chrome/android/webapk/libs/runtime_library/BUILD.gn b/chrome/android/webapk/libs/runtime_library/BUILD.gn index 0911aa8e..477d5f7 100644 --- a/chrome/android/webapk/libs/runtime_library/BUILD.gn +++ b/chrome/android/webapk/libs/runtime_library/BUILD.gn
@@ -49,19 +49,16 @@ ] } -dist_jar("webapk_runtime_library") { - requires_android = true +proguarded_dist_dex("webapk_runtime_library") { deps = [ ":runtime_library_for_assets_java", ] - proguard_enabled = true proguard_configs = [ "runtime_library.proguard.flags", "//base/android/proguard/chromium_code.flags", "//base/android/proguard/chromium_apk.flags", ] - output = "$target_gen_dir/$target_name.jar" - dex_path = "$target_gen_dir/$runtime_library_dex_asset_name" + output = "$target_gen_dir/$runtime_library_dex_asset_name" } android_assets("runtime_library_assets") {
diff --git a/chrome/app/generated_resources.grd b/chrome/app/generated_resources.grd index 069bab9..bb7bbbd 100644 --- a/chrome/app/generated_resources.grd +++ b/chrome/app/generated_resources.grd
@@ -548,7 +548,7 @@ &Go to <ph name="URL">$1<ex>http://www.google.com/</ex></ph> </message> <message name="IDS_CONTENT_CONTEXT_GENERATEPASSWORD" desc="The name of the Generate Password command in the content area context menu"> - Generate password... + Suggest password... </message> <message name="IDS_CONTENT_CONTEXT_MORE_APPS" desc="The label for the parent item of the submenu in the content area context menu."> More @@ -769,7 +769,7 @@ &Go to <ph name="URL">$1<ex>http://www.google.com/</ex></ph> </message> <message name="IDS_CONTENT_CONTEXT_GENERATEPASSWORD" desc="In Title Case: The name of the Generate Password command in the content area context menu"> - Generate Password... + Suggest Password... </message> </if> </if> @@ -9031,6 +9031,15 @@ <message name="IDS_VIDEO_AUDIO_CALL_NOTIFICATION_TEXT_2" desc="Text to be shown as a notification when a WebRTC video and audio call is in progress" formatter_data="android_java"> Accessing audio and video input </message> + <message name="IDS_VIDEO_CALL_INCOGNITO_NOTIFICATION_TEXT_2" desc="Text to be shown as a notification when a WebRTC video call is in progress in incognito mode." formatter_data="android_java"> + A site is accessing video input + </message> + <message name="IDS_AUDIO_CALL_INCOGNITO_NOTIFICATION_TEXT_2" desc="Text to be shown as a notification when a WebRTC audio call is in progress in incognito mode." formatter_data="android_java"> + A site is accessing audio input + </message> + <message name="IDS_VIDEO_AUDIO_CALL_INCOGNITO_NOTIFICATION_TEXT_2" desc="Text to be shown as a notification when a WebRTC video and audio call is in progress in incognito mode." formatter_data="android_java"> + A site is accessing audio and video input + </message> </if> <!-- Download open confirmation dialog -->
diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn index 1496cf80..7e10bfa6 100644 --- a/chrome/browser/BUILD.gn +++ b/chrome/browser/BUILD.gn
@@ -3090,6 +3090,7 @@ "badging/badge_service_impl.h", "component_updater/cros_component_installer_chromeos.cc", "component_updater/cros_component_installer_chromeos.h", + "component_updater/cros_component_manager.h", "component_updater/metadata_table_chromeos.cc", "component_updater/metadata_table_chromeos.h", "download/notification/download_item_notification.cc",
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc index 9c7281399..11a160d2 100644 --- a/chrome/browser/about_flags.cc +++ b/chrome/browser/about_flags.cc
@@ -65,6 +65,7 @@ #include "components/flags_ui/feature_entry_macros.h" #include "components/flags_ui/flags_storage.h" #include "components/flags_ui/flags_ui_switches.h" +#include "components/invalidation/impl/invalidation_switches.h" #include "components/language/core/common/language_experiments.h" #include "components/nacl/common/buildflags.h" #include "components/nacl/common/nacl_switches.h" @@ -431,6 +432,25 @@ switches::kChromeHomeSwipeLogicType, "velocity"}, }; +const FeatureEntry::FeatureParam kCCTModuleCache_ZeroMinutes[] = { + {"cct_module_cache_time_limit_ms", "0"}}; +const FeatureEntry::FeatureParam kCCTModuleCache_OneMinute[] = { + {"cct_module_cache_time_limit_ms", "60000"}}; +const FeatureEntry::FeatureParam kCCTModuleCache_FiveMinutes[] = { + {"cct_module_cache_time_limit_ms", "300000"}}; +const FeatureEntry::FeatureParam kCCTModuleCache_ThirtyMinutes[] = { + {"cct_module_cache_time_limit_ms", "1800000"}}; +const FeatureEntry::FeatureVariation kCCTModuleCacheVariations[] = { + {"0 minutes", kCCTModuleCache_ZeroMinutes, + base::size(kCCTModuleCache_ZeroMinutes), nullptr}, + {"1 minute", kCCTModuleCache_OneMinute, + base::size(kCCTModuleCache_OneMinute), nullptr}, + {"5 minutes", kCCTModuleCache_FiveMinutes, + base::size(kCCTModuleCache_FiveMinutes), nullptr}, + {"30 minutes", kCCTModuleCache_ThirtyMinutes, + base::size(kCCTModuleCache_ThirtyMinutes), nullptr}, +}; + #endif // OS_ANDROID const FeatureEntry::Choice kNumRasterThreadsChoices[] = { @@ -2377,9 +2397,6 @@ SINGLE_VALUE_TYPE(switches::kTrySupportedChannelLayouts)}, #endif // OS_WIN #if defined(OS_MACOSX) - {"mac-v2-sandbox", flag_descriptions::kMacV2SandboxName, - flag_descriptions::kMacV2SandboxDescription, kOsMac, - FEATURE_VALUE_TYPE(features::kMacV2Sandbox)}, {"mac-views-task-manager", flag_descriptions::kMacViewsTaskManagerName, flag_descriptions::kMacViewsTaskManagerDescription, kOsMac, FEATURE_VALUE_TYPE(features::kViewsTaskManager)}, @@ -4165,7 +4182,9 @@ FEATURE_VALUE_TYPE(chrome::android::kCCTModule)}, {"cct-module-cache", flag_descriptions::kCCTModuleCacheName, flag_descriptions::kCCTModuleCacheDescription, kOsAndroid, - FEATURE_VALUE_TYPE(chrome::android::kCCTModuleCache)}, + FEATURE_WITH_PARAMS_VALUE_TYPE(chrome::android::kCCTModuleCache, + kCCTModuleCacheVariations, + "CCTModule")}, #endif {"enable-css-fragment-identifiers", @@ -4421,6 +4440,10 @@ flag_descriptions::kAndroidSiteSettingsUIDescription, kOsAndroid, FEATURE_VALUE_TYPE(chrome::android::kAndroidSiteSettingsUI)}, #endif + {"fcm-invalidations", flag_descriptions::kFCMInvalidationsName, + flag_descriptions::kFCMInvalidationsDescription, kOsAll, + FEATURE_VALUE_TYPE(invalidation::switches::kFCMInvalidations)}, + }; class FlagsStateSingleton {
diff --git a/chrome/browser/android/chrome_feature_list.cc b/chrome/browser/android/chrome_feature_list.cc index 256dbaf..10bc0d1 100644 --- a/chrome/browser/android/chrome_feature_list.cc +++ b/chrome/browser/android/chrome_feature_list.cc
@@ -85,6 +85,7 @@ &kCCTParallelRequest, &kCCTPostMessageAPI, &kCCTRedirectPreconnect, + &kCCTReportParallelRequestStatus, &kCCTResourcePrefetch, &kChromeDuetFeature, &kChromeHomeSwipeLogic, @@ -230,6 +231,9 @@ const base::Feature kCCTRedirectPreconnect{"CCTRedirectPreconnect", base::FEATURE_ENABLED_BY_DEFAULT}; +const base::Feature kCCTReportParallelRequestStatus{ + "CCTReportParallelRequestStatus", base::FEATURE_DISABLED_BY_DEFAULT}; + const base::Feature kCCTResourcePrefetch{"CCTResourcePrefetch", base::FEATURE_ENABLED_BY_DEFAULT};
diff --git a/chrome/browser/android/chrome_feature_list.h b/chrome/browser/android/chrome_feature_list.h index b0b0ebf..00b50b8 100644 --- a/chrome/browser/android/chrome_feature_list.h +++ b/chrome/browser/android/chrome_feature_list.h
@@ -27,6 +27,7 @@ extern const base::Feature kCCTParallelRequest; extern const base::Feature kCCTPostMessageAPI; extern const base::Feature kCCTRedirectPreconnect; +extern const base::Feature kCCTReportParallelRequestStatus; extern const base::Feature kCCTResourcePrefetch; extern const base::Feature kChromeDuetFeature; extern const base::Feature kChromeHomeSwipeLogic;
diff --git a/chrome/browser/android/customtabs/detached_resource_request.cc b/chrome/browser/android/customtabs/detached_resource_request.cc index f8c6fd6..56839fb 100644 --- a/chrome/browser/android/customtabs/detached_resource_request.cc +++ b/chrome/browser/android/customtabs/detached_resource_request.cc
@@ -139,7 +139,9 @@ DCHECK_CURRENTLY_ON(content::BrowserThread::UI); int net_error = url_loader_->NetError(); bool success = net_error == net::OK; + net_error = std::abs(net_error); auto duration = base::TimeTicks::Now() - start_time_; + switch (motivation_) { case Motivation::kParallelRequest: { if (success) { @@ -158,7 +160,7 @@ } base::UmaHistogramSparse("CustomTabs.DetachedResourceRequest.FinalStatus", - std::abs(net_error)); + net_error); break; } case Motivation::kResourcePrefetch: { @@ -171,12 +173,12 @@ } base::UmaHistogramSparse("CustomTabs.ResourcePrefetch.FinalStatus", - std::abs(net_error)); + net_error); break; } } - std::move(cb_).Run(success); + std::move(cb_).Run(net_error); } } // namespace customtabs
diff --git a/chrome/browser/android/customtabs/detached_resource_request.h b/chrome/browser/android/customtabs/detached_resource_request.h index 8c997331a..0ad15e8 100644 --- a/chrome/browser/android/customtabs/detached_resource_request.h +++ b/chrome/browser/android/customtabs/detached_resource_request.h
@@ -44,13 +44,13 @@ // GENERATED_JAVA_CLASS_NAME_OVERRIDE: DetachedResourceRequestMotivation enum class Motivation { kParallelRequest, kResourcePrefetch }; - using OnResultCallback = base::OnceCallback<void(bool success)>; + using OnResultCallback = base::OnceCallback<void(int net_error)>; ~DetachedResourceRequest(); // Creates a detached request to a |url|, with a given initiating URL, // |first_party_for_cookies|. Called on the UI thread. - // Optional |cb| to get notified about the fetch result, for testing. + // Optional |cb| to get notified about the fetch result. static void CreateAndStart(content::BrowserContext* browser_context, const GURL& url, const GURL& first_party_for_cookies,
diff --git a/chrome/browser/android/customtabs/detached_resource_request_android.cc b/chrome/browser/android/customtabs/detached_resource_request_android.cc index 0d6e282..be65186 100644 --- a/chrome/browser/android/customtabs/detached_resource_request_android.cc +++ b/chrome/browser/android/customtabs/detached_resource_request_android.cc
@@ -5,6 +5,7 @@ #include "base/android/jni_android.h" #include "base/android/jni_string.h" #include "base/android/scoped_java_ref.h" +#include "base/bind.h" #include "chrome/browser/android/customtabs/detached_resource_request.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/profiles/profile_android.h" @@ -15,10 +16,25 @@ namespace customtabs { +namespace { + +void NotifyClientOfDetachedRequestCompletion( + const base::android::ScopedJavaGlobalRef<jobject>& session, + const GURL& url, + int net_error) { + JNIEnv* env = base::android::AttachCurrentThread(); + Java_CustomTabsConnection_notifyClientOfDetachedRequestCompletion( + env, session, base::android::ConvertUTF8ToJavaString(env, url.spec()), + net_error); +} + +} // namespace + static void JNI_CustomTabsConnection_CreateAndStartDetachedResourceRequest( JNIEnv* env, const base::android::JavaParamRef<jclass>& jcaller, const base::android::JavaParamRef<jobject>& profile, + const base::android::JavaParamRef<jobject>& session, const base::android::JavaParamRef<jstring>& url, const base::android::JavaParamRef<jstring>& origin, jint referrer_policy, @@ -39,9 +55,17 @@ static_cast<blink::WebReferrerPolicy>(referrer_policy)); DetachedResourceRequest::Motivation request_motivation = static_cast<DetachedResourceRequest::Motivation>(motivation); + + DetachedResourceRequest::OnResultCallback cb = + session.is_null() + ? base::DoNothing() + : base::BindOnce(&NotifyClientOfDetachedRequestCompletion, + base::android::ScopedJavaGlobalRef<jobject>(session), + native_url); + DetachedResourceRequest::CreateAndStart( native_profile, native_url, native_origin, url_request_referrer_policy, - request_motivation); + request_motivation, std::move(cb)); } } // namespace customtabs
diff --git a/chrome/browser/android/customtabs/detached_resource_request_unittest.cc b/chrome/browser/android/customtabs/detached_resource_request_unittest.cc index b3224578..8cd628d0 100644 --- a/chrome/browser/android/customtabs/detached_resource_request_unittest.cc +++ b/chrome/browser/android/customtabs/detached_resource_request_unittest.cc
@@ -228,8 +228,8 @@ DetachedResourceRequest::CreateAndStart( browser_context(), url, site_for_cookies, policy, kMotivation, - base::BindLambdaForTesting([&](bool success) { - EXPECT_TRUE(success); + base::BindLambdaForTesting([&](int net_error) { + EXPECT_EQ(net::OK, net_error); request_completion_waiter.Quit(); })); server_request_waiter.Run(); @@ -260,8 +260,8 @@ DetachedResourceRequest::CreateAndStart( browser_context(), url, site_for_cookies, content::Referrer::GetDefaultReferrerPolicy(), kMotivation, - base::BindLambdaForTesting([&](bool success) { - EXPECT_TRUE(success); + base::BindLambdaForTesting([&](int net_error) { + EXPECT_EQ(net::OK, net_error); request_completion_waiter.Quit(); })); server_request_waiter.Run(); @@ -285,8 +285,8 @@ DetachedResourceRequest::CreateAndStart( browser_context(), url, site_for_cookies, content::Referrer::GetDefaultReferrerPolicy(), kMotivation, - base::BindLambdaForTesting([&](bool success) { - EXPECT_FALSE(success); + base::BindLambdaForTesting([&](int net_error) { + EXPECT_NE(net::OK, net_error); request_waiter.Quit(); })); request_waiter.Run(); @@ -389,8 +389,8 @@ DetachedResourceRequest::CreateAndStart( browser_context(), url, site_for_cookies, content::Referrer::GetDefaultReferrerPolicy(), kMotivation, - base::BindLambdaForTesting([&](bool success) { - EXPECT_TRUE(success); + base::BindLambdaForTesting([&](int net_error) { + EXPECT_EQ(net::OK, net_error); request_completion_waiter.Quit(); })); @@ -450,8 +450,8 @@ DetachedResourceRequest::CreateAndStart( browser_context(), url, site_for_cookies, content::Referrer::GetDefaultReferrerPolicy(), kMotivation, - base::BindLambdaForTesting([&](bool success) { - EXPECT_TRUE(success); + base::BindLambdaForTesting([&](int net_error) { + EXPECT_EQ(net::OK, net_error); detached_request_waiter.Quit(); })); first_request_waiter.Run(); @@ -481,8 +481,8 @@ DetachedResourceRequest::CreateAndStart( browser_context(), url, site_for_cookies, content::Referrer::GetDefaultReferrerPolicy(), kMotivation, - base::BindLambdaForTesting([&](bool success) { - EXPECT_TRUE(success); + base::BindLambdaForTesting([&](int net_error) { + EXPECT_EQ(net::OK, net_error); request_waiter.Quit(); })); request_waiter.Run(); @@ -505,8 +505,8 @@ DetachedResourceRequest::CreateAndStart( browser_context(), url, site_for_cookies, content::Referrer::GetDefaultReferrerPolicy(), kMotivation, - base::BindLambdaForTesting([&](bool success) { - EXPECT_FALSE(success); + base::BindLambdaForTesting([&](int net_error) { + EXPECT_EQ(-net::ERR_TOO_MANY_REDIRECTS, net_error); request_waiter.Quit(); })); request_waiter.Run(); @@ -534,8 +534,8 @@ DetachedResourceRequest::CreateAndStart( browser_context(), url, site_for_cookies, content::Referrer::GetDefaultReferrerPolicy(), kMotivation, - base::BindLambdaForTesting([&](bool success) { - EXPECT_TRUE(success); + base::BindLambdaForTesting([&](int net_error) { + EXPECT_EQ(net::OK, net_error); first_request_waiter.Quit(); })); first_request_waiter.Run(); @@ -543,8 +543,8 @@ DetachedResourceRequest::CreateAndStart( browser_context(), url, site_for_cookies, content::Referrer::GetDefaultReferrerPolicy(), kMotivation, - base::BindLambdaForTesting([&](bool success) { - EXPECT_TRUE(success); + base::BindLambdaForTesting([&](int net_error) { + EXPECT_EQ(net::OK, net_error); second_request_waiter.Quit(); })); second_request_waiter.Run();
diff --git a/chrome/browser/android/download/download_media_parser.cc b/chrome/browser/android/download/download_media_parser.cc index 78e6cd6..4491002f 100644 --- a/chrome/browser/android/download/download_media_parser.cc +++ b/chrome/browser/android/download/download_media_parser.cc
@@ -156,14 +156,15 @@ void DownloadMediaParser::OnVideoFrameRetrieved( bool success, chrome::mojom::VideoFrameDataPtr video_frame_data, - const media::VideoDecoderConfig& config) { + const base::Optional<media::VideoDecoderConfig>& config) { if (!success) { OnError(); return; } video_frame_data_ = std::move(video_frame_data); - config_ = config; + DCHECK(config.has_value()); + config_ = config.value(); // For vp8, vp9 codec, we directly do software decoding in utility process. // Render now.
diff --git a/chrome/browser/android/download/download_media_parser.h b/chrome/browser/android/download/download_media_parser.h index 48c6b82..a4e1e22 100644 --- a/chrome/browser/android/download/download_media_parser.h +++ b/chrome/browser/android/download/download_media_parser.h
@@ -14,6 +14,7 @@ #include "base/macros.h" #include "base/memory/scoped_refptr.h" #include "base/memory/weak_ptr.h" +#include "base/optional.h" #include "base/sequenced_task_runner.h" #include "chrome/common/media_galleries/metadata_types.h" #include "chrome/services/media_gallery_util/public/cpp/media_parser_provider.h" @@ -69,9 +70,10 @@ // Retrieves an encoded video frame. void RetrieveEncodedVideoFrame(); - void OnVideoFrameRetrieved(bool success, - chrome::mojom::VideoFrameDataPtr video_frame_data, - const media::VideoDecoderConfig& config); + void OnVideoFrameRetrieved( + bool success, + chrome::mojom::VideoFrameDataPtr video_frame_data, + const base::Optional<media::VideoDecoderConfig>& config); // Decodes the video frame. void OnGpuVideoAcceleratorFactoriesReady(
diff --git a/chrome/browser/android/password_manager/password_accessory_view_android.cc b/chrome/browser/android/password_manager/password_accessory_view_android.cc index 44d412f..efbd901 100644 --- a/chrome/browser/android/password_manager/password_accessory_view_android.cc +++ b/chrome/browser/android/password_manager/password_accessory_view_android.cc
@@ -74,6 +74,16 @@ base::android::AttachCurrentThread(), java_object_); } +void PasswordAccessoryViewAndroid::ShowWhenKeyboardIsVisible() { + Java_PasswordAccessoryBridge_showWhenKeyboardIsVisible( + base::android::AttachCurrentThread(), java_object_); +} + +void PasswordAccessoryViewAndroid::Hide() { + Java_PasswordAccessoryBridge_hide(base::android::AttachCurrentThread(), + java_object_); +} + void PasswordAccessoryViewAndroid::OnAutomaticGenerationStatusChanged( bool available) { if (!available && java_object_.is_null())
diff --git a/chrome/browser/android/password_manager/password_accessory_view_android.h b/chrome/browser/android/password_manager/password_accessory_view_android.h index 1499613..1b4276e8 100644 --- a/chrome/browser/android/password_manager/password_accessory_view_android.h +++ b/chrome/browser/android/password_manager/password_accessory_view_android.h
@@ -31,6 +31,8 @@ void OnAutomaticGenerationStatusChanged(bool available) override; void CloseAccessorySheet() override; void SwapSheetWithKeyboard() override; + void ShowWhenKeyboardIsVisible() override; + void Hide() override; // Called from Java via JNI: void OnFaviconRequested(
diff --git a/chrome/browser/android/preferences/pref_service_bridge.cc b/chrome/browser/android/preferences/pref_service_bridge.cc index a46c5eb..dd13c9a 100644 --- a/chrome/browser/android/preferences/pref_service_bridge.cc +++ b/chrome/browser/android/preferences/pref_service_bridge.cc
@@ -433,7 +433,7 @@ const JavaParamRef<jobject>& obj) { PrefService* pref_service = GetPrefService(); return pref_service->IsManagedPreference( - safe_browsing::GetExtendedReportingPrefName(*pref_service)); + prefs::kSafeBrowsingScoutReportingEnabled); } static jboolean JNI_PrefServiceBridge_GetSafeBrowsingEnabled(
diff --git a/chrome/browser/autofill/autofill_interactive_uitest.cc b/chrome/browser/autofill/autofill_interactive_uitest.cc index 4d24541..7f35ff1a 100644 --- a/chrome/browser/autofill/autofill_interactive_uitest.cc +++ b/chrome/browser/autofill/autofill_interactive_uitest.cc
@@ -14,6 +14,7 @@ #include "base/metrics/field_trial.h" #include "base/rand_util.h" #include "base/run_loop.h" +#include "base/strings/strcat.h" #include "base/strings/string16.h" #include "base/strings/string_number_conversions.h" #include "base/strings/string_split.h" @@ -87,7 +88,6 @@ namespace { -static const char kDataURIPrefix[] = "data:text/html;charset=utf-8,"; static const char kTestShippingFormString[] = "<form action=\"http://www.example.com/\" method=\"POST\">" "<label for=\"firstname\">First name:</label>" @@ -246,6 +246,8 @@ https_server_.SetSSLConfig(net::EmbeddedTestServer::CERT_OK); https_server_.ServeFilesFromSourceDirectory("chrome/test/data"); + https_server_.RegisterRequestHandler(base::BindRepeating( + &AutofillInteractiveTestBase::HandleTestURL, base::Unretained(this))); ASSERT_TRUE(https_server_.InitializeAndListen()); https_server_.StartAcceptingConnections(); @@ -256,6 +258,8 @@ // Ensure that |embedded_test_server()| serves both domains used below. host_resolver()->AddRule("*", "127.0.0.1"); + embedded_test_server()->RegisterRequestHandler(base::BindRepeating( + &AutofillInteractiveTestBase::HandleTestURL, base::Unretained(this))); embedded_test_server()->StartAcceptingConnections(); // By default, all SSL cert checks are valid. Can be overriden in tests if @@ -278,6 +282,18 @@ AutofillUiTest::TearDownInProcessBrowserTestFixture(); } + std::unique_ptr<net::test_server::HttpResponse> HandleTestURL( + const net::test_server::HttpRequest& request) { + if (request.relative_url != kTestUrlPath) + return nullptr; + + auto response = std::make_unique<net::test_server::BasicHttpResponse>(); + response->set_code(net::HTTP_OK); + response->set_content_type("text/html;charset=utf-8"); + response->set_content(test_url_content_); + return std::move(response); + } + content::WebContents* GetWebContents() { return browser()->tab_strip_model()->GetActiveWebContents(); } @@ -599,8 +615,16 @@ {ObservedUiEvents::kFormDataFilled}, widget); } + GURL GetTestUrl() const { return https_server_.GetURL(kTestUrlPath); } + + void SetTestUrlResponse(std::string content) { + test_url_content_ = std::move(content); + } + net::EmbeddedTestServer* https_server() { return &https_server_; } + static const char kTestUrlPath[]; + private: net::EmbeddedTestServer https_server_; @@ -624,9 +648,15 @@ std::unique_ptr<net::test_server::ControllableHttpResponse> controllable_http_response_; + // The response to return for queries to |kTestUrlPath| + std::string test_url_content_; + DISALLOW_COPY_AND_ASSIGN(AutofillInteractiveTestBase); }; +const char AutofillInteractiveTestBase::kTestUrlPath[] = + "/internal/test_url_path"; + // AutofillInteractiveTest ---------------------------------------------------- class AutofillInteractiveTest : public AutofillInteractiveTestBase { @@ -648,8 +678,9 @@ CreateTestProfile(); // Load the test page. - ASSERT_NO_FATAL_FAILURE(ui_test_utils::NavigateToURL( - browser(), GURL(std::string(kDataURIPrefix) + kTestShippingFormString))); + SetTestUrlResponse(kTestShippingFormString); + ASSERT_NO_FATAL_FAILURE( + ui_test_utils::NavigateToURL(browser(), GetTestUrl())); // Invoke Autofill. TryBasicFormFill(); @@ -658,9 +689,11 @@ IN_PROC_BROWSER_TEST_F(AutofillInteractiveTest, BasicClear) { CreateTestProfile(); + SetTestUrlResponse(kTestShippingFormString); + // Load the test page. - ASSERT_NO_FATAL_FAILURE(ui_test_utils::NavigateToURL( - browser(), GURL(std::string(kDataURIPrefix) + kTestShippingFormString))); + ASSERT_NO_FATAL_FAILURE( + ui_test_utils::NavigateToURL(browser(), GetTestUrl())); TryBasicFormFill(); @@ -671,9 +704,10 @@ CreateTestProfile(); // Load the test page. - ASSERT_NO_FATAL_FAILURE(ui_test_utils::NavigateToURL( - browser(), GURL(std::string(kDataURIPrefix) + kTestShippingFormString + - kTestBillingFormString))); + SetTestUrlResponse( + base::StrCat({kTestShippingFormString, kTestBillingFormString})); + ASSERT_NO_FATAL_FAILURE( + ui_test_utils::NavigateToURL(browser(), GetTestUrl())); // Fill first section. TryBasicFormFill(); @@ -707,8 +741,9 @@ CreateTestProfile(); // Load the test page. - ASSERT_NO_FATAL_FAILURE(ui_test_utils::NavigateToURL( - browser(), GURL(std::string(kDataURIPrefix) + kTestShippingFormString))); + SetTestUrlResponse(kTestShippingFormString); + ASSERT_NO_FATAL_FAILURE( + ui_test_utils::NavigateToURL(browser(), GetTestUrl())); // Modify a field. FocusFieldByName("city"); @@ -735,8 +770,9 @@ CreateTestProfile(); // Load the test page. - ASSERT_NO_FATAL_FAILURE(ui_test_utils::NavigateToURL( - browser(), GURL(std::string(kDataURIPrefix) + kTestShippingFormString))); + SetTestUrlResponse(kTestShippingFormString); + ASSERT_NO_FATAL_FAILURE( + ui_test_utils::NavigateToURL(browser(), GetTestUrl())); // Modify a field. FocusFieldByName("state"); @@ -770,10 +806,10 @@ "document.getElementById('phone').value = '15142223344';" "</script>"; - // Load the test page and prefill it with the above script. - ASSERT_NO_FATAL_FAILURE(ui_test_utils::NavigateToURL( - browser(), GURL(std::string(kDataURIPrefix) + kTestShippingFormString + - kPrefillScript))); + // Load the test page. + SetTestUrlResponse(base::StrCat({kTestShippingFormString, kPrefillScript})); + ASSERT_NO_FATAL_FAILURE( + ui_test_utils::NavigateToURL(browser(), GetTestUrl())); CreateTestProfile(); @@ -791,8 +827,9 @@ CreateTestProfile(); // Load the test page. - ASSERT_NO_FATAL_FAILURE(ui_test_utils::NavigateToURL( - browser(), GURL(std::string(kDataURIPrefix) + kTestShippingFormString))); + SetTestUrlResponse(kTestShippingFormString); + ASSERT_NO_FATAL_FAILURE( + ui_test_utils::NavigateToURL(browser(), GetTestUrl())); TryBasicFormFill(); @@ -851,8 +888,9 @@ CreateTestProfile(); // Load the test page. - ASSERT_NO_FATAL_FAILURE(ui_test_utils::NavigateToURL( - browser(), GURL(std::string(kDataURIPrefix) + kTestShippingFormString))); + SetTestUrlResponse(kTestShippingFormString); + ASSERT_NO_FATAL_FAILURE( + ui_test_utils::NavigateToURL(browser(), GetTestUrl())); TryBasicFormFill(); @@ -891,8 +929,9 @@ CreateTestProfile(); // Load the test page. - ASSERT_NO_FATAL_FAILURE(ui_test_utils::NavigateToURL( - browser(), GURL(std::string(kDataURIPrefix) + kTestShippingFormString))); + SetTestUrlResponse(kTestShippingFormString); + ASSERT_NO_FATAL_FAILURE( + ui_test_utils::NavigateToURL(browser(), GetTestUrl())); TryBasicFormFill(); // Change the last name. @@ -933,8 +972,9 @@ CreateSecondTestProfile(); // Load the test page. - ASSERT_NO_FATAL_FAILURE(ui_test_utils::NavigateToURL( - browser(), GURL(std::string(kDataURIPrefix) + kTestShippingFormString))); + SetTestUrlResponse(kTestShippingFormString); + ASSERT_NO_FATAL_FAILURE( + ui_test_utils::NavigateToURL(browser(), GetTestUrl())); TryBasicFormFill(); @@ -966,8 +1006,9 @@ CreateTestProfile(); // Load the test page. - ASSERT_NO_FATAL_FAILURE(ui_test_utils::NavigateToURL( - browser(), GURL(std::string(kDataURIPrefix) + kTestShippingFormString))); + SetTestUrlResponse(kTestShippingFormString); + ASSERT_NO_FATAL_FAILURE( + ui_test_utils::NavigateToURL(browser(), GetTestUrl())); // Focus a fillable field. FocusFirstNameField(); @@ -982,8 +1023,9 @@ CreateTestProfile(); // Load the test page. - ASSERT_NO_FATAL_FAILURE(ui_test_utils::NavigateToURL( - browser(), GURL(std::string(kDataURIPrefix) + kTestShippingFormString))); + SetTestUrlResponse(kTestShippingFormString); + ASSERT_NO_FATAL_FAILURE( + ui_test_utils::NavigateToURL(browser(), GetTestUrl())); // Focus a fillable field. FocusFirstNameField(); @@ -998,8 +1040,10 @@ CreateTestProfile(); // Load the test page. - ASSERT_NO_FATAL_FAILURE(ui_test_utils::NavigateToURL( - browser(), GURL(std::string(kDataURIPrefix) + kTestShippingFormString))); + SetTestUrlResponse(kTestShippingFormString); + ASSERT_NO_FATAL_FAILURE( + ui_test_utils::NavigateToURL(browser(), GetTestUrl())); + // Focus a fillable field. ASSERT_NO_FATAL_FAILURE(FocusFirstNameField()); @@ -1074,8 +1118,9 @@ CreateTestProfile(); // Load the test page. - ASSERT_NO_FATAL_FAILURE(ui_test_utils::NavigateToURL( - browser(), GURL(std::string(kDataURIPrefix) + kTestShippingFormString))); + SetTestUrlResponse(kTestShippingFormString); + ASSERT_NO_FATAL_FAILURE( + ui_test_utils::NavigateToURL(browser(), GetTestUrl())); // If AutofillSingleClick is NOT enabled, then the first time we click on the // first name field, nothing should happen. @@ -1107,13 +1152,15 @@ // Makes sure that clicking outside the focused field doesn't activate // the popup. IN_PROC_BROWSER_TEST_F(AutofillInteractiveTest, DontAutofillForOutsideClick) { + static const char kDisabledButton[] = + "<button disabled id='disabled-button'>Cant click this</button>"; + CreateTestProfile(); // Load the test page. - ASSERT_NO_FATAL_FAILURE(ui_test_utils::NavigateToURL( - browser(), - GURL(std::string(kDataURIPrefix) + kTestShippingFormString + - "<button disabled id='disabled-button'>Cant click this</button>"))); + SetTestUrlResponse(base::StrCat({kTestShippingFormString, kDisabledButton})); + ASSERT_NO_FATAL_FAILURE( + ui_test_utils::NavigateToURL(browser(), GetTestUrl())); ASSERT_NO_FATAL_FAILURE(FocusFirstNameField()); @@ -1134,8 +1181,9 @@ CreateTestProfile(); // Load the test page. - ASSERT_NO_FATAL_FAILURE(ui_test_utils::NavigateToURL( - browser(), GURL(std::string(kDataURIPrefix) + kTestShippingFormString))); + SetTestUrlResponse(kTestShippingFormString); + ASSERT_NO_FATAL_FAILURE( + ui_test_utils::NavigateToURL(browser(), GetTestUrl())); // Invoke and accept the Autofill popup and verify the form was filled. FocusFirstNameField(); @@ -1174,18 +1222,21 @@ #endif IN_PROC_BROWSER_TEST_F(AutofillInteractiveTest, MAYBE_OnSelectOptionFromDatalist) { + static const char kTestForm[] = + "<form action=\"http://www.example.com/\" method=\"POST\">" + " <input list=\"dl\" type=\"search\" id=\"firstname\"><br>" + " <datalist id=\"dl\">" + " <option value=\"Adam\"></option>" + " <option value=\"Bob\"></option>" + " <option value=\"Carl\"></option>" + " </datalist>" + "</form>"; + // Load the test page. - ASSERT_NO_FATAL_FAILURE(ui_test_utils::NavigateToURL( - browser(), - GURL(std::string(kDataURIPrefix) + - "<form action=\"http://www.example.com/\" method=\"POST\">" - " <input list=\"dl\" type=\"search\" id=\"firstname\"><br>" - " <datalist id=\"dl\">" - " <option value=\"Adam\"></option>" - " <option value=\"Bob\"></option>" - " <option value=\"Carl\"></option>" - " </datalist>" - "</form>"))); + SetTestUrlResponse(kTestForm); + ASSERT_NO_FATAL_FAILURE( + ui_test_utils::NavigateToURL(browser(), GetTestUrl())); + std::string orginalcolor; GetFieldBackgroundColor("firstname", &orginalcolor); @@ -1202,9 +1253,7 @@ // Test that a JavaScript oninput event is fired after auto-filling a form. IN_PROC_BROWSER_TEST_F(AutofillInteractiveTest, OnInputAfterAutofill) { - CreateTestProfile(); - - const char kOnInputScript[] = + static const char kOnInputScript[] = "<script>" "focused_fired = false;" "unfocused_fired = false;" @@ -1225,10 +1274,12 @@ "document.getElementById('country').value = 'US';" "</script>"; + CreateTestProfile(); + // Load the test page. - ASSERT_NO_FATAL_FAILURE(ui_test_utils::NavigateToURL( - browser(), GURL(std::string(kDataURIPrefix) + kTestShippingFormString + - kOnInputScript))); + SetTestUrlResponse(base::StrCat({kTestShippingFormString, kOnInputScript})); + ASSERT_NO_FATAL_FAILURE( + ui_test_utils::NavigateToURL(browser(), GetTestUrl())); // Invoke Autofill. FocusFirstNameField(); @@ -1273,9 +1324,7 @@ // Test that a JavaScript onchange event is fired after auto-filling a form. IN_PROC_BROWSER_TEST_F(AutofillInteractiveTest, OnChangeAfterAutofill) { - CreateTestProfile(); - - const char kOnChangeScript[] = + static const char kOnChangeScript[] = "<script>" "focused_fired = false;" "unfocused_fired = false;" @@ -1296,10 +1345,12 @@ "document.getElementById('country').value = 'US';" "</script>"; + CreateTestProfile(); + // Load the test page. - ASSERT_NO_FATAL_FAILURE(ui_test_utils::NavigateToURL( - browser(), GURL(std::string(kDataURIPrefix) + kTestShippingFormString + - kOnChangeScript))); + SetTestUrlResponse(base::StrCat({kTestShippingFormString, kOnChangeScript})); + ASSERT_NO_FATAL_FAILURE( + ui_test_utils::NavigateToURL(browser(), GetTestUrl())); // Invoke Autofill. FocusFirstNameField(); @@ -1343,9 +1394,7 @@ } IN_PROC_BROWSER_TEST_F(AutofillInteractiveTest, InputFiresBeforeChange) { - CreateTestProfile(); - - const char kInputFiresBeforeChangeScript[] = + static const char kInputFiresBeforeChangeScript[] = "<script>" "inputElementEvents = [];" "function recordInputElementEvent(e) {" @@ -1363,10 +1412,13 @@ "document.getElementById('country').onchange = recordSelectElementEvent;" "</script>"; + CreateTestProfile(); + // Load the test page. - ASSERT_NO_FATAL_FAILURE(ui_test_utils::NavigateToURL( - browser(), GURL(std::string(kDataURIPrefix) + kTestShippingFormString + - kInputFiresBeforeChangeScript))); + SetTestUrlResponse( + base::StrCat({kTestShippingFormString, kInputFiresBeforeChangeScript})); + ASSERT_NO_FATAL_FAILURE( + ui_test_utils::NavigateToURL(browser(), GetTestUrl())); // Invoke and accept the Autofill popup and verify the form was filled. FocusFirstNameField(); @@ -1421,11 +1473,7 @@ // Test that we can autofill forms distinguished only by their |id| attribute. IN_PROC_BROWSER_TEST_F(AutofillInteractiveTest, AutofillFormsDistinguishedById) { - CreateTestProfile(); - - // Load the test page. - const std::string kURL = - std::string(kDataURIPrefix) + kTestShippingFormString + + static const char kScript[] = "<script>" "var mainForm = document.forms[0];" "mainForm.id = 'mainForm';" @@ -1435,7 +1483,13 @@ "newForm.id = 'newForm';" "mainForm.parentNode.insertBefore(newForm, mainForm);" "</script>"; - ASSERT_NO_FATAL_FAILURE(ui_test_utils::NavigateToURL(browser(), GURL(kURL))); + + CreateTestProfile(); + + // Load the test page. + SetTestUrlResponse(base::StrCat({kTestShippingFormString, kScript})); + ASSERT_NO_FATAL_FAILURE( + ui_test_utils::NavigateToURL(browser(), GetTestUrl())); // Invoke Autofill. TryBasicFormFill(); @@ -1446,43 +1500,46 @@ // (duplicated for "confirmation"); or variants that are hot-swapped via // JavaScript, with only one actually visible at any given time. IN_PROC_BROWSER_TEST_F(AutofillInteractiveTest, AutofillFormWithRepeatedField) { + static const char kForm[] = + "<form action=\"http://www.example.com/\" method=\"POST\">" + "<label for=\"firstname\">First name:</label>" + " <input type=\"text\" id=\"firstname\"" + " onfocus=\"domAutomationController.send(true)\"><br>" + "<label for=\"lastname\">Last name:</label>" + " <input type=\"text\" id=\"lastname\"><br>" + "<label for=\"address1\">Address line 1:</label>" + " <input type=\"text\" id=\"address1\"><br>" + "<label for=\"address2\">Address line 2:</label>" + " <input type=\"text\" id=\"address2\"><br>" + "<label for=\"city\">City:</label>" + " <input type=\"text\" id=\"city\"><br>" + "<label for=\"state\">State:</label>" + " <select id=\"state\">" + " <option value=\"\" selected=\"yes\">--</option>" + " <option value=\"CA\">California</option>" + " <option value=\"TX\">Texas</option>" + " </select><br>" + "<label for=\"state_freeform\" style=\"display:none\">State:</label>" + " <input type=\"text\" id=\"state_freeform\"" + " style=\"display:none\"><br>" + "<label for=\"zip\">ZIP code:</label>" + " <input type=\"text\" id=\"zip\"><br>" + "<label for=\"country\">Country:</label>" + " <select id=\"country\">" + " <option value=\"\" selected=\"yes\">--</option>" + " <option value=\"CA\">Canada</option>" + " <option value=\"US\">United States</option>" + " </select><br>" + "<label for=\"phone\">Phone number:</label>" + " <input type=\"text\" id=\"phone\"><br>" + "</form>"; + CreateTestProfile(); // Load the test page. - ASSERT_NO_FATAL_FAILURE(ui_test_utils::NavigateToURL(browser(), - GURL(std::string(kDataURIPrefix) + - "<form action=\"http://www.example.com/\" method=\"POST\">" - "<label for=\"firstname\">First name:</label>" - " <input type=\"text\" id=\"firstname\"" - " onfocus=\"domAutomationController.send(true)\"><br>" - "<label for=\"lastname\">Last name:</label>" - " <input type=\"text\" id=\"lastname\"><br>" - "<label for=\"address1\">Address line 1:</label>" - " <input type=\"text\" id=\"address1\"><br>" - "<label for=\"address2\">Address line 2:</label>" - " <input type=\"text\" id=\"address2\"><br>" - "<label for=\"city\">City:</label>" - " <input type=\"text\" id=\"city\"><br>" - "<label for=\"state\">State:</label>" - " <select id=\"state\">" - " <option value=\"\" selected=\"yes\">--</option>" - " <option value=\"CA\">California</option>" - " <option value=\"TX\">Texas</option>" - " </select><br>" - "<label for=\"state_freeform\" style=\"display:none\">State:</label>" - " <input type=\"text\" id=\"state_freeform\"" - " style=\"display:none\"><br>" - "<label for=\"zip\">ZIP code:</label>" - " <input type=\"text\" id=\"zip\"><br>" - "<label for=\"country\">Country:</label>" - " <select id=\"country\">" - " <option value=\"\" selected=\"yes\">--</option>" - " <option value=\"CA\">Canada</option>" - " <option value=\"US\">United States</option>" - " </select><br>" - "<label for=\"phone\">Phone number:</label>" - " <input type=\"text\" id=\"phone\"><br>" - "</form>"))); + SetTestUrlResponse(kForm); + ASSERT_NO_FATAL_FAILURE( + ui_test_utils::NavigateToURL(browser(), GetTestUrl())); // Invoke Autofill. TryBasicFormFill(); @@ -1492,42 +1549,45 @@ // Test that we properly autofill forms with non-autofillable fields. IN_PROC_BROWSER_TEST_F(AutofillInteractiveTest, AutofillFormWithNonAutofillableField) { + static const char kForm[] = + "<form action=\"http://www.example.com/\" method=\"POST\">" + "<label for=\"firstname\">First name:</label>" + " <input type=\"text\" id=\"firstname\"" + " onfocus=\"domAutomationController.send(true)\"><br>" + "<label for=\"middlename\">Middle name:</label>" + " <input type=\"text\" id=\"middlename\" autocomplete=\"off\" /><br>" + "<label for=\"lastname\">Last name:</label>" + " <input type=\"text\" id=\"lastname\"><br>" + "<label for=\"address1\">Address line 1:</label>" + " <input type=\"text\" id=\"address1\"><br>" + "<label for=\"address2\">Address line 2:</label>" + " <input type=\"text\" id=\"address2\"><br>" + "<label for=\"city\">City:</label>" + " <input type=\"text\" id=\"city\"><br>" + "<label for=\"state\">State:</label>" + " <select id=\"state\">" + " <option value=\"\" selected=\"yes\">--</option>" + " <option value=\"CA\">California</option>" + " <option value=\"TX\">Texas</option>" + " </select><br>" + "<label for=\"zip\">ZIP code:</label>" + " <input type=\"text\" id=\"zip\"><br>" + "<label for=\"country\">Country:</label>" + " <select id=\"country\">" + " <option value=\"\" selected=\"yes\">--</option>" + " <option value=\"CA\">Canada</option>" + " <option value=\"US\">United States</option>" + " </select><br>" + "<label for=\"phone\">Phone number:</label>" + " <input type=\"text\" id=\"phone\"><br>" + "</form>"; + CreateTestProfile(); // Load the test page. - ASSERT_NO_FATAL_FAILURE(ui_test_utils::NavigateToURL(browser(), - GURL(std::string(kDataURIPrefix) + - "<form action=\"http://www.example.com/\" method=\"POST\">" - "<label for=\"firstname\">First name:</label>" - " <input type=\"text\" id=\"firstname\"" - " onfocus=\"domAutomationController.send(true)\"><br>" - "<label for=\"middlename\">Middle name:</label>" - " <input type=\"text\" id=\"middlename\" autocomplete=\"off\" /><br>" - "<label for=\"lastname\">Last name:</label>" - " <input type=\"text\" id=\"lastname\"><br>" - "<label for=\"address1\">Address line 1:</label>" - " <input type=\"text\" id=\"address1\"><br>" - "<label for=\"address2\">Address line 2:</label>" - " <input type=\"text\" id=\"address2\"><br>" - "<label for=\"city\">City:</label>" - " <input type=\"text\" id=\"city\"><br>" - "<label for=\"state\">State:</label>" - " <select id=\"state\">" - " <option value=\"\" selected=\"yes\">--</option>" - " <option value=\"CA\">California</option>" - " <option value=\"TX\">Texas</option>" - " </select><br>" - "<label for=\"zip\">ZIP code:</label>" - " <input type=\"text\" id=\"zip\"><br>" - "<label for=\"country\">Country:</label>" - " <select id=\"country\">" - " <option value=\"\" selected=\"yes\">--</option>" - " <option value=\"CA\">Canada</option>" - " <option value=\"US\">United States</option>" - " </select><br>" - "<label for=\"phone\">Phone number:</label>" - " <input type=\"text\" id=\"phone\"><br>" - "</form>"))); + SetTestUrlResponse(kForm); + ASSERT_NO_FATAL_FAILURE( + ui_test_utils::NavigateToURL(browser(), GetTestUrl())); // Invoke Autofill. TryBasicFormFill(); @@ -1535,84 +1595,87 @@ // Test that we can Autofill dynamically generated forms. IN_PROC_BROWSER_TEST_F(AutofillInteractiveTest, DynamicFormFill) { + static const char kDynamicForm[] = + "<form id=\"form\" action=\"http://www.example.com/\"" + " method=\"POST\"></form>" + "<script>" + "function AddElement(name, label) {" + " var form = document.getElementById('form');" + "" + " var label_text = document.createTextNode(label);" + " var label_element = document.createElement('label');" + " label_element.setAttribute('for', name);" + " label_element.appendChild(label_text);" + " form.appendChild(label_element);" + "" + " if (name === 'state' || name === 'country') {" + " var select_element = document.createElement('select');" + " select_element.setAttribute('id', name);" + " select_element.setAttribute('name', name);" + "" + " /* Add an empty selected option. */" + " var default_option = new Option('--', '', true);" + " select_element.appendChild(default_option);" + "" + " /* Add the other options. */" + " if (name == 'state') {" + " var option1 = new Option('California', 'CA');" + " select_element.appendChild(option1);" + " var option2 = new Option('Texas', 'TX');" + " select_element.appendChild(option2);" + " } else {" + " var option1 = new Option('Canada', 'CA');" + " select_element.appendChild(option1);" + " var option2 = new Option('United States', 'US');" + " select_element.appendChild(option2);" + " }" + "" + " form.appendChild(select_element);" + " } else {" + " var input_element = document.createElement('input');" + " input_element.setAttribute('id', name);" + " input_element.setAttribute('name', name);" + "" + " /* Add the onfocus listener to the 'firstname' field. */" + " if (name === 'firstname') {" + " input_element.onfocus = function() {" + " domAutomationController.send(true);" + " };" + " }" + "" + " form.appendChild(input_element);" + " }" + "" + " form.appendChild(document.createElement('br'));" + "};" + "" + "function BuildForm() {" + " var elements = [" + " ['firstname', 'First name:']," + " ['lastname', 'Last name:']," + " ['address1', 'Address line 1:']," + " ['address2', 'Address line 2:']," + " ['city', 'City:']," + " ['state', 'State:']," + " ['zip', 'ZIP code:']," + " ['country', 'Country:']," + " ['phone', 'Phone number:']," + " ];" + "" + " for (var i = 0; i < elements.length; i++) {" + " var name = elements[i][0];" + " var label = elements[i][1];" + " AddElement(name, label);" + " }" + "};" + "</script>"; + CreateTestProfile(); // Load the test page. - ASSERT_NO_FATAL_FAILURE(ui_test_utils::NavigateToURL(browser(), - GURL(std::string(kDataURIPrefix) + - "<form id=\"form\" action=\"http://www.example.com/\"" - " method=\"POST\"></form>" - "<script>" - "function AddElement(name, label) {" - " var form = document.getElementById('form');" - "" - " var label_text = document.createTextNode(label);" - " var label_element = document.createElement('label');" - " label_element.setAttribute('for', name);" - " label_element.appendChild(label_text);" - " form.appendChild(label_element);" - "" - " if (name === 'state' || name === 'country') {" - " var select_element = document.createElement('select');" - " select_element.setAttribute('id', name);" - " select_element.setAttribute('name', name);" - "" - " /* Add an empty selected option. */" - " var default_option = new Option('--', '', true);" - " select_element.appendChild(default_option);" - "" - " /* Add the other options. */" - " if (name == 'state') {" - " var option1 = new Option('California', 'CA');" - " select_element.appendChild(option1);" - " var option2 = new Option('Texas', 'TX');" - " select_element.appendChild(option2);" - " } else {" - " var option1 = new Option('Canada', 'CA');" - " select_element.appendChild(option1);" - " var option2 = new Option('United States', 'US');" - " select_element.appendChild(option2);" - " }" - "" - " form.appendChild(select_element);" - " } else {" - " var input_element = document.createElement('input');" - " input_element.setAttribute('id', name);" - " input_element.setAttribute('name', name);" - "" - " /* Add the onfocus listener to the 'firstname' field. */" - " if (name === 'firstname') {" - " input_element.onfocus = function() {" - " domAutomationController.send(true);" - " };" - " }" - "" - " form.appendChild(input_element);" - " }" - "" - " form.appendChild(document.createElement('br'));" - "};" - "" - "function BuildForm() {" - " var elements = [" - " ['firstname', 'First name:']," - " ['lastname', 'Last name:']," - " ['address1', 'Address line 1:']," - " ['address2', 'Address line 2:']," - " ['city', 'City:']," - " ['state', 'State:']," - " ['zip', 'ZIP code:']," - " ['country', 'Country:']," - " ['phone', 'Phone number:']," - " ];" - "" - " for (var i = 0; i < elements.length; i++) {" - " var name = elements[i][0];" - " var label = elements[i][1];" - " AddElement(name, label);" - " }" - "};" - "</script>"))); + SetTestUrlResponse(kDynamicForm); + ASSERT_NO_FATAL_FAILURE( + ui_test_utils::NavigateToURL(browser(), GetTestUrl())); // Dynamically construct the form. ASSERT_TRUE(content::ExecuteScript(GetWebContents(), "BuildForm();")); @@ -1626,8 +1689,9 @@ CreateTestProfile(); // Load the test page. - ASSERT_NO_FATAL_FAILURE(ui_test_utils::NavigateToURL( - browser(), GURL(std::string(kDataURIPrefix) + kTestShippingFormString))); + SetTestUrlResponse(kTestShippingFormString); + ASSERT_NO_FATAL_FAILURE( + ui_test_utils::NavigateToURL(browser(), GetTestUrl())); // Reload the page. content::WebContents* web_contents = GetWebContents(); @@ -1644,8 +1708,9 @@ CreateTestProfile(); // Load the test page. - ASSERT_NO_FATAL_FAILURE(ui_test_utils::NavigateToURL( - browser(), GURL(std::string(kDataURIPrefix) + kTestEventFormString))); + SetTestUrlResponse(kTestEventFormString); + ASSERT_NO_FATAL_FAILURE( + ui_test_utils::NavigateToURL(browser(), GetTestUrl())); // Invoke Autofill. TryBasicFormFill(); @@ -1750,49 +1815,51 @@ CreateTestProfile(); - GURL url(std::string(kDataURIPrefix) + - "<form action=\"http://www.example.com/\" method=\"POST\">" - "<label for=\"fn\">なまえ</label>" - " <input type=\"text\" id=\"fn\"" - " onfocus=\"domAutomationController.send(true)\"" - "><br>" - "<label for=\"ln\">みょうじ</label>" - " <input type=\"text\" id=\"ln\"><br>" - "<label for=\"a1\">Address line 1:</label>" - " <input type=\"text\" id=\"a1\"><br>" - "<label for=\"a2\">Address line 2:</label>" - " <input type=\"text\" id=\"a2\"><br>" - "<label for=\"ci\">City:</label>" - " <input type=\"text\" id=\"ci\"><br>" - "<label for=\"st\">State:</label>" - " <select id=\"st\">" - " <option value=\"\" selected=\"yes\">--</option>" - " <option value=\"CA\">California</option>" - " <option value=\"TX\">Texas</option>" - " </select><br>" - "<label for=\"z\">ZIP code:</label>" - " <input type=\"text\" id=\"z\"><br>" - "<label for=\"co\">Country:</label>" - " <select id=\"co\">" - " <option value=\"\" selected=\"yes\">--</option>" - " <option value=\"CA\">Canada</option>" - " <option value=\"US\">United States</option>" - " </select><br>" - "<label for=\"ph\">Phone number:</label>" - " <input type=\"text\" id=\"ph\"><br>" - "</form>" - // Add additional Japanese characters to ensure the translate bar - // will appear. - "我々は重要な、興味深いものになるが、時折状況が発生するため苦労や痛みは" - "彼にいくつかの素晴らしいを調達することができます。それから、いくつかの利"); + static const char kForm[] = + "<form action=\"http://www.example.com/\" method=\"POST\">" + "<label for=\"fn\">なまえ</label>" + " <input type=\"text\" id=\"fn\"" + " onfocus=\"domAutomationController.send(true)\"" + "><br>" + "<label for=\"ln\">みょうじ</label>" + " <input type=\"text\" id=\"ln\"><br>" + "<label for=\"a1\">Address line 1:</label>" + " <input type=\"text\" id=\"a1\"><br>" + "<label for=\"a2\">Address line 2:</label>" + " <input type=\"text\" id=\"a2\"><br>" + "<label for=\"ci\">City:</label>" + " <input type=\"text\" id=\"ci\"><br>" + "<label for=\"st\">State:</label>" + " <select id=\"st\">" + " <option value=\"\" selected=\"yes\">--</option>" + " <option value=\"CA\">California</option>" + " <option value=\"TX\">Texas</option>" + " </select><br>" + "<label for=\"z\">ZIP code:</label>" + " <input type=\"text\" id=\"z\"><br>" + "<label for=\"co\">Country:</label>" + " <select id=\"co\">" + " <option value=\"\" selected=\"yes\">--</option>" + " <option value=\"CA\">Canada</option>" + " <option value=\"US\">United States</option>" + " </select><br>" + "<label for=\"ph\">Phone number:</label>" + " <input type=\"text\" id=\"ph\"><br>" + "</form>" + // Add additional Japanese characters to ensure the translate bar + // will appear. + "我々は重要な、興味深いものになるが、時折状況が発生するため苦労や痛みは" + "彼にいくつかの素晴らしいを調達することができます。それから、いくつかの" + "利"; // Set up an observer to be able to wait for the bubble to be shown. content::Source<content::WebContents> source(GetWebContents()); content::WindowedNotificationObserver language_detected_signal( chrome::NOTIFICATION_TAB_LANGUAGE_DETERMINED, source); + SetTestUrlResponse(kForm); ASSERT_NO_FATAL_FAILURE( - ui_test_utils::NavigateToURL(browser(), url)); + ui_test_utils::NavigateToURL(browser(), GetTestUrl())); // Wait for the translate bubble to appear. language_detected_signal.Wait(); @@ -2054,8 +2121,9 @@ CreateTestProfile(); // Load the test page. - ASSERT_NO_FATAL_FAILURE(ui_test_utils::NavigateToURL( - browser(), GURL(std::string(kDataURIPrefix) + kTestShippingFormString))); + SetTestUrlResponse(kTestShippingFormString); + ASSERT_NO_FATAL_FAILURE( + ui_test_utils::NavigateToURL(browser(), GetTestUrl())); // Invoke Autofill: Start filling the first name field with "M" and wait for // the popup to be shown.
diff --git a/chrome/browser/autofill/autofill_server_browsertest.cc b/chrome/browser/autofill/autofill_server_browsertest.cc index 56cae23b..c043036 100644 --- a/chrome/browser/autofill/autofill_server_browsertest.cc +++ b/chrome/browser/autofill/autofill_server_browsertest.cc
@@ -8,6 +8,7 @@ #include "base/macros.h" #include "base/memory/ref_counted.h" #include "base/strings/utf_string_conversions.h" +#include "base/test/scoped_feature_list.h" #include "chrome/browser/autofill/personal_data_manager_factory.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/ui/browser.h" @@ -18,6 +19,7 @@ #include "components/autofill/core/browser/autofill_test_utils.h" #include "components/autofill/core/browser/personal_data_manager.h" #include "components/autofill/core/browser/personal_data_manager_observer.h" +#include "components/autofill/core/common/autofill_features.h" #include "content/public/test/browser_test_utils.h" #include "content/public/test/test_utils.h" #include "content/public/test/url_loader_interceptor.h" @@ -124,11 +126,27 @@ class AutofillServerTest : public InProcessBrowserTest { public: + void SetUp() override { + // Enable data-url support. + // TODO(crbug.com/894428) - fix this suite to use the embedded test server + // instead of data urls. + scoped_feature_list_.InitAndEnableFeature( + features::kAutofillAllowNonHttpActivation); + + // Note that features MUST be enabled/disabled before continuing with + // SetUp(); otherwise, the feature state doesn't propagate to the test + // browser instance. + InProcessBrowserTest::SetUp(); + } + void SetUpCommandLine(base::CommandLine* command_line) override { // Enable finch experiment for sending field metadata. command_line->AppendSwitchASCII( ::switches::kForceFieldTrials, "AutofillFieldMetadata/Enabled/"); } + + private: + base::test::ScopedFeatureList scoped_feature_list_; }; // Regression test for http://crbug.com/177419
diff --git a/chrome/browser/browser_process_platform_part_chromeos.cc b/chrome/browser/browser_process_platform_part_chromeos.cc index 5468dbb9..57e325b 100644 --- a/chrome/browser/browser_process_platform_part_chromeos.cc +++ b/chrome/browser/browser_process_platform_part_chromeos.cc
@@ -108,9 +108,12 @@ } void BrowserProcessPlatformPart::InitializeCrosComponentManager() { + if (using_testing_cros_component_manager_) + return; + DCHECK(!cros_component_manager_); cros_component_manager_ = - std::make_unique<component_updater::CrOSComponentManager>( + std::make_unique<component_updater::CrOSComponentInstaller>( component_updater::MetadataTable::Create( g_browser_process->local_state())); @@ -119,6 +122,9 @@ } void BrowserProcessPlatformPart::ShutdownCrosComponentManager() { + if (using_testing_cros_component_manager_) + return; + cros_component_manager_.reset(); }
diff --git a/chrome/browser/browser_process_platform_part_chromeos.h b/chrome/browser/browser_process_platform_part_chromeos.h index 692a4c48..b2f616d 100644 --- a/chrome/browser/browser_process_platform_part_chromeos.h +++ b/chrome/browser/browser_process_platform_part_chromeos.h
@@ -13,6 +13,8 @@ #include "base/sequence_checker.h" #include "chrome/browser/browser_process_platform_part_base.h" +class BrowserProcessPlatformPartTestApi; + namespace chromeos { class AccountManagerFactory; class ChromeSessionManager; @@ -121,6 +123,8 @@ chromeos::AccountManagerFactory* GetAccountManagerFactory(); private: + friend class BrowserProcessPlatformPartTestApi; + void CreateProfileHelper(); std::unique_ptr<chromeos::ChromeSessionManager> session_manager_; @@ -146,6 +150,9 @@ std::unique_ptr<ScopedKeepAlive> keep_alive_; + // Whether cros_component_manager_ has been initialized for test. Set by + // BrowserProcessPlatformPartTestApi. + bool using_testing_cros_component_manager_ = false; std::unique_ptr<component_updater::CrOSComponentManager> cros_component_manager_;
diff --git a/chrome/browser/chromeos/arc/input_method_manager/arc_input_method_manager_bridge.h b/chrome/browser/chromeos/arc/input_method_manager/arc_input_method_manager_bridge.h index 186621ce..959baeb 100644 --- a/chrome/browser/chromeos/arc/input_method_manager/arc_input_method_manager_bridge.h +++ b/chrome/browser/chromeos/arc/input_method_manager/arc_input_method_manager_bridge.h
@@ -42,6 +42,8 @@ virtual void SendFocus(mojom::InputConnectionPtr connection, mojom::TextInputStatePtr state) = 0; virtual void SendUpdateTextInputState(mojom::TextInputStatePtr state) = 0; + virtual void SendShowVirtualKeyboard() = 0; + virtual void SendHideVirtualKeyboard() = 0; }; } // namespace arc
diff --git a/chrome/browser/chromeos/arc/input_method_manager/arc_input_method_manager_bridge_impl.cc b/chrome/browser/chromeos/arc/input_method_manager/arc_input_method_manager_bridge_impl.cc index 512e7ed..a7e4bd87 100644 --- a/chrome/browser/chromeos/arc/input_method_manager/arc_input_method_manager_bridge_impl.cc +++ b/chrome/browser/chromeos/arc/input_method_manager/arc_input_method_manager_bridge_impl.cc
@@ -81,6 +81,30 @@ imm_instance->UpdateTextInputState(std::move(state)); } +void ArcInputMethodManagerBridgeImpl::SendShowVirtualKeyboard() { + auto* imm_instance = ARC_GET_INSTANCE_FOR_METHOD( + bridge_service_->input_method_manager(), ShowVirtualKeyboard); + if (!imm_instance) + return; + + if (!base::FeatureList::IsEnabled(kEnableInputMethodFeature)) + return; + + imm_instance->ShowVirtualKeyboard(); +} + +void ArcInputMethodManagerBridgeImpl::SendHideVirtualKeyboard() { + auto* imm_instance = ARC_GET_INSTANCE_FOR_METHOD( + bridge_service_->input_method_manager(), HideVirtualKeyboard); + if (!imm_instance) + return; + + if (!base::FeatureList::IsEnabled(kEnableInputMethodFeature)) + return; + + imm_instance->HideVirtualKeyboard(); +} + void ArcInputMethodManagerBridgeImpl::OnConnectionClosed() { delegate_->OnConnectionClosed(); }
diff --git a/chrome/browser/chromeos/arc/input_method_manager/arc_input_method_manager_bridge_impl.h b/chrome/browser/chromeos/arc/input_method_manager/arc_input_method_manager_bridge_impl.h index fa817c6d..ffcf826 100644 --- a/chrome/browser/chromeos/arc/input_method_manager/arc_input_method_manager_bridge_impl.h +++ b/chrome/browser/chromeos/arc/input_method_manager/arc_input_method_manager_bridge_impl.h
@@ -34,6 +34,8 @@ void SendFocus(mojom::InputConnectionPtr connection, mojom::TextInputStatePtr state) override; void SendUpdateTextInputState(mojom::TextInputStatePtr state) override; + void SendShowVirtualKeyboard() override; + void SendHideVirtualKeyboard() override; // ConnectionObserver<mojom::InputMethodManagerInstance> overrides: void OnConnectionClosed() override;
diff --git a/chrome/browser/chromeos/arc/input_method_manager/arc_input_method_manager_service.cc b/chrome/browser/chromeos/arc/input_method_manager/arc_input_method_manager_service.cc index 6fc830b..40658b5f 100644 --- a/chrome/browser/chromeos/arc/input_method_manager/arc_input_method_manager_service.cc +++ b/chrome/browser/chromeos/arc/input_method_manager/arc_input_method_manager_service.cc
@@ -28,6 +28,7 @@ #include "ui/base/ime/chromeos/extension_ime_util.h" #include "ui/base/ime/chromeos/input_method_util.h" #include "ui/base/ime/ime_bridge.h" +#include "ui/base/ime/input_method_observer.h" #include "ui/keyboard/keyboard_util.h" namespace arc { @@ -90,15 +91,16 @@ } // namespace -class ArcInputMethodManagerService::ArcProxyInputMethodObserver +class ArcInputMethodManagerService::InputMethodEngineObserver : public input_method::InputMethodEngineBase::Observer { public: - explicit ArcProxyInputMethodObserver(ArcInputMethodManagerService* owner) + explicit InputMethodEngineObserver(ArcInputMethodManagerService* owner) : owner_(owner) {} - ~ArcProxyInputMethodObserver() override = default; + ~InputMethodEngineObserver() override = default; // input_method::InputMethodEngineBase::Observer overrides: void OnActivate(const std::string& engine_id) override { + owner_->OnArcImeActivated(); // ash::Shell is not created in the unit tests. if (!ash::Shell::HasInstance()) return; @@ -117,9 +119,18 @@ void OnKeyEvent( const std::string& engine_id, const input_method::InputMethodEngineBase::KeyboardEvent& event, - ui::IMEEngineHandlerInterface::KeyEventDoneCallback key_data) override {} + ui::IMEEngineHandlerInterface::KeyEventDoneCallback key_data) override { + if (event.key == "HistoryBack") { + // Back button on the shelf is pressed. + owner_->imm_bridge_->SendHideVirtualKeyboard(); + std::move(key_data).Run(true); + return; + } + std::move(key_data).Run(false); + } void OnReset(const std::string& engine_id) override {} void OnDeactivated(const std::string& engine_id) override { + owner_->OnArcImeDeactivated(); // ash::Shell is not created in the unit tests. if (!ash::Shell::HasInstance()) return; @@ -135,7 +146,7 @@ const std::vector<gfx::Rect>& bounds) override { owner_->UpdateTextInputState(); } - bool IsInterestedInKeyEvent() const override { return false; } + bool IsInterestedInKeyEvent() const override { return true; } void OnSurroundingTextChanged(const std::string& engine_id, const std::string& text, int cursor_pos, @@ -157,7 +168,30 @@ private: ArcInputMethodManagerService* const owner_; - DISALLOW_COPY_AND_ASSIGN(ArcProxyInputMethodObserver); + DISALLOW_COPY_AND_ASSIGN(InputMethodEngineObserver); +}; + +class ArcInputMethodManagerService::InputMethodObserver + : public ui::InputMethodObserver { + public: + explicit InputMethodObserver(ArcInputMethodManagerService* owner) + : owner_(owner) {} + ~InputMethodObserver() override = default; + + // ui::InputMethodObserver overrides: + void OnFocus() override {} + void OnBlur() override {} + void OnCaretBoundsChanged(const ui::TextInputClient* client) override {} + void OnTextInputStateChanged(const ui::TextInputClient* client) override {} + void OnInputMethodDestroyed(const ui::InputMethod* input_method) override {} + void OnShowVirtualKeyboardIfEnabled() override { + owner_->imm_bridge_->SendShowVirtualKeyboard(); + } + + private: + ArcInputMethodManagerService* const owner_; + + DISALLOW_COPY_AND_ASSIGN(InputMethodObserver); }; class ArcInputMethodManagerService::TabletModeObserver @@ -203,13 +237,14 @@ proxy_ime_extension_id_( crx_file::id_util::GenerateId(kArcIMEProxyExtensionName)), proxy_ime_engine_(std::make_unique<chromeos::InputMethodEngine>()), - tablet_mode_observer_(std::make_unique<TabletModeObserver>(this)) { + tablet_mode_observer_(std::make_unique<TabletModeObserver>(this)), + input_method_observer_(std::make_unique<InputMethodObserver>(this)) { auto* imm = chromeos::input_method::InputMethodManager::Get(); imm->AddObserver(this); imm->AddImeMenuObserver(this); proxy_ime_engine_->Initialize( - std::make_unique<ArcProxyInputMethodObserver>(this), + std::make_unique<InputMethodEngineObserver>(this), proxy_ime_extension_id_.c_str(), profile_); // TabletModeClient should be already created here because it's created in @@ -586,4 +621,18 @@ manager->NotifyInputMethodExtensionAdded(proxy_ime_extension_id_); } +void ArcInputMethodManagerService::OnArcImeActivated() { + ui::InputMethod* input_method = + ui::IMEBridge::Get()->GetInputContextHandler()->GetInputMethod(); + if (input_method) + input_method->AddObserver(input_method_observer_.get()); +} + +void ArcInputMethodManagerService::OnArcImeDeactivated() { + ui::InputMethod* input_method = + ui::IMEBridge::Get()->GetInputContextHandler()->GetInputMethod(); + if (input_method) + input_method->RemoveObserver(input_method_observer_.get()); +} + } // namespace arc
diff --git a/chrome/browser/chromeos/arc/input_method_manager/arc_input_method_manager_service.h b/chrome/browser/chromeos/arc/input_method_manager/arc_input_method_manager_service.h index 315cf3a..c0c3d5a 100644 --- a/chrome/browser/chromeos/arc/input_method_manager/arc_input_method_manager_service.h +++ b/chrome/browser/chromeos/arc/input_method_manager/arc_input_method_manager_service.h
@@ -70,7 +70,8 @@ InputConnectionImpl* GetInputConnectionForTesting(); private: - class ArcProxyInputMethodObserver; + class InputMethodEngineObserver; + class InputMethodObserver; class TabletModeObserver; void EnableIme(const std::string& ime_id, bool enable); @@ -95,6 +96,10 @@ // Notifies InputMethodManager's observers of possible ARC IME state changes. void NotifyInputMethodManagerObservers(bool is_tablet_mode); + // Called by InputMethodEngineObserver. + void OnArcImeActivated(); + void OnArcImeDeactivated(); + Profile* const profile_; std::unique_ptr<ArcInputMethodManagerBridge> imm_bridge_; @@ -110,6 +115,8 @@ std::unique_ptr<TabletModeObserver> tablet_mode_observer_; + std::unique_ptr<InputMethodObserver> input_method_observer_; + DISALLOW_COPY_AND_ASSIGN(ArcInputMethodManagerService); };
diff --git a/chrome/browser/chromeos/arc/input_method_manager/arc_input_method_manager_service_unittest.cc b/chrome/browser/chromeos/arc/input_method_manager/arc_input_method_manager_service_unittest.cc index 98a1e23..81daec3 100644 --- a/chrome/browser/chromeos/arc/input_method_manager/arc_input_method_manager_service_unittest.cc +++ b/chrome/browser/chromeos/arc/input_method_manager/arc_input_method_manager_service_unittest.cc
@@ -206,11 +206,17 @@ last_text_input_state = state.Clone(); } + void SendShowVirtualKeyboard() override { + ++show_virtual_keyboard_calls_count_; + } + void SendHideVirtualKeyboard() override {} + std::vector<std::tuple<std::string, bool>> enable_ime_calls_; std::vector<std::string> switch_ime_to_calls_; int focus_calls_count_ = 0; int update_text_input_state_calls_count_ = 0; mojom::TextInputStatePtr last_text_input_state; + int show_virtual_keyboard_calls_count_ = 0; private: DISALLOW_COPY_AND_ASSIGN(TestInputMethodManagerBridge); @@ -669,14 +675,8 @@ ASSERT_EQ(1u, imm()->state()->added_input_method_extensions_.size()); ui::IMEEngineHandlerInterface* engine_handler = std::get<2>(imm()->state()->added_input_method_extensions_.at(0)); - // Enable it - ui::IMEBridge::Get()->SetCurrentEngineHandler(engine_handler); - engine_handler->Enable( - chromeos::extension_ime_util::GetComponentIDByInputMethodID( - std::get<1>(imm()->state()->added_input_method_extensions_.at(0)) - .at(0) - .id())); + // Set up mock input context. constexpr int test_context_id = 0; const ui::IMEEngineHandlerInterface::InputContext test_context{ test_context_id, @@ -687,8 +687,16 @@ true /* should_do_learning */}; ui::MockInputMethod mock_input_method(nullptr); TestIMEInputContextHandler test_context_handler(&mock_input_method); - ui::DummyTextInputClient dummy_text_input_client; + ui::DummyTextInputClient dummy_text_input_client(ui::TEXT_INPUT_TYPE_TEXT); ui::IMEBridge::Get()->SetInputContextHandler(&test_context_handler); + + // Enable the ARC IME. + ui::IMEBridge::Get()->SetCurrentEngineHandler(engine_handler); + engine_handler->Enable( + chromeos::extension_ime_util::GetComponentIDByInputMethodID( + std::get<1>(imm()->state()->added_input_method_extensions_.at(0)) + .at(0) + .id())); mock_input_method.SetFocusedTextInputClient(&dummy_text_input_client); ASSERT_EQ(0, bridge()->focus_calls_count_); @@ -737,14 +745,8 @@ ASSERT_EQ(1u, imm()->state()->added_input_method_extensions_.size()); ui::IMEEngineHandlerInterface* engine_handler = std::get<2>(imm()->state()->added_input_method_extensions_.at(0)); - // Enable it - ui::IMEBridge::Get()->SetCurrentEngineHandler(engine_handler); - engine_handler->Enable( - chromeos::extension_ime_util::GetComponentIDByInputMethodID( - std::get<1>(imm()->state()->added_input_method_extensions_.at(0)) - .at(0) - .id())); + // Set up mock input context. constexpr int test_context_id = 0; const ui::IMEEngineHandlerInterface::InputContext test_context{ test_context_id, @@ -757,6 +759,14 @@ TestIMEInputContextHandler test_context_handler(&mock_input_method); ui::DummyTextInputClient dummy_text_input_client(ui::TEXT_INPUT_TYPE_TEXT); ui::IMEBridge::Get()->SetInputContextHandler(&test_context_handler); + + // Enable the ARC IME. + ui::IMEBridge::Get()->SetCurrentEngineHandler(engine_handler); + engine_handler->Enable( + chromeos::extension_ime_util::GetComponentIDByInputMethodID( + std::get<1>(imm()->state()->added_input_method_extensions_.at(0)) + .at(0) + .id())); mock_input_method.SetFocusedTextInputClient(&dummy_text_input_client); engine_handler->FocusIn(test_context); @@ -880,4 +890,60 @@ EXPECT_TRUE(keyboard::IsKeyboardEnabled()); } +TEST_F(ArcInputMethodManagerServiceTest, ShowVirtualKeyboard) { + base::test::ScopedFeatureList feature; + feature.InitAndEnableFeature(kEnableInputMethodFeature); + ToggleTabletMode(true); + + // Adding one ARC IME. + { + const std::string android_ime_id = "test.arc.ime"; + const std::string display_name = "DisplayName"; + const std::string settings_url = "url_to_settings"; + mojom::ImeInfoPtr info = mojom::ImeInfo::New(); + info->ime_id = android_ime_id; + info->display_name = display_name; + info->enabled = false; + info->settings_url = settings_url; + + std::vector<mojom::ImeInfoPtr> info_array; + info_array.emplace_back(std::move(info)); + service()->OnImeInfoChanged(std::move(info_array)); + } + // The proxy IME engine should be added. + ASSERT_EQ(1u, imm()->state()->added_input_method_extensions_.size()); + ui::IMEEngineHandlerInterface* engine_handler = + std::get<2>(imm()->state()->added_input_method_extensions_.at(0)); + + // Set up mock input context. + constexpr int test_context_id = 0; + const ui::IMEEngineHandlerInterface::InputContext test_context{ + test_context_id, + ui::TEXT_INPUT_TYPE_TEXT, + ui::TEXT_INPUT_MODE_DEFAULT, + 0 /* flags */, + ui::TextInputClient::FOCUS_REASON_MOUSE, + true /* should_do_learning */}; + ui::MockInputMethod mock_input_method(nullptr); + TestIMEInputContextHandler test_context_handler(&mock_input_method); + ui::DummyTextInputClient dummy_text_input_client(ui::TEXT_INPUT_TYPE_TEXT); + ui::IMEBridge::Get()->SetInputContextHandler(&test_context_handler); + + // Enable the ARC IME. + ui::IMEBridge::Get()->SetCurrentEngineHandler(engine_handler); + engine_handler->Enable( + chromeos::extension_ime_util::GetComponentIDByInputMethodID( + std::get<1>(imm()->state()->added_input_method_extensions_.at(0)) + .at(0) + .id())); + + mock_input_method.SetFocusedTextInputClient(&dummy_text_input_client); + + EXPECT_EQ(0, bridge()->show_virtual_keyboard_calls_count_); + mock_input_method.ShowVirtualKeyboardIfEnabled(); + EXPECT_EQ(1, bridge()->show_virtual_keyboard_calls_count_); + ui::IMEBridge::Get()->SetInputContextHandler(nullptr); + ui::IMEBridge::Get()->SetCurrentEngineHandler(nullptr); +} + } // namespace arc
diff --git a/chrome/browser/chromeos/login/demo_mode/demo_extensions_external_loader_unittest.cc b/chrome/browser/chromeos/login/demo_mode/demo_extensions_external_loader_unittest.cc index 7b427fe..f51cf5d 100644 --- a/chrome/browser/chromeos/login/demo_mode/demo_extensions_external_loader_unittest.cc +++ b/chrome/browser/chromeos/login/demo_mode/demo_extensions_external_loader_unittest.cc
@@ -22,14 +22,17 @@ #include "base/run_loop.h" #include "base/values.h" #include "base/version.h" +#include "chrome/browser/browser_process.h" +#include "chrome/browser/browser_process_platform_part.h" #include "chrome/browser/chromeos/login/demo_mode/demo_session.h" #include "chrome/browser/chromeos/login/users/fake_chrome_user_manager.h" +#include "chrome/browser/component_updater/fake_cros_component_manager.h" #include "chrome/browser/extensions/external_provider_impl.h" #include "chrome/common/chrome_paths.h" +#include "chrome/test/base/browser_process_platform_part_test_api_chromeos.h" #include "chrome/test/base/testing_browser_process.h" #include "chrome/test/base/testing_profile.h" #include "chromeos/dbus/dbus_thread_manager.h" -#include "chromeos/dbus/fake_image_loader_client.h" #include "components/session_manager/core/session_manager.h" #include "components/user_manager/scoped_user_manager.h" #include "content/public/browser/notification_service.h" @@ -140,21 +143,19 @@ class DemoExtensionsExternalLoaderTest : public testing::Test { public: DemoExtensionsExternalLoaderTest() - : test_shared_loader_factory_( + : browser_process_platform_part_test_api_( + TestingBrowserProcess::GetGlobal()->platform_part()), + test_shared_loader_factory_( base::MakeRefCounted<network::WeakWrapperSharedURLLoaderFactory>( &test_url_loader_factory_)) {} ~DemoExtensionsExternalLoaderTest() override = default; void SetUp() override { + DBusThreadManager::Initialize(); DemoSession::SetDemoConfigForTesting(DemoSession::DemoModeConfig::kOnline); ASSERT_TRUE(offline_demo_resources_.CreateUniqueTempDir()); - - auto image_loader_client = std::make_unique<FakeImageLoaderClient>(); - image_loader_client_ = image_loader_client.get(); - DBusThreadManager::GetSetterForTesting()->SetImageLoaderClient( - std::move(image_loader_client)); session_manager_ = std::make_unique<session_manager::SessionManager>(); TestingBrowserProcess::GetGlobal()->SetSharedURLLoaderFactory( @@ -163,22 +164,17 @@ void TearDown() override { profile_.reset(); - - image_loader_client_ = nullptr; DBusThreadManager::Shutdown(); - DemoSession::ShutDownIfInitialized(); DemoSession::ResetDemoConfigForTesting(); + browser_process_platform_part_test_api_.ShutdownCrosComponentManager(); } protected: void InitializeSession(bool mount_demo_resources, bool wait_for_offline_resources_load) { - if (mount_demo_resources) { - image_loader_client_->SetMountPathForComponent( - DemoSession::kDemoModeResourcesComponentName, - offline_demo_resources_.GetPath()); - } + InitializeCrosComponentManager(mount_demo_resources); + ASSERT_TRUE(DemoSession::StartIfInDemoMode()); if (wait_for_offline_resources_load) @@ -187,6 +183,23 @@ profile_ = std::make_unique<TestingProfile>(); } + void InitializeCrosComponentManager(bool enable_demo_resources) { + auto cros_component_manager = + std::make_unique<component_updater::FakeCrOSComponentManager>(); + cros_component_manager->set_supported_components( + {DemoSession::kDemoModeResourcesComponentName}); + if (enable_demo_resources) { + cros_component_manager->ResetComponentState( + DemoSession::kDemoModeResourcesComponentName, + component_updater::FakeCrOSComponentManager::ComponentInfo( + component_updater::CrOSComponentManager::Error::NONE, + base::FilePath("/dev/null"), offline_demo_resources_.GetPath())); + } + + browser_process_platform_part_test_api_.InitializeCrosComponentManager( + std::move(cros_component_manager)); + } + void WaitForOfflineResourcesLoad() { base::RunLoop run_loop; DemoSession::Get()->EnsureOfflineResourcesLoaded(run_loop.QuitClosure()); @@ -249,8 +262,7 @@ private: content::TestBrowserThreadBundle thread_bundle_; - // Image loader client injected into, and owned by DBusThreadManager. - FakeImageLoaderClient* image_loader_client_ = nullptr; + BrowserProcessPlatformPartTestApi browser_process_platform_part_test_api_; base::ScopedTempDir offline_demo_resources_;
diff --git a/chrome/browser/chromeos/login/demo_mode/demo_session_unittest.cc b/chrome/browser/chromeos/login/demo_mode/demo_session_unittest.cc index 45d426c..80de2a5 100644 --- a/chrome/browser/chromeos/login/demo_mode/demo_session_unittest.cc +++ b/chrome/browser/chromeos/login/demo_mode/demo_session_unittest.cc
@@ -14,12 +14,17 @@ #include "base/files/file_path.h" #include "base/macros.h" #include "base/optional.h" +#include "chrome/browser/browser_process.h" +#include "chrome/browser/browser_process_platform_part.h" +#include "chrome/browser/component_updater/fake_cros_component_manager.h" +#include "chrome/test/base/browser_process_platform_part_test_api_chromeos.h" #include "chromeos/dbus/dbus_thread_manager.h" -#include "chromeos/dbus/fake_image_loader_client.h" #include "components/session_manager/core/session_manager.h" #include "content/public/test/test_browser_thread_bundle.h" #include "testing/gtest/include/gtest/gtest.h" +using component_updater::FakeCrOSComponentManager; + namespace chromeos { namespace { @@ -36,110 +41,65 @@ *value = true; } -class TestImageLoaderClient : public FakeImageLoaderClient { - public: - TestImageLoaderClient() = default; - ~TestImageLoaderClient() override = default; - - const std::list<std::string>& pending_loads() const { return pending_loads_; } - - // FakeImageLoaderClient: - void LoadComponentAtPath( - const std::string& name, - const base::FilePath& path, - DBusMethodCallback<base::FilePath> callback) override { - ASSERT_FALSE(path.empty()); - - components_[name].source = path; - components_[name].load_callbacks.emplace_back(std::move(callback)); - pending_loads_.push_back(name); - } - - bool FinishComponentLoad(const std::string& component_name, - const base::FilePath& mount_point) { - if (pending_loads_.empty() || pending_loads_.front() != component_name) - return false; - pending_loads_.pop_front(); - - components_[component_name].loaded = true; - RunPendingLoadCallback(component_name, mount_point); - return true; - } - - bool FailComponentLoad(const std::string& component_name) { - if (pending_loads_.empty() || pending_loads_.front() != component_name) - return false; - pending_loads_.pop_front(); - RunPendingLoadCallback(component_name, base::nullopt); - return true; - } - - bool ComponentLoadedFromPath(const std::string& name, - const base::FilePath& file_path) const { - const auto& component = components_.find(name); - if (component == components_.end()) - return false; - return component->second.loaded && component->second.source == file_path; - } - - private: - struct ComponentInfo { - ComponentInfo() = default; - ~ComponentInfo() = default; - - base::FilePath source; - bool loaded = false; - std::list<DBusMethodCallback<base::FilePath>> load_callbacks; - }; - - void RunPendingLoadCallback(const std::string& component_name, - base::Optional<base::FilePath> mount_point) { - DBusMethodCallback<base::FilePath> callback = - std::move(components_[component_name].load_callbacks.front()); - components_[component_name].load_callbacks.pop_front(); - - std::move(callback).Run(std::move(mount_point)); - } - - // Map containing known components. - std::map<std::string, ComponentInfo> components_; - - // List of components whose load has been requested. - std::list<std::string> pending_loads_; - - DISALLOW_COPY_AND_ASSIGN(TestImageLoaderClient); -}; - } // namespace class DemoSessionTest : public testing::Test { public: - DemoSessionTest() = default; + DemoSessionTest() + : browser_process_platform_part_test_api_( + g_browser_process->platform_part()) {} ~DemoSessionTest() override = default; void SetUp() override { + chromeos::DBusThreadManager::Initialize(); DemoSession::SetDemoConfigForTesting(DemoSession::DemoModeConfig::kOnline); - auto image_loader_client = std::make_unique<TestImageLoaderClient>(); - image_loader_client_ = image_loader_client.get(); - chromeos::DBusThreadManager::GetSetterForTesting()->SetImageLoaderClient( - std::move(image_loader_client)); + InitializeCrosComponentManager(); session_manager_ = std::make_unique<session_manager::SessionManager>(); } void TearDown() override { DemoSession::ShutDownIfInitialized(); DemoSession::ResetDemoConfigForTesting(); - image_loader_client_ = nullptr; + chromeos::DBusThreadManager::Shutdown(); + + cros_component_manager_ = nullptr; + browser_process_platform_part_test_api_.ShutdownCrosComponentManager(); } protected: - // Points to the image loader client passed to the test DBusTestManager. - TestImageLoaderClient* image_loader_client_ = nullptr; + bool FinishResourcesComponentLoad(const base::FilePath& mount_path) { + EXPECT_TRUE( + cros_component_manager_->HasPendingInstall(kOfflineResourcesComponent)); + EXPECT_FALSE( + cros_component_manager_->UpdateRequested(kOfflineResourcesComponent)); + + return cros_component_manager_->FinishLoadRequest( + kOfflineResourcesComponent, + FakeCrOSComponentManager::ComponentInfo( + component_updater::CrOSComponentManager::Error::NONE, + base::FilePath("/dev/null"), mount_path)); + } + + void InitializeCrosComponentManager() { + auto fake_cros_component_manager = + std::make_unique<FakeCrOSComponentManager>(); + fake_cros_component_manager->set_queue_load_requests(true); + fake_cros_component_manager->set_supported_components( + {kOfflineResourcesComponent}); + cros_component_manager_ = fake_cros_component_manager.get(); + + browser_process_platform_part_test_api_.InitializeCrosComponentManager( + std::move(fake_cros_component_manager)); + } + + FakeCrOSComponentManager* cros_component_manager_ = nullptr; content::TestBrowserThreadBundle thread_bundle_; std::unique_ptr<session_manager::SessionManager> session_manager_; private: + BrowserProcessPlatformPartTestApi browser_process_platform_part_test_api_; + DISALLOW_COPY_AND_ASSIGN(DemoSessionTest); }; @@ -157,13 +117,10 @@ ASSERT_TRUE(demo_session); EXPECT_FALSE(demo_session->offline_resources_loaded()); - EXPECT_EQ(std::list<std::string>({kOfflineResourcesComponent}), - image_loader_client_->pending_loads()); const base::FilePath component_mount_point = base::FilePath(kTestDemoModeResourcesMountPoint); - ASSERT_TRUE(image_loader_client_->FinishComponentLoad( - kOfflineResourcesComponent, component_mount_point)); + ASSERT_TRUE(FinishResourcesComponentLoad(component_mount_point)); EXPECT_TRUE(demo_session->offline_resources_loaded()); EXPECT_EQ(component_mount_point.AppendASCII(kDemoAppsImageFile), @@ -193,7 +150,8 @@ EXPECT_FALSE(DemoSession::StartIfInDemoMode()); EXPECT_FALSE(DemoSession::Get()); - EXPECT_EQ(std::list<std::string>(), image_loader_client_->pending_loads()); + EXPECT_FALSE( + cros_component_manager_->HasPendingInstall(kOfflineResourcesComponent)); } TEST_F(DemoSessionTest, StartIfInOfflineEnrolledDemoMode) { @@ -207,8 +165,8 @@ EXPECT_EQ(demo_session, DemoSession::Get()); EXPECT_FALSE(demo_session->offline_resources_loaded()); - EXPECT_EQ(std::list<std::string>({kOfflineResourcesComponent}), - image_loader_client_->pending_loads()); + EXPECT_FALSE( + cros_component_manager_->HasPendingInstall(kOfflineResourcesComponent)); } TEST_F(DemoSessionTest, PreloadOfflineResourcesIfInDemoMode) { @@ -220,13 +178,12 @@ EXPECT_FALSE(demo_session->offline_enrolled()); EXPECT_FALSE(demo_session->offline_resources_loaded()); - EXPECT_EQ(std::list<std::string>({kOfflineResourcesComponent}), - image_loader_client_->pending_loads()); const base::FilePath component_mount_point = base::FilePath(kTestDemoModeResourcesMountPoint); - ASSERT_TRUE(image_loader_client_->FinishComponentLoad( - kOfflineResourcesComponent, component_mount_point)); + ASSERT_TRUE(FinishResourcesComponentLoad(component_mount_point)); + EXPECT_FALSE( + cros_component_manager_->HasPendingInstall(kOfflineResourcesComponent)); EXPECT_FALSE(demo_session->started()); EXPECT_TRUE(demo_session->offline_resources_loaded()); @@ -240,7 +197,8 @@ DemoSession::SetDemoConfigForTesting(DemoSession::DemoModeConfig::kNone); DemoSession::PreloadOfflineResourcesIfInDemoMode(); EXPECT_FALSE(DemoSession::Get()); - EXPECT_EQ(std::list<std::string>(), image_loader_client_->pending_loads()); + EXPECT_FALSE( + cros_component_manager_->HasPendingInstall(kOfflineResourcesComponent)); } TEST_F(DemoSessionTest, PreloadOfflineResourcesIfInOfflineDemoMode) { @@ -253,8 +211,8 @@ EXPECT_TRUE(demo_session->offline_enrolled()); EXPECT_FALSE(demo_session->offline_resources_loaded()); - EXPECT_EQ(std::list<std::string>({kOfflineResourcesComponent}), - image_loader_client_->pending_loads()); + EXPECT_FALSE( + cros_component_manager_->HasPendingInstall(kOfflineResourcesComponent)); } TEST_F(DemoSessionTest, ShutdownResetsInstance) { @@ -279,13 +237,12 @@ EXPECT_TRUE(demo_session->started()); EXPECT_FALSE(demo_session->offline_resources_loaded()); - EXPECT_EQ(std::list<std::string>({kOfflineResourcesComponent}), - image_loader_client_->pending_loads()); const base::FilePath component_mount_point = base::FilePath(kTestDemoModeResourcesMountPoint); - ASSERT_TRUE(image_loader_client_->FinishComponentLoad( - kOfflineResourcesComponent, component_mount_point)); + ASSERT_TRUE(FinishResourcesComponentLoad(component_mount_point)); + EXPECT_FALSE( + cros_component_manager_->HasPendingInstall(kOfflineResourcesComponent)); EXPECT_TRUE(demo_session->started()); EXPECT_TRUE(demo_session->offline_resources_loaded()); @@ -298,13 +255,11 @@ TEST_F(DemoSessionTest, StartDemoSessionAfterPreloadingResources) { DemoSession::PreloadOfflineResourcesIfInDemoMode(); - EXPECT_EQ(std::list<std::string>({kOfflineResourcesComponent}), - image_loader_client_->pending_loads()); - const base::FilePath component_mount_point = base::FilePath(kTestDemoModeResourcesMountPoint); - ASSERT_TRUE(image_loader_client_->FinishComponentLoad( - kOfflineResourcesComponent, component_mount_point)); + ASSERT_TRUE(FinishResourcesComponentLoad(component_mount_point)); + EXPECT_FALSE( + cros_component_manager_->HasPendingInstall(kOfflineResourcesComponent)); DemoSession* demo_session = DemoSession::StartIfInDemoMode(); EXPECT_TRUE(demo_session->started()); @@ -314,7 +269,8 @@ EXPECT_EQ(component_mount_point.AppendASCII(kExternalExtensionsPrefsFile), demo_session->GetExternalExtensionsPrefsPath()); - EXPECT_EQ(std::list<std::string>(), image_loader_client_->pending_loads()); + EXPECT_FALSE( + cros_component_manager_->HasPendingInstall(kOfflineResourcesComponent)); } TEST_F(DemoSessionTest, EnsureOfflineResourcesLoadedAfterStart) { @@ -328,13 +284,11 @@ EXPECT_FALSE(callback_called); EXPECT_FALSE(demo_session->offline_resources_loaded()); - EXPECT_EQ(std::list<std::string>({kOfflineResourcesComponent}), - image_loader_client_->pending_loads()); - const base::FilePath component_mount_point = base::FilePath(kTestDemoModeResourcesMountPoint); - ASSERT_TRUE(image_loader_client_->FinishComponentLoad( - kOfflineResourcesComponent, component_mount_point)); + ASSERT_TRUE(FinishResourcesComponentLoad(component_mount_point)); + EXPECT_FALSE( + cros_component_manager_->HasPendingInstall(kOfflineResourcesComponent)); EXPECT_TRUE(callback_called); EXPECT_TRUE(demo_session->offline_resources_loaded()); @@ -347,18 +301,18 @@ TEST_F(DemoSessionTest, EnsureOfflineResourcesLoadedAfterOfflineResourceLoad) { DemoSession* demo_session = DemoSession::StartIfInDemoMode(); ASSERT_TRUE(demo_session); - EXPECT_EQ(std::list<std::string>({kOfflineResourcesComponent}), - image_loader_client_->pending_loads()); const base::FilePath component_mount_point = base::FilePath(kTestDemoModeResourcesMountPoint); - ASSERT_TRUE(image_loader_client_->FinishComponentLoad( - kOfflineResourcesComponent, component_mount_point)); + ASSERT_TRUE(FinishResourcesComponentLoad(component_mount_point)); + EXPECT_FALSE( + cros_component_manager_->HasPendingInstall(kOfflineResourcesComponent)); bool callback_called = false; demo_session->EnsureOfflineResourcesLoaded( base::BindOnce(&SetBoolean, &callback_called)); - EXPECT_EQ(std::list<std::string>(), image_loader_client_->pending_loads()); + EXPECT_FALSE( + cros_component_manager_->HasPendingInstall(kOfflineResourcesComponent)); EXPECT_TRUE(callback_called); EXPECT_TRUE(demo_session->offline_resources_loaded()); @@ -381,13 +335,11 @@ EXPECT_FALSE(callback_called); EXPECT_FALSE(demo_session->offline_resources_loaded()); - EXPECT_EQ(std::list<std::string>({kOfflineResourcesComponent}), - image_loader_client_->pending_loads()); - const base::FilePath component_mount_point = base::FilePath(kTestDemoModeResourcesMountPoint); - ASSERT_TRUE(image_loader_client_->FinishComponentLoad( - kOfflineResourcesComponent, component_mount_point)); + ASSERT_TRUE(FinishResourcesComponentLoad(component_mount_point)); + EXPECT_FALSE( + cros_component_manager_->HasPendingInstall(kOfflineResourcesComponent)); EXPECT_TRUE(callback_called); EXPECT_TRUE(demo_session->offline_resources_loaded()); @@ -418,13 +370,11 @@ EXPECT_FALSE(third_callback_called); EXPECT_FALSE(demo_session->offline_resources_loaded()); - EXPECT_EQ(std::list<std::string>({kOfflineResourcesComponent}), - image_loader_client_->pending_loads()); - const base::FilePath component_mount_point = base::FilePath(kTestDemoModeResourcesMountPoint); - ASSERT_TRUE(image_loader_client_->FinishComponentLoad( - kOfflineResourcesComponent, component_mount_point)); + ASSERT_TRUE(FinishResourcesComponentLoad(component_mount_point)); + EXPECT_FALSE( + cros_component_manager_->HasPendingInstall(kOfflineResourcesComponent)); EXPECT_TRUE(first_callback_called); EXPECT_TRUE(second_callback_called);
diff --git a/chrome/browser/chromeos/login/easy_unlock/easy_unlock_service_signin_chromeos.cc b/chrome/browser/chromeos/login/easy_unlock/easy_unlock_service_signin_chromeos.cc index 6772988..a92a59f 100644 --- a/chrome/browser/chromeos/login/easy_unlock/easy_unlock_service_signin_chromeos.cc +++ b/chrome/browser/chromeos/login/easy_unlock/easy_unlock_service_signin_chromeos.cc
@@ -346,7 +346,8 @@ bool EasyUnlockServiceSignin::IsAllowedInternal() const { return service_active_ && account_id_.is_valid() && !LoginState::Get()->IsUserLoggedIn() && - (pref_manager_ && pref_manager_->IsEasyUnlockAllowed()); + (pref_manager_ && pref_manager_->IsEasyUnlockAllowed() && + pref_manager_->IsChromeOSLoginAllowed()); } bool EasyUnlockServiceSignin::IsEnabled() const {
diff --git a/chrome/browser/chromeos/login/wizard_controller_browsertest.cc b/chrome/browser/chromeos/login/wizard_controller_browsertest.cc index d18e5483..db38043 100644 --- a/chrome/browser/chromeos/login/wizard_controller_browsertest.cc +++ b/chrome/browser/chromeos/login/wizard_controller_browsertest.cc
@@ -2393,8 +2393,9 @@ DISALLOW_COPY_AND_ASSIGN(WizardControllerDemoSetupDeviceDisabledTest); }; +// Flaky https://crbug.com/894384. IN_PROC_BROWSER_TEST_F(WizardControllerDemoSetupDeviceDisabledTest, - OnlineDemoSetup) { + DISABLED_OnlineDemoSetup) { CheckCurrentScreen(OobeScreen::SCREEN_OOBE_WELCOME); EXPECT_FALSE(DemoSetupController::IsOobeDemoSetupFlowInProgress()); WaitUntilJSIsReady();
diff --git a/chrome/browser/chromeos/smb_client/smb_service.cc b/chrome/browser/chromeos/smb_client/smb_service.cc index 9a01a0b..b889255 100644 --- a/chrome/browser/chromeos/smb_client/smb_service.cc +++ b/chrome/browser/chromeos/smb_client/smb_service.cc
@@ -121,6 +121,7 @@ user_prefs::PrefRegistrySyncable* registry) { registry->RegisterBooleanPref(prefs::kNetworkFileSharesAllowed, true); registry->RegisterBooleanPref(prefs::kNetBiosShareDiscoveryEnabled, true); + registry->RegisterBooleanPref(prefs::kNTLMShareAuthenticationEnabled, true); } void SmbService::Mount(const file_system_provider::MountOptions& options, @@ -187,7 +188,13 @@ return; } - const base::FilePath mount_path(share_finder_->GetResolvedUrl(parsed_url)); + // If using kerberos, the hostname should not be resolved since kerberos + // service tickets are keyed on hosname. + const base::FilePath mount_path = + use_chromad_kerberos + ? share_path + : base::FilePath(share_finder_->GetResolvedUrl(parsed_url)); + GetSmbProviderClient()->Mount( mount_path, workgroup, username, temp_file_manager_->WritePasswordToFile(password), @@ -292,7 +299,12 @@ return; } - const base::FilePath mount_path(share_finder_->GetResolvedUrl(parsed_url)); + // If using kerberos, the hostname should not be resolved since kerberos + // service tickets are keyed on hosname. + const base::FilePath mount_path = + is_kerberos_chromad + ? share_path + : base::FilePath(share_finder_->GetResolvedUrl(parsed_url)); // An empty password is passed to Remount to conform with the credentials API // which expects username & workgroup strings along with a password file
diff --git a/chrome/browser/component_updater/cros_component_installer_chromeos.cc b/chrome/browser/component_updater/cros_component_installer_chromeos.cc index 851ad68..52c4216 100644 --- a/chrome/browser/component_updater/cros_component_installer_chromeos.cc +++ b/chrome/browser/component_updater/cros_component_installer_chromeos.cc
@@ -104,8 +104,11 @@ } // namespace CrOSComponentInstallerPolicy::CrOSComponentInstallerPolicy( - const ComponentConfig& config) - : name_(config.name), env_version_(config.env_version) { + const ComponentConfig& config, + CrOSComponentInstaller* cros_component_installer) + : cros_component_installer_(cros_component_installer), + name_(config.name), + env_version_(config.env_version) { if (strlen(config.sha2hash) != crypto::kSHA256Length * 2) return; @@ -132,17 +135,13 @@ // TODO(xiaochu): remove after M66 ships to stable. https://crbug.com/792203 CleanUpOldInstalls(name_); - g_browser_process->platform_part() - ->cros_component_manager() - ->EmitInstalledSignal(GetName()); + cros_component_installer_->EmitInstalledSignal(GetName()); return update_client::CrxInstaller::Result(update_client::InstallError::NONE); } void CrOSComponentInstallerPolicy::OnCustomUninstall() { - g_browser_process->platform_part() - ->cros_component_manager() - ->UnregisterCompatiblePath(name_); + cros_component_installer_->UnregisterCompatiblePath(name_); chromeos::DBusThreadManager::Get()->GetImageLoaderClient()->UnmountComponent( name_, base::BindOnce(&LogCustomUninstall)); @@ -159,9 +158,7 @@ if (!IsCompatible(env_version_, min_env_version)) return; - g_browser_process->platform_part() - ->cros_component_manager() - ->RegisterCompatiblePath(GetName(), path); + cros_component_installer_->RegisterCompatiblePath(GetName(), path); } bool CrOSComponentInstallerPolicy::VerifyInstallation( @@ -205,20 +202,20 @@ env_version >= min_env_version; } -CrOSComponentManager::CrOSComponentManager( +CrOSComponentInstaller::CrOSComponentInstaller( std::unique_ptr<MetadataTable> metadata_table) : metadata_table_(std::move(metadata_table)) {} -CrOSComponentManager::~CrOSComponentManager() {} +CrOSComponentInstaller::~CrOSComponentInstaller() {} -void CrOSComponentManager::SetDelegate(Delegate* delegate) { +void CrOSComponentInstaller::SetDelegate(Delegate* delegate) { delegate_ = delegate; } -void CrOSComponentManager::Load(const std::string& name, - MountPolicy mount_policy, - UpdatePolicy update_policy, - LoadCallback load_callback) { +void CrOSComponentInstaller::Load(const std::string& name, + MountPolicy mount_policy, + UpdatePolicy update_policy, + LoadCallback load_callback) { if (!IsCompatible(name) || update_policy == UpdatePolicy::kForce) { // A compatible component is not installed, or forced update is requested. // Start registration and installation/update process. @@ -235,7 +232,7 @@ } } -bool CrOSComponentManager::Unload(const std::string& name) { +bool CrOSComponentInstaller::Unload(const std::string& name) { const ComponentConfig* config = FindConfig(name); if (!config) { // Component |name| does not exist. @@ -248,33 +245,35 @@ updater->UnregisterComponent(id); } -void CrOSComponentManager::RegisterInstalled() { +void CrOSComponentInstaller::RegisterInstalled() { base::PostTaskWithTraitsAndReplyWithResult( FROM_HERE, {base::MayBlock()}, base::BindOnce(GetInstalled), - base::BindOnce(&CrOSComponentManager::RegisterN, base::Unretained(this))); + base::BindOnce(&CrOSComponentInstaller::RegisterN, + base::Unretained(this))); } -void CrOSComponentManager::RegisterCompatiblePath(const std::string& name, - const base::FilePath& path) { +void CrOSComponentInstaller::RegisterCompatiblePath( + const std::string& name, + const base::FilePath& path) { compatible_components_[name] = path; } -void CrOSComponentManager::UnregisterCompatiblePath(const std::string& name) { +void CrOSComponentInstaller::UnregisterCompatiblePath(const std::string& name) { compatible_components_.erase(name); } -base::FilePath CrOSComponentManager::GetCompatiblePath( +base::FilePath CrOSComponentInstaller::GetCompatiblePath( const std::string& name) const { const auto it = compatible_components_.find(name); return it == compatible_components_.end() ? base::FilePath() : it->second; } -void CrOSComponentManager::EmitInstalledSignal(const std::string& component) { +void CrOSComponentInstaller::EmitInstalledSignal(const std::string& component) { if (delegate_) delegate_->EmitInstalledSignal(component); } -bool CrOSComponentManager::IsRegistered(const std::string& name) { +bool CrOSComponentInstaller::IsRegistered(const std::string& name) const { base::FilePath root; if (!base::PathService::Get(DIR_COMPONENT_USER, &root)) return false; @@ -282,19 +281,19 @@ return base::PathExists(root.Append(kComponentsRootPath).Append(name)); } -void CrOSComponentManager::Register(ComponentUpdateService* cus, - const ComponentConfig& config, - base::OnceClosure register_callback) { +void CrOSComponentInstaller::Register(ComponentUpdateService* cus, + const ComponentConfig& config, + base::OnceClosure register_callback) { auto installer = base::MakeRefCounted<ComponentInstaller>( - std::make_unique<CrOSComponentInstallerPolicy>(config)); + std::make_unique<CrOSComponentInstallerPolicy>(config, this)); installer->Register(cus, std::move(register_callback)); } -void CrOSComponentManager::Install(ComponentUpdateService* cus, - const std::string& name, - UpdatePolicy update_policy, - MountPolicy mount_policy, - LoadCallback load_callback) { +void CrOSComponentInstaller::Install(ComponentUpdateService* cus, + const std::string& name, + UpdatePolicy update_policy, + MountPolicy mount_policy, + LoadCallback load_callback) { const ComponentConfig* config = FindConfig(name); if (!config) { base::ThreadTaskRunnerHandle::Get()->PostTask( @@ -306,14 +305,14 @@ Register(cus, *config, base::BindOnce( - &CrOSComponentManager::StartInstall, base::Unretained(this), cus, - name, GenerateId(config->sha2hash), update_policy, - base::BindOnce(&CrOSComponentManager::FinishInstall, + &CrOSComponentInstaller::StartInstall, base::Unretained(this), + cus, name, GenerateId(config->sha2hash), update_policy, + base::BindOnce(&CrOSComponentInstaller::FinishInstall, base::Unretained(this), name, mount_policy, std::move(load_callback)))); } -void CrOSComponentManager::StartInstall( +void CrOSComponentInstaller::StartInstall( ComponentUpdateService* cus, const std::string& name, const std::string& id, @@ -337,10 +336,10 @@ std::move(install_callback)); } -void CrOSComponentManager::FinishInstall(const std::string& name, - MountPolicy mount_policy, - LoadCallback load_callback, - update_client::Error error) { +void CrOSComponentInstaller::FinishInstall(const std::string& name, + MountPolicy mount_policy, + LoadCallback load_callback, + update_client::Error error) { if (error != update_client::Error::NONE) { base::ThreadTaskRunnerHandle::Get()->PostTask( FROM_HERE, @@ -355,8 +354,8 @@ } } -void CrOSComponentManager::LoadInternal(const std::string& name, - LoadCallback load_callback) { +void CrOSComponentInstaller::LoadInternal(const std::string& name, + LoadCallback load_callback) { const base::FilePath path = GetCompatiblePath(name); // path is empty if no compatible component is available to load. if (!path.empty()) { @@ -364,7 +363,7 @@ ->GetImageLoaderClient() ->LoadComponentAtPath( name, path, - base::BindOnce(&CrOSComponentManager::FinishLoad, + base::BindOnce(&CrOSComponentInstaller::FinishLoad, base::Unretained(this), std::move(load_callback), base::TimeTicks::Now(), name)); } else { @@ -376,10 +375,10 @@ } } -void CrOSComponentManager::FinishLoad(LoadCallback load_callback, - const base::TimeTicks start_time, - const std::string& name, - base::Optional<base::FilePath> result) { +void CrOSComponentInstaller::FinishLoad(LoadCallback load_callback, + const base::TimeTicks start_time, + const std::string& name, + base::Optional<base::FilePath> result) { // Report component image mount time. UMA_HISTOGRAM_LONG_TIMES("ComponentUpdater.ChromeOS.MountTime", base::TimeTicks::Now() - start_time); @@ -396,7 +395,7 @@ } } -void CrOSComponentManager::RegisterN( +void CrOSComponentInstaller::RegisterN( const std::vector<ComponentConfig>& configs) { DCHECK_CURRENTLY_ON(content::BrowserThread::UI); ComponentUpdateService* updater = g_browser_process->component_updater(); @@ -405,7 +404,7 @@ } } -bool CrOSComponentManager::IsCompatible(const std::string& name) const { +bool CrOSComponentInstaller::IsCompatible(const std::string& name) const { return compatible_components_.count(name) > 0; }
diff --git a/chrome/browser/component_updater/cros_component_installer_chromeos.h b/chrome/browser/component_updater/cros_component_installer_chromeos.h index ece47580..01b95216 100644 --- a/chrome/browser/component_updater/cros_component_installer_chromeos.h +++ b/chrome/browser/component_updater/cros_component_installer_chromeos.h
@@ -12,6 +12,7 @@ #include "base/containers/flat_map.h" #include "base/gtest_prod_util.h" #include "base/optional.h" +#include "chrome/browser/component_updater/cros_component_manager.h" #include "components/component_updater/component_installer.h" #include "components/component_updater/component_updater_service.h" #include "components/update_client/update_client.h" @@ -20,6 +21,7 @@ class ComponentUpdateService; class MetadataTable; +class CrOSComponentInstaller; struct ComponentConfig { const char* name; @@ -29,7 +31,9 @@ class CrOSComponentInstallerPolicy : public ComponentInstallerPolicy { public: - explicit CrOSComponentInstallerPolicy(const ComponentConfig& config); + CrOSComponentInstallerPolicy( + const ComponentConfig& config, + CrOSComponentInstaller* cros_component_installer); ~CrOSComponentInstallerPolicy() override; private: @@ -60,6 +64,8 @@ virtual bool IsCompatible(const std::string& env_version_str, const std::string& min_env_version_str); + CrOSComponentInstaller* const cros_component_installer_; + const std::string name_; const std::string env_version_; std::vector<uint8_t> sha2_hash_; @@ -68,86 +74,31 @@ }; // This class contains functions used to register and install a component. -class CrOSComponentManager { +class CrOSComponentInstaller : public CrOSComponentManager { public: - // Error needs to be consistent with CrosComponentManagerError in - // src/tools/metrics/histograms/enums.xml. - enum class Error { - NONE = 0, - UNKNOWN_COMPONENT = 1, // Component requested does not exist. - INSTALL_FAILURE = 2, // update_client fails to install component. - MOUNT_FAILURE = 3, // Component can not be mounted. - COMPATIBILITY_CHECK_FAILED = 4, // Compatibility check failed. - ERROR_MAX - }; - // LoadCallback will always return the load result in |error|. If used in - // conjunction with the |kMount| policy below, return the mounted FilePath in - // |path|, or an empty |path| otherwise. - using LoadCallback = - base::OnceCallback<void(Error error, const base::FilePath& path)>; - // Policy on mount operation. - enum class MountPolicy { - // Mount the component if installed. - kMount, - // Skip the mount operation. - kDontMount, - }; - // Policy on update operation. - enum class UpdatePolicy { - // Force component update. - kForce, - // Do not update if a compatible component is installed. - kDontForce, - // Do not run updater, even if a compatible component is not installed at - // the moment. - kSkip - }; + explicit CrOSComponentInstaller( + std::unique_ptr<MetadataTable> metadata_table); + ~CrOSComponentInstaller() override; - class Delegate { - public: - virtual ~Delegate() {} - // Broadcasts a D-Bus signal for a successful component installation. - virtual void EmitInstalledSignal(const std::string& component) = 0; - }; - - explicit CrOSComponentManager(std::unique_ptr<MetadataTable> metadata_table); - ~CrOSComponentManager(); - - void SetDelegate(Delegate* delegate); - - // Installs a component and keeps it up-to-date. - // The |load_callback| is run on the calling thread. + // CrOSComponentManager: + void SetDelegate(Delegate* delegate) override; void Load(const std::string& name, MountPolicy mount_policy, UpdatePolicy update_policy, - LoadCallback load_callback); - - // Stops updating and removes a component. - // Returns true if the component was successfully unloaded - // or false if it couldn't be unloaded or already wasn't loaded. - bool Unload(const std::string& name); - - // Register all installed components. - void RegisterInstalled(); - - // Saves the name and install path of a compatible component. + LoadCallback load_callback) override; + bool Unload(const std::string& name) override; void RegisterCompatiblePath(const std::string& name, - const base::FilePath& path); + const base::FilePath& path) override; + void RegisterInstalled() override; - // Removes the name and install path entry of a component. - void UnregisterCompatiblePath(const std::string& name); - - // Returns installed path of a compatible component given |name|. Returns an - // empty path if the component isn't compatible. - base::FilePath GetCompatiblePath(const std::string& name) const; + void UnregisterCompatiblePath(const std::string& name) override; + base::FilePath GetCompatiblePath(const std::string& name) const override; + bool IsRegistered(const std::string& name) const override; // Called when a component is installed/updated. // Broadcasts a D-Bus signal for a successful component installation. void EmitInstalledSignal(const std::string& component); - // Returns true if any previously registered version of a component exists, - // even if it is incompatible. - bool IsRegistered(const std::string& name); private: FRIEND_TEST_ALL_PREFIXES(CrOSComponentInstallerTest, RegisterComponent); @@ -206,12 +157,12 @@ base::flat_map<std::string, base::FilePath> compatible_components_; // A weak pointer to a Delegate for emitting D-Bus signal. - Delegate* delegate_; + Delegate* delegate_ = nullptr; // Table storing metadata (installs, usage, etc.). std::unique_ptr<MetadataTable> metadata_table_; - DISALLOW_COPY_AND_ASSIGN(CrOSComponentManager); + DISALLOW_COPY_AND_ASSIGN(CrOSComponentInstaller); }; } // namespace component_updater
diff --git a/chrome/browser/component_updater/cros_component_installer_chromeos_unittest.cc b/chrome/browser/component_updater/cros_component_installer_chromeos_unittest.cc index eace0e9..1ad087e 100644 --- a/chrome/browser/component_updater/cros_component_installer_chromeos_unittest.cc +++ b/chrome/browser/component_updater/cros_component_installer_chromeos_unittest.cc
@@ -47,14 +47,14 @@ class MockCrOSComponentInstallerPolicy : public CrOSComponentInstallerPolicy { public: explicit MockCrOSComponentInstallerPolicy(const ComponentConfig& config) - : CrOSComponentInstallerPolicy(config) {} + : CrOSComponentInstallerPolicy(config, nullptr) {} MOCK_METHOD2(IsCompatible, bool(const std::string& env_version_str, const std::string& min_env_version_str)); }; TEST_F(CrOSComponentInstallerTest, CompatibleCrOSComponent) { - component_updater::CrOSComponentManager cros_component_manager(nullptr); + component_updater::CrOSComponentInstaller cros_component_manager(nullptr); const std::string kComponent = "a"; EXPECT_FALSE(cros_component_manager.IsCompatible(kComponent)); @@ -94,7 +94,7 @@ TEST_F(CrOSComponentInstallerTest, IsCompatibleOrNot) { ComponentConfig config{"", "", ""}; - CrOSComponentInstallerPolicy policy(config); + CrOSComponentInstallerPolicy policy(config, nullptr); EXPECT_TRUE(policy.IsCompatible("1.0", "1.0")); EXPECT_TRUE(policy.IsCompatible("1.1", "1.0")); EXPECT_FALSE(policy.IsCompatible("1.0", "1.1")); @@ -111,7 +111,7 @@ "star-cups-driver", "1.1", "6d24de30f671da5aee6d463d9e446cafe9ddac672800a9defe86877dcde6c466"}; EXPECT_CALL(*cus, RegisterComponent(testing::_)).Times(1); - component_updater::CrOSComponentManager cros_component_manager(nullptr); + component_updater::CrOSComponentInstaller cros_component_manager(nullptr); cros_component_manager.Register(cus.get(), config, base::OnceClosure()); RunUntilIdle(); }
diff --git a/chrome/browser/component_updater/cros_component_manager.h b/chrome/browser/component_updater/cros_component_manager.h new file mode 100644 index 0000000..36e0914 --- /dev/null +++ b/chrome/browser/component_updater/cros_component_manager.h
@@ -0,0 +1,101 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_COMPONENT_UPDATER_CROS_COMPONENT_MANAGER_H_ +#define CHROME_BROWSER_COMPONENT_UPDATER_CROS_COMPONENT_MANAGER_H_ + +#include <string> + +#include "base/callback_forward.h" + +namespace base { +class FilePath; +} + +namespace component_updater { + +// This class contains functions used to register and install a component. +class CrOSComponentManager { + public: + // Error needs to be consistent with CrosComponentManagerError in + // src/tools/metrics/histograms/enums.xml. + enum class Error { + NONE = 0, + UNKNOWN_COMPONENT = 1, // Component requested does not exist. + INSTALL_FAILURE = 2, // update_client fails to install component. + MOUNT_FAILURE = 3, // Component can not be mounted. + COMPATIBILITY_CHECK_FAILED = 4, // Compatibility check failed. + ERROR_MAX + }; + + // Policy on mount operation. + enum class MountPolicy { + // Mount the component if installed. + kMount, + // Skip the mount operation. + kDontMount, + }; + + // Policy on update operation. + enum class UpdatePolicy { + // Force component update. + kForce, + // Do not update if a compatible component is installed. + kDontForce, + // Do not run updater, even if a compatible component is not installed at + // the moment. + kSkip + }; + + // LoadCallback will always return the load result in |error|. If used in + // conjunction with the |kMount| policy below, return the mounted FilePath in + // |path|, or an empty |path| otherwise. + using LoadCallback = + base::OnceCallback<void(Error error, const base::FilePath& path)>; + + class Delegate { + public: + virtual ~Delegate() {} + // Broadcasts a D-Bus signal for a successful component installation. + virtual void EmitInstalledSignal(const std::string& component) = 0; + }; + + virtual ~CrOSComponentManager() = default; + + virtual void SetDelegate(Delegate* delegate) = 0; + + // Installs a component and keeps it up-to-date. + // The |load_callback| is run on the calling thread. + virtual void Load(const std::string& name, + MountPolicy mount_policy, + UpdatePolicy update_policy, + LoadCallback load_callback) = 0; + + // Stops updating and removes a component. + // Returns true if the component was successfully unloaded + // or false if it couldn't be unloaded or already wasn't loaded. + virtual bool Unload(const std::string& name) = 0; + + // Saves the name and install path of a compatible component. + virtual void RegisterCompatiblePath(const std::string& name, + const base::FilePath& path) = 0; + + // Removes the name and install path entry of a component. + virtual void UnregisterCompatiblePath(const std::string& name) = 0; + + // Returns installed path of a compatible component given |name|. Returns an + // empty path if the component isn't compatible. + virtual base::FilePath GetCompatiblePath(const std::string& name) const = 0; + + // Returns true if any previously registered version of a component exists, + // even if it is incompatible. + virtual bool IsRegistered(const std::string& name) const = 0; + + // Register all installed components. + virtual void RegisterInstalled() = 0; +}; + +} // namespace component_updater + +#endif // CHROME_BROWSER_COMPONENT_UPDATER_CROS_COMPONENT_MANAGER_H_
diff --git a/chrome/browser/component_updater/fake_cros_component_manager.cc b/chrome/browser/component_updater/fake_cros_component_manager.cc new file mode 100644 index 0000000..20d71595 --- /dev/null +++ b/chrome/browser/component_updater/fake_cros_component_manager.cc
@@ -0,0 +1,216 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/component_updater/fake_cros_component_manager.h" + +#include <utility> + +#include "base/bind.h" +#include "base/callback.h" +#include "base/files/file_path.h" +#include "base/logging.h" +#include "base/threading/sequenced_task_runner_handle.h" + +namespace component_updater { + +FakeCrOSComponentManager::ComponentInfo::ComponentInfo( + Error load_response, + const base::FilePath& install_path, + const base::FilePath& mount_path) + : load_response(load_response), + install_path(install_path), + mount_path(mount_path) { + // If component load fails, neither install nor mount path should be set. + DCHECK(load_response == Error::NONE || + (install_path.empty() && mount_path.empty())); + // Component should have install path set if it's expected to be loaded. + DCHECK(load_response != Error::NONE || !install_path.empty()); +} + +FakeCrOSComponentManager::ComponentInfo::~ComponentInfo() = default; + +FakeCrOSComponentManager::FakeCrOSComponentManager() = default; + +FakeCrOSComponentManager::~FakeCrOSComponentManager() = default; + +bool FakeCrOSComponentManager::FinishLoadRequest( + const std::string& name, + const ComponentInfo& component_info) { + if (!pending_loads_.count(name) || pending_loads_[name].empty()) { + LOG(ERROR) << "No pending load for " << name; + return false; + } + + auto& pending_load = pending_loads_[name].front(); + FinishComponentLoad(name, pending_load.mount_requested, component_info); + + LoadCallback callback = std::move(pending_load.callback); + pending_loads_[name].pop_front(); + + std::move(callback).Run(component_info.load_response, + component_info.load_response == Error::NONE + ? component_info.mount_path + : base::FilePath()); + return true; +} + +bool FakeCrOSComponentManager::ResetComponentState(const std::string& name, + const ComponentInfo& state) { + if (!supported_components_.count(name)) + return false; + + installed_components_.erase(name); + mounted_components_.erase(name); + + component_infos_.erase(name); + component_infos_.emplace( + name, + ComponentInfo(state.load_response, state.install_path, state.mount_path)); + return true; +} + +bool FakeCrOSComponentManager::HasPendingInstall( + const std::string& name) const { + DCHECK(queue_load_requests_); + + const auto& it = pending_loads_.find(name); + return it != pending_loads_.end() && !it->second.empty(); +} + +bool FakeCrOSComponentManager::UpdateRequested(const std::string& name) const { + DCHECK(queue_load_requests_); + + const auto& it = pending_loads_.find(name); + return it != pending_loads_.end() && !it->second.empty() && + it->second.front().needs_update; +} + +void FakeCrOSComponentManager::SetDelegate(Delegate* delegate) { + // No-op, not used by the fake. +} + +void FakeCrOSComponentManager::Load(const std::string& name, + MountPolicy mount_policy, + UpdatePolicy update_policy, + LoadCallback load_callback) { + if (!supported_components_.count(name)) { + base::SequencedTaskRunnerHandle::Get()->PostTask( + FROM_HERE, base::BindOnce(std::move(load_callback), + Error::UNKNOWN_COMPONENT, base::FilePath())); + return; + } + + bool needs_update = update_policy == UpdatePolicy::kForce || + (!installed_components_.count(name) && + update_policy != UpdatePolicy::kSkip); + + // The request has to be handled if the component is not yet installed, or it + // requires immediate update. + if (needs_update || !installed_components_.count(name)) { + HandlePendingRequest(name, mount_policy == MountPolicy::kMount, + needs_update, std::move(load_callback)); + return; + } + + // Handle request if the component has yet to be mounted - e.g. if previous + // loads installed the component without mounting it. + if (!mounted_components_.count(name) && mount_policy == MountPolicy::kMount) { + HandlePendingRequest(name, true /*mount_requested*/, false /*needs_update*/, + std::move(load_callback)); + return; + } + + // The component has been prevoiusly installed, and mounted as required by + // this load request - run the callback according to the existing state. + base::SequencedTaskRunnerHandle::Get()->PostTask( + FROM_HERE, base::BindOnce(std::move(load_callback), Error::NONE, + mount_policy == MountPolicy::kMount + ? mounted_components_[name] + : base::FilePath())); +} + +bool FakeCrOSComponentManager::Unload(const std::string& name) { + registered_components_.erase(name); + mounted_components_.erase(name); + installed_components_.erase(name); + return true; +} + +void FakeCrOSComponentManager::RegisterCompatiblePath( + const std::string& name, + const base::FilePath& path) { + installed_components_[name] = path; +} + +void FakeCrOSComponentManager::UnregisterCompatiblePath( + const std::string& name) { + installed_components_.erase(name); +} + +base::FilePath FakeCrOSComponentManager::GetCompatiblePath( + const std::string& name) const { + const auto& it = installed_components_.find(name); + if (it == installed_components_.end()) + return base::FilePath(); + return it->second; +} + +bool FakeCrOSComponentManager::IsRegistered(const std::string& name) const { + return registered_components_.count(name); +} + +void FakeCrOSComponentManager::RegisterInstalled() { + NOTIMPLEMENTED(); +} + +FakeCrOSComponentManager::LoadRequest::LoadRequest(bool mount_requested, + bool needs_update, + LoadCallback callback) + : mount_requested(mount_requested), + needs_update(needs_update), + callback(std::move(callback)) {} + +FakeCrOSComponentManager::LoadRequest::~LoadRequest() = default; + +void FakeCrOSComponentManager::HandlePendingRequest(const std::string& name, + bool mount_requested, + bool needs_update, + LoadCallback callback) { + if (queue_load_requests_) { + pending_loads_[name].emplace_back(mount_requested, needs_update, + std::move(callback)); + return; + } + + const auto& component_info = component_infos_.find(name); + if (component_info == component_infos_.end()) { + base::SequencedTaskRunnerHandle::Get()->PostTask( + FROM_HERE, base::BindOnce(std::move(callback), Error::INSTALL_FAILURE, + base::FilePath())); + return; + } + + FinishComponentLoad(name, mount_requested, component_info->second); + + base::SequencedTaskRunnerHandle::Get()->PostTask( + FROM_HERE, + base::BindOnce(std::move(callback), component_info->second.load_response, + component_info->second.mount_path)); +} + +void FakeCrOSComponentManager::FinishComponentLoad( + const std::string& name, + bool mount_requested, + const ComponentInfo& component_info) { + registered_components_.insert(name); + if (component_info.load_response != Error::NONE) + return; + + DCHECK_EQ(mount_requested, !component_info.mount_path.empty()); + installed_components_[name] = component_info.install_path; + if (mount_requested) + mounted_components_[name] = component_info.mount_path; +} + +} // namespace component_updater
diff --git a/chrome/browser/component_updater/fake_cros_component_manager.h b/chrome/browser/component_updater/fake_cros_component_manager.h new file mode 100644 index 0000000..2be89ab6 --- /dev/null +++ b/chrome/browser/component_updater/fake_cros_component_manager.h
@@ -0,0 +1,159 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_COMPONENT_UPDATER_FAKE_CROS_COMPONENT_MANAGER_H_ +#define CHROME_BROWSER_COMPONENT_UPDATER_FAKE_CROS_COMPONENT_MANAGER_H_ + +#include <list> +#include <map> +#include <memory> +#include <set> +#include <string> + +#include "base/callback.h" +#include "base/files/file_path.h" +#include "base/macros.h" +#include "chrome/browser/component_updater/cros_component_manager.h" + +namespace component_updater { + +// This fake implementation of cros component manager. Intended to be used in +// tests to abstract away the cros component manager dependency on imageloader +// and component updater services, and local file system. +class FakeCrOSComponentManager : public CrOSComponentManager { + public: + // Information about how fake component manager should "load" a component. + struct ComponentInfo { + ComponentInfo(Error load_response, + const base::FilePath& install_path, + const base::FilePath& mount_path); + ~ComponentInfo(); + + // The status load requests for the component should produce. + Error load_response; + + // The local path where the fake component manager thinks the component is + // installed. + base::FilePath install_path; + + // The path where the fake component manager thinks the component is + // mounted. + base::FilePath mount_path; + }; + + FakeCrOSComponentManager(); + ~FakeCrOSComponentManager() override; + + void set_queue_load_requests(bool queue_load_requests) { + queue_load_requests_ = queue_load_requests; + } + void set_supported_components(const std::set<std::string>& components) { + supported_components_ = components; + } + void set_registered_components(const std::set<std::string>& components) { + registered_components_ = components; + } + + // Finishes a queued component load request. Should be used only if + // |queue_load_requests_| is set. + bool FinishLoadRequest(const std::string& name, const ComponentInfo& state); + + // If the component is "loaded", clears the recorded install and mount paths, + // and sets the info about how future load requests for the component should + // be handled. + bool ResetComponentState(const std::string& name, const ComponentInfo& state); + + // Whether any component loads are pending. Expected to be used only if + // |queue_load_requests_| is set. + bool HasPendingInstall(const std::string& name) const; + + // Whether the next pending component load requests triggers immediate + // component update request. Expected to be used only if + // |queue_load_requests_| is set. + bool UpdateRequested(const std::string& name) const; + + // CrOSComponentManager: + void SetDelegate(Delegate* delegate) override; + void Load(const std::string& name, + MountPolicy mount_policy, + UpdatePolicy update_policy, + LoadCallback load_callback) override; + bool Unload(const std::string& name) override; + void RegisterCompatiblePath(const std::string& name, + const base::FilePath& path) override; + void UnregisterCompatiblePath(const std::string& name) override; + base::FilePath GetCompatiblePath(const std::string& name) const override; + bool IsRegistered(const std::string& name) const override; + void RegisterInstalled() override; + + private: + // Describes pending component load request. + struct LoadRequest { + LoadRequest(bool mount_requested, bool needs_update, LoadCallback callback); + ~LoadRequest(); + + // Whether the component should be mounted as part of the load request. + bool mount_requested; + + // Whether the request should start immediate component update check. + bool needs_update; + + // The load request callback. + LoadCallback callback; + }; + + // Handles a load request for a component, either by queueing it (if + // queue_load_requests_ is set), or setting the new component state depending + // on component_infos_. + // |name|: the component name. + // |mount_requested|: whether the component mount was requested as part of the + // load request. + // |needs_update|: whether the load request triggers immediate update attempt. + // |callback|: to be called when the load request finishes. + void HandlePendingRequest(const std::string& name, + bool mount_requested, + bool needs_update, + LoadCallback callback); + // Updates the fake component loader state on a successful component load + // request. + // |name|: the component name. + // |mount_requested|: whether the component should be mounted. + // |component_info|: the component's load information. + void FinishComponentLoad(const std::string& name, + bool mount_requested, + const ComponentInfo& component_info); + + // Whether the load requests should be queued up, and not handled immediately. + // When this is set, component load requests should be completed using + // FinishLoadRequest(). + bool queue_load_requests_ = false; + + // Set of components that can be handled by this component manager. + std::set<std::string> supported_components_; + + // Set of components registered with this component manager - used primarily + // by IsRegistered() implementation. + std::set<std::string> registered_components_; + + // The component information registered using ResetComponentInfo() - used to + // handle component load requests when queue_load_requests_ is not set. + std::map<std::string, ComponentInfo> component_infos_; + + // List of pending component load requests per component. Used only if + // queue_load_requests_ is set. + std::map<std::string, std::list<LoadRequest>> pending_loads_; + + // Maps the currently installed (and loaded) components to their installation + // path. + std::map<std::string, base::FilePath> installed_components_; + + // Maps the currently mounted components to their mount point path. + std::map<std::string, base::FilePath> mounted_components_; + + DISALLOW_COPY_AND_ASSIGN(FakeCrOSComponentManager); +}; + +} // namespace component_updater + +#endif // CHROME_BROWSER_COMPONENT_UPDATER_FAKE_CROS_COMPONENT_MANAGER_H_
diff --git a/chrome/browser/extensions/api/identity/identity_api.cc b/chrome/browser/extensions/api/identity/identity_api.cc index 0a600743..4d06926 100644 --- a/chrome/browser/extensions/api/identity/identity_api.cc +++ b/chrome/browser/extensions/api/identity/identity_api.cc
@@ -25,6 +25,7 @@ #include "chrome/browser/extensions/api/identity/identity_constants.h" #include "chrome/browser/extensions/extension_service.h" #include "chrome/browser/profiles/profile.h" +#include "chrome/browser/signin/account_consistency_mode_manager.h" #include "chrome/browser/signin/account_tracker_service_factory.h" #include "chrome/browser/signin/chrome_signin_client_factory.h" #include "chrome/browser/signin/profile_oauth2_token_service_factory.h" @@ -42,6 +43,11 @@ namespace extensions { +#if BUILDFLAG(ENABLE_DICE_SUPPORT) +const base::Feature kExtensionsAllAccountsFeature{ + "ExtensionsAllAccounts", base::FEATURE_DISABLED_BY_DEFAULT}; +#endif + IdentityTokenCacheValue::IdentityTokenCacheValue() : status_(CACHE_STATUS_NOTFOUND) {} @@ -153,6 +159,19 @@ return g_identity_api_factory.Pointer(); } +bool IdentityAPI::AreExtensionsRestrictedToPrimaryAccount() { +#if BUILDFLAG(ENABLE_DICE_SUPPORT) + if (!signin::DiceMethodGreaterOrEqual( + AccountConsistencyModeManager::GetMethodForProfile(profile_), + signin::AccountConsistencyMethod::kDiceMigration)) { + return true; + } + return !base::FeatureList::IsEnabled(kExtensionsAllAccountsFeature); +#else + return true; +#endif +} + void IdentityAPI::OnRefreshTokenAvailable(const std::string& account_id) { const AccountInfo& account_info = AccountTrackerServiceFactory::GetForProfile(profile_)->GetAccountInfo(
diff --git a/chrome/browser/extensions/api/identity/identity_api.h b/chrome/browser/extensions/api/identity/identity_api.h index 5fc41ec..964c7b01 100644 --- a/chrome/browser/extensions/api/identity/identity_api.h +++ b/chrome/browser/extensions/api/identity/identity_api.h
@@ -12,11 +12,13 @@ #include <vector> #include "base/callback_list.h" +#include "base/feature_list.h" #include "base/gtest_prod_util.h" #include "base/memory/ref_counted.h" #include "base/memory/weak_ptr.h" #include "base/observer_list.h" #include "build/build_config.h" +#include "build/buildflag.h" #include "chrome/browser/extensions/api/identity/extension_token_key.h" #include "chrome/browser/extensions/api/identity/gaia_web_auth_flow.h" #include "chrome/browser/extensions/api/identity/identity_get_accounts_function.h" @@ -28,6 +30,7 @@ #include "chrome/browser/extensions/api/identity/web_auth_flow.h" #include "chrome/browser/extensions/chrome_extension_function.h" #include "components/signin/core/browser/account_tracker_service.h" +#include "components/signin/core/browser/signin_buildflags.h" #include "extensions/browser/browser_context_keyed_api_factory.h" #include "extensions/browser/event_router.h" #include "google_apis/gaia/oauth2_mint_token_flow.h" @@ -41,6 +44,11 @@ namespace extensions { +#if BUILDFLAG(ENABLE_DICE_SUPPORT) +// Enables all accounts in extensions. +extern const base::Feature kExtensionsAllAccountsFeature; +#endif + class IdentityTokenCacheValue { public: IdentityTokenCacheValue(); @@ -112,6 +120,10 @@ on_signin_changed_callback_for_testing_ = callback; } + // Whether the chrome.identity API should use all accounts or the primary + // account only. + bool AreExtensionsRestrictedToPrimaryAccount(); + private: friend class BrowserContextKeyedAPIFactory<IdentityAPI>;
diff --git a/chrome/browser/extensions/api/identity/identity_api_unittest.cc b/chrome/browser/extensions/api/identity/identity_api_unittest.cc new file mode 100644 index 0000000..ffb0cc7 --- /dev/null +++ b/chrome/browser/extensions/api/identity/identity_api_unittest.cc
@@ -0,0 +1,54 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/extensions/api/identity/identity_api.h" + +#include "base/test/scoped_feature_list.h" +#include "build/build_config.h" +#include "chrome/browser/signin/scoped_account_consistency.h" +#include "chrome/test/base/testing_profile.h" +#include "components/signin/core/browser/signin_buildflags.h" +#include "content/public/test/test_browser_thread_bundle.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace extensions { + +#if BUILDFLAG(ENABLE_DICE_SUPPORT) +// Tests that all accounts in extensions is only enabled when Dice is enabled. +TEST(IdentityApiTest, DiceAllAccountsExtensions) { + content::TestBrowserThreadBundle test_thread_bundle; + base::test::ScopedFeatureList feature_list; + feature_list.InitAndEnableFeature(kExtensionsAllAccountsFeature); + + { + ScopedAccountConsistencyDice scoped_dice; + TestingProfile profile; + IdentityAPI api(&profile); + EXPECT_FALSE(api.AreExtensionsRestrictedToPrimaryAccount()); + api.Shutdown(); + } + + { + ScopedAccountConsistencyDiceFixAuthErrors scoped_dice_fix_errors; + TestingProfile profile; + IdentityAPI api(&profile); + EXPECT_TRUE(api.AreExtensionsRestrictedToPrimaryAccount()); + api.Shutdown(); + } +} +#endif + +TEST(IdentityApiTest, AllAccountsExtensionDisabled) { + content::TestBrowserThreadBundle test_thread_bundle; +#if BUILDFLAG(ENABLE_DICE_SUPPORT) + base::test::ScopedFeatureList feature_list; + feature_list.InitAndDisableFeature(kExtensionsAllAccountsFeature); +#endif + TestingProfile profile; + IdentityAPI api(&profile); + EXPECT_TRUE(api.AreExtensionsRestrictedToPrimaryAccount()); + api.Shutdown(); +} + +} // namespace extensions
diff --git a/chrome/browser/extensions/api/identity/identity_apitest.cc b/chrome/browser/extensions/api/identity/identity_apitest.cc index 6420425..16dc019 100644 --- a/chrome/browser/extensions/api/identity/identity_apitest.cc +++ b/chrome/browser/extensions/api/identity/identity_apitest.cc
@@ -13,8 +13,10 @@ #include "base/memory/ptr_util.h" #include "base/run_loop.h" #include "base/strings/string_util.h" +#include "base/test/scoped_feature_list.h" #include "base/values.h" #include "build/build_config.h" +#include "build/buildflag.h" #include "chrome/browser/chrome_notification_types.h" #include "chrome/browser/extensions/api/identity/identity_api.h" #include "chrome/browser/extensions/api/identity/identity_constants.h" @@ -50,10 +52,9 @@ #include "components/signin/core/browser/account_tracker_service.h" #include "components/signin/core/browser/fake_gaia_cookie_manager_service.h" #include "components/signin/core/browser/fake_profile_oauth2_token_service.h" -#include "components/signin/core/browser/profile_management_switches.h" +#include "components/signin/core/browser/signin_buildflags.h" #include "components/signin/core/browser/signin_manager.h" #include "components/signin/core/browser/signin_pref_names.h" -#include "components/signin/core/browser/signin_switches.h" #include "content/public/browser/notification_service.h" #include "content/public/browser/notification_source.h" #include "content/public/test/test_utils.h" @@ -506,6 +507,10 @@ return account_tracker->SeedAccountInfo(gaia, email); } + IdentityAPI* id_api() { + return IdentityAPI::GetFactoryInstance()->Get(browser()->profile()); + } + FakeSigninManagerForTesting* signin_manager_; FakeProfileOAuth2TokenService* token_service_; @@ -515,9 +520,11 @@ }; class IdentityGetAccountsFunctionTest : public IdentityTestWithSignin { - void SetUpCommandLine(base::CommandLine* command_line) override { - ExtensionBrowserTest::SetUpCommandLine(command_line); - command_line->AppendSwitch(switches::kExtensionsMultiAccount); + public: + IdentityGetAccountsFunctionTest() { +#if BUILDFLAG(ENABLE_DICE_SUPPORT) + feature_list_.InitAndEnableFeature(kExtensionsAllAccountsFeature); +#endif } protected: @@ -586,10 +593,17 @@ return testing::AssertionFailure(msg); } + + private: + base::test::ScopedFeatureList feature_list_; }; -IN_PROC_BROWSER_TEST_F(IdentityGetAccountsFunctionTest, MultiAccountOn) { - EXPECT_TRUE(signin::IsExtensionsMultiAccount()); +IN_PROC_BROWSER_TEST_F(IdentityGetAccountsFunctionTest, AllAccountsOn) { +#if BUILDFLAG(ENABLE_DICE_SUPPORT) + EXPECT_FALSE(id_api()->AreExtensionsRestrictedToPrimaryAccount()); +#else + EXPECT_TRUE(id_api()->AreExtensionsRestrictedToPrimaryAccount()); +#endif } IN_PROC_BROWSER_TEST_F(IdentityGetAccountsFunctionTest, NoneSignedIn) { @@ -617,21 +631,31 @@ IN_PROC_BROWSER_TEST_F(IdentityGetAccountsFunctionTest, TwoAccountsSignedIn) { SignIn("primary@example.com"); AddAccount("secondary@example.com"); - EXPECT_TRUE(ExpectGetAccounts({"gaia_id_for_primary@example.com", - "gaia_id_for_secondary@example.com"})); + if (!id_api()->AreExtensionsRestrictedToPrimaryAccount()) { + EXPECT_TRUE(ExpectGetAccounts({"gaia_id_for_primary@example.com", + "gaia_id_for_secondary@example.com"})); + } else { + EXPECT_TRUE(ExpectGetAccounts({"gaia_id_for_primary@example.com"})); + } } class IdentityOldProfilesGetAccountsFunctionTest : public IdentityGetAccountsFunctionTest { - void SetUpCommandLine(base::CommandLine* command_line) override { - ExtensionBrowserTest::SetUpCommandLine(command_line); - // Don't add the multi-account switch that parent class would have. + public: + IdentityOldProfilesGetAccountsFunctionTest() { +#if BUILDFLAG(ENABLE_DICE_SUPPORT) + // Disable the feature that was enabled by the parent class. + feature_list_.InitAndDisableFeature(kExtensionsAllAccountsFeature); +#endif } + + private: + base::test::ScopedFeatureList feature_list_; }; IN_PROC_BROWSER_TEST_F(IdentityOldProfilesGetAccountsFunctionTest, - MultiAccountOff) { - EXPECT_FALSE(signin::IsExtensionsMultiAccount()); + AllAccountsOff) { + EXPECT_TRUE(id_api()->AreExtensionsRestrictedToPrimaryAccount()); } IN_PROC_BROWSER_TEST_F(IdentityOldProfilesGetAccountsFunctionTest, @@ -705,9 +729,14 @@ : public IdentityTestWithSignin, public OAuth2TokenService::DiagnosticsObserver { public: + GetAuthTokenFunctionTest() { +#if BUILDFLAG(ENABLE_DICE_SUPPORT) + feature_list_.InitAndEnableFeature(kExtensionsAllAccountsFeature); +#endif + } + void SetUpCommandLine(base::CommandLine* command_line) override { IdentityTestWithSignin::SetUpCommandLine(command_line); - command_line->AppendSwitch(switches::kExtensionsMultiAccount); } std::string IssueLoginAccessTokenForAccount(const std::string& account_id) { @@ -765,10 +794,6 @@ return ext; } - IdentityAPI* id_api() { - return IdentityAPI::GetFactoryInstance()->Get(browser()->profile()); - } - const std::string& GetPrimaryAccountId() { SigninManagerBase* signin_manager = SigninManagerFactory::GetForProfile(browser()->profile()); @@ -812,6 +837,7 @@ std::move(on_access_token_requested_).Run(); } + base::test::ScopedFeatureList feature_list_; std::string extension_id_; std::set<std::string> oauth_scopes_; }; @@ -1777,6 +1803,10 @@ IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest, MultiSecondaryUserManuallyIssueToken) { + // This test is only relevant if extensions see all accounts. + if (id_api()->AreExtensionsRestrictedToPrimaryAccount()) + return; + std::string primary_account_id = SignIn("primary@example.com"); std::string secondary_account_id = AddAccount("secondary@example.com"); @@ -1823,6 +1853,10 @@ IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest, MultiSecondaryNonInteractiveMintFailure) { + // This test is only relevant if extensions see all accounts. + if (id_api()->AreExtensionsRestrictedToPrimaryAccount()) + return; + SignIn("primary@example.com"); AddAccount("secondary@example.com"); @@ -1841,6 +1875,10 @@ IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest, MultiSecondaryNonInteractiveLoginAccessTokenFailure) { + // This test is only relevant if extensions see all accounts. + if (id_api()->AreExtensionsRestrictedToPrimaryAccount()) + return; + SignIn("primary@example.com"); AddAccount("secondary@example.com"); @@ -1857,6 +1895,10 @@ IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest, MultiSecondaryInteractiveApprovalAborted) { + // This test is only relevant if extensions see all accounts. + if (id_api()->AreExtensionsRestrictedToPrimaryAccount()) + return; + SignIn("primary@example.com"); AddAccount("secondary@example.com");
diff --git a/chrome/browser/extensions/api/identity/identity_get_accounts_function.cc b/chrome/browser/extensions/api/identity/identity_get_accounts_function.cc index bc4e0341..ed995e4 100644 --- a/chrome/browser/extensions/api/identity/identity_get_accounts_function.cc +++ b/chrome/browser/extensions/api/identity/identity_get_accounts_function.cc
@@ -6,8 +6,8 @@ #include "chrome/browser/extensions/api/identity/identity_api.h" #include "chrome/browser/extensions/api/identity/identity_constants.h" +#include "chrome/browser/profiles/profile.h" #include "chrome/common/extensions/api/identity.h" -#include "components/signin/core/browser/profile_management_switches.h" #include "content/public/browser/browser_context.h" #include "content/public/common/service_manager_connection.h" #include "services/identity/public/mojom/account.mojom.h" @@ -41,10 +41,20 @@ std::vector<identity::mojom::AccountPtr> accounts) { std::unique_ptr<base::ListValue> infos(new base::ListValue()); - // If there is no primary account or the primary account has no refresh token - // available, short-circuit out. - if (accounts.empty() || !accounts[0]->state.is_primary_account || - !accounts[0]->state.has_refresh_token) { + if (accounts.empty()) { + Respond(OneArgument(std::move(infos))); + return; + } + + Profile* profile = Profile::FromBrowserContext(browser_context()); + bool primary_account_only = IdentityAPI::GetFactoryInstance() + ->Get(profile) + ->AreExtensionsRestrictedToPrimaryAccount(); + + // If extensions are restricted to the primary account and there is no valid + // primary account, short-circuit out. + if (primary_account_only && (!accounts[0]->state.is_primary_account || + !accounts[0]->state.has_refresh_token)) { Respond(OneArgument(std::move(infos))); return; } @@ -54,8 +64,9 @@ account_info.id = account->info.gaia; infos->Append(account_info.ToValue()); - // Stop after the primary account if extensions are not multi-account. - if (!signin::IsExtensionsMultiAccount()) + // Stop after the primary account if extensions are restricted to the + // primary account. + if (primary_account_only) break; }
diff --git a/chrome/browser/extensions/api/identity/identity_get_auth_token_function.cc b/chrome/browser/extensions/api/identity/identity_get_auth_token_function.cc index 41b2cc1..bd28b06 100644 --- a/chrome/browser/extensions/api/identity/identity_get_auth_token_function.cc +++ b/chrome/browser/extensions/api/identity/identity_get_auth_token_function.cc
@@ -23,7 +23,6 @@ #include "chrome/common/extensions/api/identity.h" #include "components/prefs/pref_service.h" #include "components/signin/core/browser/account_tracker_service.h" -#include "components/signin/core/browser/profile_management_switches.h" #include "components/signin/core/browser/profile_oauth2_token_service.h" #include "components/signin/core/browser/signin_pref_names.h" #include "content/public/common/service_manager_connection.h" @@ -151,7 +150,10 @@ // Detect and handle the case where the extension is using an account other // than the primary account. if (!extension_gaia_id.empty() && extension_gaia_id != primary_gaia_id) { - if (!signin::IsExtensionsMultiAccount()) { + bool primary_account_only = IdentityAPI::GetFactoryInstance() + ->Get(GetProfile()) + ->AreExtensionsRestrictedToPrimaryAccount(); + if (primary_account_only) { // TODO(courage): should this be a different error? CompleteFunctionWithError(identity_constants::kUserNotSignedIn); return;
diff --git a/chrome/browser/extensions/api/instance_id/instance_id_apitest.cc b/chrome/browser/extensions/api/instance_id/instance_id_apitest.cc index f967a3e..38be02f 100644 --- a/chrome/browser/extensions/api/instance_id/instance_id_apitest.cc +++ b/chrome/browser/extensions/api/instance_id/instance_id_apitest.cc
@@ -27,27 +27,16 @@ public: InstanceIDApiTest(); - protected: - void SetUp() override; - void TearDown() override; - private: + gcm::GCMProfileServiceFactory::ScopedTestingFactoryInstaller + scoped_testing_factory_installer_; + DISALLOW_COPY_AND_ASSIGN(InstanceIDApiTest); }; -InstanceIDApiTest::InstanceIDApiTest() { -} - -void InstanceIDApiTest::SetUp() { - gcm::GCMProfileServiceFactory::SetGlobalTestingFactory( - base::BindRepeating(&gcm::FakeGCMProfileService::Build)); - ExtensionApiTest::SetUp(); -} - -void InstanceIDApiTest::TearDown() { - gcm::GCMProfileServiceFactory::SetGlobalTestingFactory( - BrowserContextKeyedServiceFactory::TestingFactory()); -} +InstanceIDApiTest::InstanceIDApiTest() + : scoped_testing_factory_installer_( + base::BindRepeating(&gcm::FakeGCMProfileService::Build)) {} IN_PROC_BROWSER_TEST_F(InstanceIDApiTest, GetID) { ASSERT_TRUE(RunExtensionTest("instance_id/get_id"));
diff --git a/chrome/browser/extensions/extension_keybinding_apitest.cc b/chrome/browser/extensions/extension_keybinding_apitest.cc index ebea6bc2..8bbdaa2 100644 --- a/chrome/browser/extensions/extension_keybinding_apitest.cc +++ b/chrome/browser/extensions/extension_keybinding_apitest.cc
@@ -576,12 +576,6 @@ // web pages. IN_PROC_BROWSER_TEST_F(CommandsApiTest, OverwriteBookmarkShortcutByUserOverridesWebKeybinding) { -#if defined(OS_MACOSX) - // This doesn't work in MacViews mode: https://crbug.com/845503 is the likely - // root cause. - if (!views_mode_controller::IsViewsBrowserCocoa()) - return; -#endif ASSERT_TRUE(embedded_test_server()->Start()); ASSERT_TRUE(ui_test_utils::BringBrowserWindowToFront(browser()));
diff --git a/chrome/browser/extensions/service_worker_apitest.cc b/chrome/browser/extensions/service_worker_apitest.cc index 5d10948..46f476a6 100644 --- a/chrome/browser/extensions/service_worker_apitest.cc +++ b/chrome/browser/extensions/service_worker_apitest.cc
@@ -474,7 +474,11 @@ class ServiceWorkerPushMessagingTest : public ServiceWorkerTest { public: ServiceWorkerPushMessagingTest() - : gcm_driver_(nullptr), push_service_(nullptr) {} + : scoped_testing_factory_installer_( + base::BindRepeating(&gcm::FakeGCMProfileService::Build)), + gcm_driver_(nullptr), + push_service_(nullptr) {} + ~ServiceWorkerPushMessagingTest() override {} void GrantNotificationPermissionForTest(const GURL& url) { @@ -500,12 +504,6 @@ ServiceWorkerTest::SetUpCommandLine(command_line); } - void SetUp() override { - gcm::GCMProfileServiceFactory::SetGlobalTestingFactory( - base::BindRepeating(&gcm::FakeGCMProfileService::Build)); - ServiceWorkerTest::SetUp(); - } - void SetUpOnMainThread() override { NotificationDisplayServiceFactory::GetInstance()->SetTestingFactory( profile(), @@ -521,18 +519,15 @@ ServiceWorkerTest::SetUpOnMainThread(); } - void TearDown() override { - gcm::GCMProfileServiceFactory::SetGlobalTestingFactory( - BrowserContextKeyedServiceFactory::TestingFactory()); - ServiceWorkerTest::TearDown(); - } - instance_id::FakeGCMDriverForInstanceID* gcm_driver() const { return gcm_driver_; } PushMessagingServiceImpl* push_service() const { return push_service_; } private: + gcm::GCMProfileServiceFactory::ScopedTestingFactoryInstaller + scoped_testing_factory_installer_; + instance_id::FakeGCMDriverForInstanceID* gcm_driver_; PushMessagingServiceImpl* push_service_;
diff --git a/chrome/browser/file_select_helper.cc b/chrome/browser/file_select_helper.cc index e4e6fad3..891553cf 100644 --- a/chrome/browser/file_select_helper.cc +++ b/chrome/browser/file_select_helper.cc
@@ -681,8 +681,14 @@ void FileSelectHelper::RenderFrameHostChanged( content::RenderFrameHost* old_host, content::RenderFrameHost* new_host) { - if (old_host == render_frame_host_) + if (!render_frame_host_) + return; + // The |old_host| and its children are now pending deletion. Do not give them + // file access past this point. + if (render_frame_host_ == old_host || + render_frame_host_->IsDescendantOf(old_host)) { render_frame_host_ = nullptr; + } } void FileSelectHelper::RenderFrameDeleted(
diff --git a/chrome/browser/flag_descriptions.cc b/chrome/browser/flag_descriptions.cc index cca9bfc..59c27e4 100644 --- a/chrome/browser/flag_descriptions.cc +++ b/chrome/browser/flag_descriptions.cc
@@ -217,6 +217,11 @@ "print server, instead of the cloud print interface in the Print " "Preview WebUI."; +const char kFCMInvalidationsName[] = + "Enable invalidations delivery via new FCM based protocol"; +const char kFCMInvalidationsDescription[] = + "Use the new FCM-based protocol for deliveling invalidations"; + const char kForceColorProfileSRGB[] = "sRGB"; const char kForceColorProfileP3[] = "Display P3 D65"; const char kForceColorProfileColorSpin[] = "Color spin with gamma 2.4"; @@ -2231,8 +2236,8 @@ const char kCCTModuleCacheName[] = "Chrome Custom Tabs Module Cache"; const char kCCTModuleCacheDescription[] = - "Enables a cache for dynamically loaded modules in Chrome Custom Tabs, " - "on Android."; + "Enables a cache for dynamically loaded modules in Chrome Custom Tabs. " + "Under mild memory pressure the cache may be retained for some time"; const char kChromeDuetName[] = "Chrome Duet"; const char kChromeDuetDescription[] = @@ -2975,11 +2980,6 @@ const char kMacTouchBarName[] = "Hardware Touch Bar"; const char kMacTouchBarDescription[] = "Control the use of the Touch Bar."; -const char kMacV2SandboxName[] = "Mac V2 Sandbox"; -const char kMacV2SandboxDescription[] = - "Eliminates the unsandboxed warmup phase and sandboxes processes for their " - "entire life cycle."; - const char kMacViewsNativeAppWindowsName[] = "Toolkit-Views App Windows."; const char kMacViewsNativeAppWindowsDescription[] = "Controls whether to use Toolkit-Views based Chrome App windows.";
diff --git a/chrome/browser/flag_descriptions.h b/chrome/browser/flag_descriptions.h index 8d9eca5f..acd6e485 100644 --- a/chrome/browser/flag_descriptions.h +++ b/chrome/browser/flag_descriptions.h
@@ -155,6 +155,9 @@ extern const char kCloudPrinterHandlerName[]; extern const char kCloudPrinterHandlerDescription[]; +extern const char kFCMInvalidationsName[]; +extern const char kFCMInvalidationsDescription[]; + extern const char kForceColorProfileSRGB[]; extern const char kForceColorProfileP3[]; extern const char kForceColorProfileColorSpin[]; @@ -1797,9 +1800,6 @@ extern const char kMacTouchBarName[]; extern const char kMacTouchBarDescription[]; -extern const char kMacV2SandboxName[]; -extern const char kMacV2SandboxDescription[]; - extern const char kMacViewsNativeAppWindowsName[]; extern const char kMacViewsNativeAppWindowsDescription[];
diff --git a/chrome/browser/gcm/gcm_profile_service_factory.cc b/chrome/browser/gcm/gcm_profile_service_factory.cc index 2537432..28c87d5b 100644 --- a/chrome/browser/gcm/gcm_profile_service_factory.cc +++ b/chrome/browser/gcm/gcm_profile_service_factory.cc
@@ -76,6 +76,17 @@ } // namespace +GCMProfileServiceFactory::ScopedTestingFactoryInstaller:: + ScopedTestingFactoryInstaller(TestingFactory testing_factory) { + DCHECK(!GetTestingFactory()); + GetTestingFactory() = std::move(testing_factory); +} + +GCMProfileServiceFactory::ScopedTestingFactoryInstaller:: + ~ScopedTestingFactoryInstaller() { + GetTestingFactory() = BrowserContextKeyedServiceFactory::TestingFactory(); +} + // static GCMProfileService* GCMProfileServiceFactory::GetForProfile( content::BrowserContext* profile) { @@ -92,12 +103,6 @@ return base::Singleton<GCMProfileServiceFactory>::get(); } -// static -void GCMProfileServiceFactory::SetGlobalTestingFactory( - BrowserContextKeyedServiceFactory::TestingFactory factory) { - GetTestingFactory() = std::move(factory); -} - GCMProfileServiceFactory::GCMProfileServiceFactory() : BrowserContextKeyedServiceFactory( "GCMProfileService",
diff --git a/chrome/browser/gcm/gcm_profile_service_factory.h b/chrome/browser/gcm/gcm_profile_service_factory.h index 997f7d865..8786f9f 100644 --- a/chrome/browser/gcm/gcm_profile_service_factory.h +++ b/chrome/browser/gcm/gcm_profile_service_factory.h
@@ -21,7 +21,18 @@ public: static GCMProfileService* GetForProfile(content::BrowserContext* profile); static GCMProfileServiceFactory* GetInstance(); - static void SetGlobalTestingFactory(TestingFactory factory); + + // Helper registering a testing factory. Needs to be instantiated before the + // factory is accessed in your test, and deallocated after the last access. + // Usually this is achieved by putting this object as the first member in + // your test fixture. + class ScopedTestingFactoryInstaller { + public: + explicit ScopedTestingFactoryInstaller(TestingFactory testing_factory); + ~ScopedTestingFactoryInstaller(); + + DISALLOW_COPY_AND_ASSIGN(ScopedTestingFactoryInstaller); + }; private: friend struct base::DefaultSingletonTraits<GCMProfileServiceFactory>;
diff --git a/chrome/browser/page_load_metrics/observers/ads_page_load_metrics_observer.cc b/chrome/browser/page_load_metrics/observers/ads_page_load_metrics_observer.cc index 8d258cf..a9d311b 100644 --- a/chrome/browser/page_load_metrics/observers/ads_page_load_metrics_observer.cc +++ b/chrome/browser/page_load_metrics/observers/ads_page_load_metrics_observer.cc
@@ -36,6 +36,13 @@ break; \ } +#define RESOURCE_BYTES_HISTOGRAM(suffix, was_cached, value) \ + if (was_cached) { \ + PAGE_BYTES_HISTOGRAM("Ads.ResourceUsage.Size.Cache." suffix, value); \ + } else { \ + PAGE_BYTES_HISTOGRAM("Ads.ResourceUsage.Size.Network." suffix, value); \ + } + // Finds the RenderFrameHost for the handle, possibly using the FrameTreeNode // ID directly if the the handle has not been committed. // NOTE: Unsafe with respect to security privileges. @@ -434,42 +441,48 @@ void AdsPageLoadMetricsObserver::RecordResourceMimeHistograms( const page_load_metrics::mojom::ResourceDataUpdatePtr& resource) { + int64_t data_length = resource->was_fetched_via_cache + ? resource->encoded_body_length + : resource->received_data_length; ResourceMimeType mime_type = GetResourceMimeType(resource); if (mime_type == ResourceMimeType::kImage) { - PAGE_BYTES_HISTOGRAM("Ads.ResourceUsage.Size.Mime.Image", - resource->received_data_length); + RESOURCE_BYTES_HISTOGRAM("Mime.Image", resource->was_fetched_via_cache, + data_length); } else if (mime_type == ResourceMimeType::kJavascript) { - PAGE_BYTES_HISTOGRAM("Ads.ResourceUsage.Size.Mime.JS", - resource->received_data_length); + RESOURCE_BYTES_HISTOGRAM("Mime.JS", resource->was_fetched_via_cache, + data_length); } else if (mime_type == ResourceMimeType::kVideo) { - PAGE_BYTES_HISTOGRAM("Ads.ResourceUsage.Size.Mime.Video", - resource->received_data_length); + RESOURCE_BYTES_HISTOGRAM("Mime.Video", resource->was_fetched_via_cache, + data_length); } else if (mime_type == ResourceMimeType::kCss) { - PAGE_BYTES_HISTOGRAM("Ads.ResourceUsage.Size.Mime.CSS", - resource->received_data_length); + RESOURCE_BYTES_HISTOGRAM("Mime.CSS", resource->was_fetched_via_cache, + data_length); } else if (mime_type == ResourceMimeType::kHtml) { - PAGE_BYTES_HISTOGRAM("Ads.ResourceUsage.Size.Mime.HTML", - resource->received_data_length); + RESOURCE_BYTES_HISTOGRAM("Mime.HTML", resource->was_fetched_via_cache, + data_length); } else if (mime_type == ResourceMimeType::kOther) { - PAGE_BYTES_HISTOGRAM("Ads.ResourceUsage.Size.Mime.Other", - resource->received_data_length); + RESOURCE_BYTES_HISTOGRAM("Mime.Other", resource->was_fetched_via_cache, + data_length); } } void AdsPageLoadMetricsObserver::RecordResourceHistograms( const page_load_metrics::mojom::ResourceDataUpdatePtr& resource) { + int64_t data_length = resource->was_fetched_via_cache + ? resource->encoded_body_length + : resource->received_data_length; if (resource->is_main_frame_resource && resource->reported_as_ad_resource) { - PAGE_BYTES_HISTOGRAM("Ads.ResourceUsage.Size.Mainframe.AdResource", - resource->received_data_length); + RESOURCE_BYTES_HISTOGRAM("Mainframe.AdResource", + resource->was_fetched_via_cache, data_length); } else if (resource->is_main_frame_resource) { - PAGE_BYTES_HISTOGRAM("Ads.ResourceUsage.Size.Mainframe.VanillaResource", - resource->received_data_length); + RESOURCE_BYTES_HISTOGRAM("Mainframe.VanillaResource", + resource->was_fetched_via_cache, data_length); } else if (resource->reported_as_ad_resource) { - PAGE_BYTES_HISTOGRAM("Ads.ResourceUsage.Size.Subframe.AdResource", - resource->received_data_length); + RESOURCE_BYTES_HISTOGRAM("Subframe.AdResource", + resource->was_fetched_via_cache, data_length); } else { - PAGE_BYTES_HISTOGRAM("Ads.ResourceUsage.Size.Subframe.VanillaResource", - resource->received_data_length); + RESOURCE_BYTES_HISTOGRAM("Subframe.VanillaResource", + resource->was_fetched_via_cache, data_length); } // Only report sizes by mime type for ad resources.
diff --git a/chrome/browser/page_load_metrics/observers/ads_page_load_metrics_observer_browsertest.cc b/chrome/browser/page_load_metrics/observers/ads_page_load_metrics_observer_browsertest.cc index 073a39b..a905b96 100644 --- a/chrome/browser/page_load_metrics/observers/ads_page_load_metrics_observer_browsertest.cc +++ b/chrome/browser/page_load_metrics/observers/ads_page_load_metrics_observer_browsertest.cc
@@ -344,14 +344,14 @@ // Verify correct numbers of resources are recorded. histogram_tester.ExpectTotalCount( - "Ads.ResourceUsage.Size.Mainframe.VanillaResource", 1); + "Ads.ResourceUsage.Size.Network.Mainframe.VanillaResource", 1); histogram_tester.ExpectTotalCount( - "Ads.ResourceUsage.Size.Mainframe.AdResource", 1); + "Ads.ResourceUsage.Size.Network.Mainframe.AdResource", 1); + histogram_tester.ExpectTotalCount( + "Ads.ResourceUsage.Size.Network.Subframe.AdResource", 1); // Verify unfinished resource not yet recorded. histogram_tester.ExpectTotalCount( - "Ads.ResourceUsage.Size.Subframe.AdResource", 1); - histogram_tester.ExpectTotalCount( - "Ads.ResourceUsage.Size.Subframe.VanillaResource", 0); + "Ads.ResourceUsage.Size.Network.Subframe.VanillaResource", 0); // Close all tabs instead of navigating as the embedded_test_server will // hang waiting for loads to finish when we have an unfinished @@ -360,7 +360,7 @@ // Verify unfinished resource recorded when page is destroyed. histogram_tester.ExpectTotalCount( - "Ads.ResourceUsage.Size.Subframe.AdResource", 2); + "Ads.ResourceUsage.Size.Network.Subframe.AdResource", 2); histogram_tester.ExpectBucketCount( "PageLoad.Clients.Ads.Resources.Bytes.Total", 4, 1); @@ -375,6 +375,51 @@ "PageLoad.Clients.Ads.Resources.Bytes.Unfinished", 1, 1); } +// Verify that per-resource metrics are reported for cached resources and +// resources loaded by the network. +IN_PROC_BROWSER_TEST_F(AdsPageLoadMetricsObserverResourceBrowserTest, + RecordedCacheResourceMetrics) { + base::HistogramTester histogram_tester; + SetRulesetWithRules( + {subresource_filter::testing::CreateSuffixRule("create_frame.js")}); + embedded_test_server()->ServeFilesFromSourceDirectory( + "chrome/test/data/ad_tagging"); + content::SetupCrossSiteRedirector(embedded_test_server()); + ASSERT_TRUE(embedded_test_server()->Start()); + + auto waiter = CreateAdsPageLoadMetricsTestWaiter(); + ui_test_utils::NavigateToURL( + browser(), embedded_test_server()->GetURL("foo.com", "/cachetime")); + + // Wait for the favicon to be fetched. + waiter->AddMinimumCompleteResourcesExpectation(2); + waiter->Wait(); + + // All resources should have been loaded by network. + histogram_tester.ExpectTotalCount( + "Ads.ResourceUsage.Size.Network.Mainframe.VanillaResource", 2); + + // Open a new tab and navigate so that resources are fetched via the disk + // cache. Navigating to the same URL in the same tab triggers a refresh which + // will not check the disk cache. + ui_test_utils::NavigateToURLWithDisposition( + browser(), GURL("about:blank"), WindowOpenDisposition::NEW_FOREGROUND_TAB, + ui_test_utils::BROWSER_TEST_WAIT_FOR_TAB | + ui_test_utils::BROWSER_TEST_WAIT_FOR_NAVIGATION); + waiter = CreateAdsPageLoadMetricsTestWaiter(); + ui_test_utils::NavigateToURL( + browser(), embedded_test_server()->GetURL("foo.com", "/cachetime")); + + // Wait for the resource to be fetched. + waiter->AddMinimumCompleteResourcesExpectation(1); + waiter->Wait(); + + // Resource should be recorded as loaded from the cache. Favicon not + // fetched this time. + histogram_tester.ExpectTotalCount( + "Ads.ResourceUsage.Size.Cache.Mainframe.VanillaResource", 1); +} + // Verify that Mime type metrics are recorded correctly. IN_PROC_BROWSER_TEST_F(AdsPageLoadMetricsObserverResourceBrowserTest, RecordedMimeMetrics) { @@ -399,15 +444,21 @@ // Close all tabs to log metrics, as the video resource request is incomplete. browser()->tab_strip_model()->CloseAllTabs(); - histogram_tester.ExpectTotalCount("Ads.ResourceUsage.Size.Mime.HTML", 1); - histogram_tester.ExpectTotalCount("Ads.ResourceUsage.Size.Mime.CSS", 1); - histogram_tester.ExpectTotalCount("Ads.ResourceUsage.Size.Mime.JS", 3); + histogram_tester.ExpectTotalCount("Ads.ResourceUsage.Size.Network.Mime.HTML", + 1); + histogram_tester.ExpectTotalCount("Ads.ResourceUsage.Size.Network.Mime.CSS", + 1); + histogram_tester.ExpectTotalCount("Ads.ResourceUsage.Size.Network.Mime.JS", + 3); // Note: png and video/webm mime types are not set explicitly by the // embedded_test_server. - histogram_tester.ExpectTotalCount("Ads.ResourceUsage.Size.Mime.Image", 1); - histogram_tester.ExpectTotalCount("Ads.ResourceUsage.Size.Mime.Video", 1); - histogram_tester.ExpectTotalCount("Ads.ResourceUsage.Size.Mime.Other", 1); + histogram_tester.ExpectTotalCount("Ads.ResourceUsage.Size.Network.Mime.Image", + 1); + histogram_tester.ExpectTotalCount("Ads.ResourceUsage.Size.Network.Mime.Video", + 1); + histogram_tester.ExpectTotalCount("Ads.ResourceUsage.Size.Network.Mime.Other", + 1); // Verify UKM Metrics recorded. auto entries =
diff --git a/chrome/browser/password_manager/chrome_password_manager_client.cc b/chrome/browser/password_manager/chrome_password_manager_client.cc index fcaf2a1a..35800552 100644 --- a/chrome/browser/password_manager/chrome_password_manager_client.cc +++ b/chrome/browser/password_manager/chrome_password_manager_client.cc
@@ -1075,16 +1075,23 @@ if (!PasswordAccessoryController::AllowedForWebContents(web_contents())) { return; // No need to even create the bridge if it's not going to be used. } - if (is_fillable) { // If not fillable, update existing an accessory only. + if (is_password_field) { + DCHECK(is_fillable); PasswordAccessoryController::CreateForWebContents(web_contents()); - } - PasswordAccessoryController* accessory = - PasswordAccessoryController::FromWebContents(web_contents()); - if (accessory) { + PasswordAccessoryController* accessory = + PasswordAccessoryController::FromWebContents(web_contents()); accessory->RefreshSuggestionsForField( password_manager_driver_bindings_.GetCurrentTargetFrame() ->GetLastCommittedOrigin(), is_fillable, is_password_field); + accessory->ShowWhenKeyboardIsVisible(); + } else { + // If not a password field, only update the accessory if one exists. + PasswordAccessoryController* accessory = + PasswordAccessoryController::FromWebContents(web_contents()); + if (accessory) { + accessory->Hide(); + } } #endif // defined(OS_ANDROID) }
diff --git a/chrome/browser/password_manager/password_accessory_controller.cc b/chrome/browser/password_manager/password_accessory_controller.cc index 0bb11d7..22e566a 100644 --- a/chrome/browser/password_manager/password_accessory_controller.cc +++ b/chrome/browser/password_manager/password_accessory_controller.cc
@@ -191,9 +191,7 @@ for (const auto& pair : best_matches) { const PasswordForm* form = pair.second; suggestions->emplace_back(form->password_value, GetDisplayUsername(*form), - form->username_value.empty() - ? Item::Type::NON_INTERACTIVE_SUGGESTION - : Item::Type::SUGGESTION); + Item::Type::NON_INTERACTIVE_SUGGESTION); } } @@ -264,6 +262,14 @@ origin_suggestions_.clear(); } +void PasswordAccessoryController::ShowWhenKeyboardIsVisible() { + view_->ShowWhenKeyboardIsVisible(); +} + +void PasswordAccessoryController::Hide() { + view_->Hide(); +} + void PasswordAccessoryController::GetFavicon( int desired_size_in_pixel, base::OnceCallback<void(const gfx::Image&)> icon_callback) {
diff --git a/chrome/browser/password_manager/password_accessory_controller.h b/chrome/browser/password_manager/password_accessory_controller.h index c1b3b49..923bebc 100644 --- a/chrome/browser/password_manager/password_accessory_controller.h +++ b/chrome/browser/password_manager/password_accessory_controller.h
@@ -102,6 +102,14 @@ // Reacts to a navigation on the main frame, e.g. by clearing caches. void DidNavigateMainFrame(); + // Requests to show the accessory bar. The accessory will only be shown + // when the keyboard becomes visible. + void ShowWhenKeyboardIsVisible(); + + // Requests to hide the accessory. This hides both the accessory sheet + // (if open) and the accessory bar. + void Hide(); + // -------------------------- // Methods called by UI code: // --------------------------
diff --git a/chrome/browser/password_manager/password_accessory_controller_unittest.cc b/chrome/browser/password_manager/password_accessory_controller_unittest.cc index bc3aa18..443cf71 100644 --- a/chrome/browser/password_manager/password_accessory_controller_unittest.cc +++ b/chrome/browser/password_manager/password_accessory_controller_unittest.cc
@@ -70,6 +70,8 @@ MOCK_METHOD1(OnAutomaticGenerationStatusChanged, void(bool)); MOCK_METHOD0(CloseAccessorySheet, void()); MOCK_METHOD0(SwapSheetWithKeyboard, void()); + MOCK_METHOD0(ShowWhenKeyboardIsVisible, void()); + MOCK_METHOD0(Hide, void()); private: DISALLOW_COPY_AND_ASSIGN(MockPasswordAccessoryView); @@ -355,7 +357,7 @@ OnItemsAvailable(ElementsAre( IsTopDivider(), MatchesLabel(passwords_title_str(kExampleDomain)), MatchesItem(ASCIIToUTF16("Ben"), ASCIIToUTF16("Ben"), false, - ItemType::SUGGESTION), + ItemType::NON_INTERACTIVE_SUGGESTION), MatchesItem(ASCIIToUTF16("S3cur3"), password_for_str("Ben"), true, ItemType::NON_INTERACTIVE_SUGGESTION), IsDivider(), MatchesOption(manage_passwords_str())))); @@ -396,22 +398,22 @@ IsTopDivider(), MatchesLabel(passwords_title_str(kExampleDomain)), MatchesItem(ASCIIToUTF16("Alf"), ASCIIToUTF16("Alf"), false, - ItemType::SUGGESTION), + ItemType::NON_INTERACTIVE_SUGGESTION), MatchesItem(ASCIIToUTF16("PWD"), password_for_str("Alf"), true, ItemType::NON_INTERACTIVE_SUGGESTION), MatchesItem(ASCIIToUTF16("Ben"), ASCIIToUTF16("Ben"), false, - ItemType::SUGGESTION), + ItemType::NON_INTERACTIVE_SUGGESTION), MatchesItem(ASCIIToUTF16("S3cur3"), password_for_str("Ben"), true, ItemType::NON_INTERACTIVE_SUGGESTION), MatchesItem(ASCIIToUTF16("Cat"), ASCIIToUTF16("Cat"), false, - ItemType::SUGGESTION), + ItemType::NON_INTERACTIVE_SUGGESTION), MatchesItem(ASCIIToUTF16("M1@u"), password_for_str("Cat"), true, ItemType::NON_INTERACTIVE_SUGGESTION), MatchesItem(ASCIIToUTF16("Zebra"), ASCIIToUTF16("Zebra"), false, - ItemType::SUGGESTION), + ItemType::NON_INTERACTIVE_SUGGESTION), MatchesItem(ASCIIToUTF16("M3h"), password_for_str("Zebra"), true, ItemType::NON_INTERACTIVE_SUGGESTION), IsDivider(), MatchesOption(manage_passwords_str())))); @@ -431,7 +433,7 @@ OnItemsAvailable(ElementsAre( IsTopDivider(), MatchesLabel(passwords_title_str(kExampleDomain)), MatchesItem(ASCIIToUTF16("Ben"), ASCIIToUTF16("Ben"), false, - ItemType::SUGGESTION), + ItemType::NON_INTERACTIVE_SUGGESTION), MatchesItem(ASCIIToUTF16("S3cur3"), password_for_str("Ben"), true, ItemType::NON_INTERACTIVE_SUGGESTION), IsDivider(), MatchesOption(manage_passwords_str())))); @@ -541,7 +543,7 @@ OnItemsAvailable(ElementsAre( IsTopDivider(), MatchesLabel(passwords_title_str(kExampleDomain)), MatchesItem(ASCIIToUTF16("Ben"), ASCIIToUTF16("Ben"), false, - ItemType::SUGGESTION), + ItemType::NON_INTERACTIVE_SUGGESTION), MatchesItem(ASCIIToUTF16("S3cur3"), password_for_str("Ben"), true, ItemType::NON_INTERACTIVE_SUGGESTION), IsDivider(), MatchesOption(manage_passwords_str())))); @@ -557,7 +559,7 @@ OnItemsAvailable(ElementsAre( IsTopDivider(), MatchesLabel(passwords_title_str(kExampleDomain)), MatchesItem(ASCIIToUTF16("Ben"), ASCIIToUTF16("Ben"), false, - ItemType::SUGGESTION), + ItemType::NON_INTERACTIVE_SUGGESTION), MatchesItem(ASCIIToUTF16("S3cur3"), password_for_str("Ben"), true, ItemType::SUGGESTION), IsDivider(), MatchesOption(manage_passwords_str())))); @@ -575,7 +577,7 @@ OnItemsAvailable(ElementsAre( IsTopDivider(), MatchesLabel(passwords_title_str(kExampleDomain)), MatchesItem(ASCIIToUTF16("Ben"), ASCIIToUTF16("Ben"), false, - ItemType::SUGGESTION), + ItemType::NON_INTERACTIVE_SUGGESTION), MatchesItem(ASCIIToUTF16("S3cur3"), password_for_str("Ben"), true, ItemType::NON_INTERACTIVE_SUGGESTION), IsDivider(), MatchesOption(manage_passwords_str())))); @@ -591,7 +593,7 @@ OnItemsAvailable(ElementsAre( IsTopDivider(), MatchesLabel(passwords_title_str(kExampleDomain)), MatchesItem(ASCIIToUTF16("Alf"), ASCIIToUTF16("Alf"), false, - ItemType::SUGGESTION), + ItemType::NON_INTERACTIVE_SUGGESTION), MatchesItem(ASCIIToUTF16("M3lm4k"), password_for_str("Alf"), true, ItemType::NON_INTERACTIVE_SUGGESTION), IsDivider(), MatchesOption(manage_passwords_str())))); @@ -611,7 +613,7 @@ OnItemsAvailable(ElementsAre( IsTopDivider(), MatchesLabel(passwords_title_str(kExampleDomain)), MatchesItem(ASCIIToUTF16("Ben"), ASCIIToUTF16("Ben"), false, - ItemType::SUGGESTION), + ItemType::NON_INTERACTIVE_SUGGESTION), MatchesItem(ASCIIToUTF16("S3cur3"), password_for_str("Ben"), true, ItemType::NON_INTERACTIVE_SUGGESTION), IsDivider(), MatchesOption(manage_passwords_str())))); @@ -643,7 +645,7 @@ OnItemsAvailable(ElementsAre( IsTopDivider(), MatchesLabel(passwords_title_str(kExampleDomain)), MatchesItem(ASCIIToUTF16("Ben"), ASCIIToUTF16("Ben"), false, - ItemType::SUGGESTION), + ItemType::NON_INTERACTIVE_SUGGESTION), MatchesItem(ASCIIToUTF16("S3cur3"), password_for_str("Ben"), true, ItemType::NON_INTERACTIVE_SUGGESTION), IsDivider(), MatchesOption(manage_passwords_str())))); @@ -855,3 +857,10 @@ "PasswordGeneration.UserEvent", PasswordGenerationUserEvent::kPasswordRejectedInDialog, 1); } + +TEST_F(PasswordAccessoryControllerTest, RelaysShowAndHideKeyboardAccessory) { + EXPECT_CALL(*view(), ShowWhenKeyboardIsVisible()); + controller()->ShowWhenKeyboardIsVisible(); + EXPECT_CALL(*view(), Hide()); + controller()->Hide(); +}
diff --git a/chrome/browser/password_manager/password_accessory_view_interface.h b/chrome/browser/password_manager/password_accessory_view_interface.h index 21e734d..ee1ed94 100644 --- a/chrome/browser/password_manager/password_accessory_view_interface.h +++ b/chrome/browser/password_manager/password_accessory_view_interface.h
@@ -81,6 +81,12 @@ // Opens a keyboard which dismisses the sheet. NoOp without open sheet. virtual void SwapSheetWithKeyboard() = 0; + // Shows the accessory bar when the keyboard is also shown. + virtual void ShowWhenKeyboardIsVisible() = 0; + + // Hides the accessory bar and the accessory sheet (if open). + virtual void Hide() = 0; + private: friend class PasswordAccessoryController; // Factory function used to create a concrete instance of this view.
diff --git a/chrome/browser/policy/configuration_policy_handler_list_factory.cc b/chrome/browser/policy/configuration_policy_handler_list_factory.cc index 5c2f7b3..96295c7 100644 --- a/chrome/browser/policy/configuration_policy_handler_list_factory.cc +++ b/chrome/browser/policy/configuration_policy_handler_list_factory.cc
@@ -687,6 +687,9 @@ { key::kReportCrostiniUsageEnabled, crostini::prefs::kReportCrostiniUsageEnabled, base::Value::Type::BOOLEAN }, + { key::kNTLMShareAuthenticationEnabled, + prefs::kNTLMShareAuthenticationEnabled, + base::Value::Type::BOOLEAN }, #endif // defined(OS_CHROMEOS) // Metrics reporting is controlled by a platform specific policy for ChromeOS
diff --git a/chrome/browser/push_messaging/push_messaging_browsertest.cc b/chrome/browser/push_messaging/push_messaging_browsertest.cc index e45c9db..3945233 100644 --- a/chrome/browser/push_messaging/push_messaging_browsertest.cc +++ b/chrome/browser/push_messaging/push_messaging_browsertest.cc
@@ -127,7 +127,11 @@ class PushMessagingBrowserTest : public InProcessBrowserTest { public: - PushMessagingBrowserTest() : gcm_service_(nullptr), gcm_driver_(nullptr) {} + PushMessagingBrowserTest() + : scoped_testing_factory_installer_( + base::BindRepeating(&gcm::FakeGCMProfileService::Build)), + gcm_service_(nullptr), + gcm_driver_(nullptr) {} ~PushMessagingBrowserTest() override {} // InProcessBrowserTest: @@ -137,9 +141,6 @@ https_server_->ServeFilesFromSourceDirectory("chrome/test/data"); ASSERT_TRUE(https_server_->Start()); - gcm::GCMProfileServiceFactory::SetGlobalTestingFactory( - base::BindRepeating(&gcm::FakeGCMProfileService::Build)); - SiteEngagementScore::SetParamValuesForTesting(); InProcessBrowserTest::SetUp(); } @@ -168,12 +169,6 @@ LoadTestPage(); } - void TearDown() override { - gcm::GCMProfileServiceFactory::SetGlobalTestingFactory( - BrowserContextKeyedServiceFactory::TestingFactory()); - InProcessBrowserTest::TearDown(); - } - void TearDownOnMainThread() override { notification_tester_.reset(); InProcessBrowserTest::TearDownOnMainThread(); @@ -327,6 +322,9 @@ virtual Browser* GetBrowser() const { return browser(); } + gcm::GCMProfileServiceFactory::ScopedTestingFactoryInstaller + scoped_testing_factory_installer_; + gcm::FakeGCMProfileService* gcm_service_; instance_id::FakeGCMDriverForInstanceID* gcm_driver_; base::HistogramTester histogram_tester_;
diff --git a/chrome/browser/resources/chromeos/zip_archiver/cpp/volume.cc b/chrome/browser/resources/chromeos/zip_archiver/cpp/volume.cc index bbb5f1fd..5c63bc8 100644 --- a/chrome/browser/resources/chromeos/zip_archiver/cpp/volume.cc +++ b/chrome/browser/resources/chromeos/zip_archiver/cpp/volume.cc
@@ -204,10 +204,6 @@ Volume::~Volume() { worker_.Join(); - - if (volume_archive_) { - volume_archive_->Cleanup(); - } } bool Volume::Init() {
diff --git a/chrome/browser/resources/chromeos/zip_archiver/cpp/volume_archive.h b/chrome/browser/resources/chromeos/zip_archiver/cpp/volume_archive.h index 4629ef3f..64e079a9 100644 --- a/chrome/browser/resources/chromeos/zip_archiver/cpp/volume_archive.h +++ b/chrome/browser/resources/chromeos/zip_archiver/cpp/volume_archive.h
@@ -29,10 +29,9 @@ }; // Initializes VolumeArchive. Should be called only once. - // In case of any errors call VolumeArchive::Cleanup and the error message can - // be obtained with VolumeArchive::error_message(). Encoding is the default - // encoding. Note, that other encoding may be used if specified in the - // archive file. + // In case of any errors, the error message can be obtained with + // VolumeArchive::error_message(). Encoding is the default encoding. Note, + // that other encoding may be used if specified in the archive file. virtual bool Init(const std::string& encoding) = 0; // Gets the next header. If path_name is set to nullptr, then there are no @@ -82,11 +81,6 @@ // buffer. virtual void MaybeDecompressAhead() = 0; - // Cleans all resources. Should be called only once. Returns true if - // successful. In case of failure the error message can be obtained with - // VolumeArchive::error_message(). - virtual bool Cleanup() = 0; - VolumeReader* reader() const { return reader_.get(); } std::string error_message() const { return error_message_; }
diff --git a/chrome/browser/resources/chromeos/zip_archiver/cpp/volume_archive_minizip.cc b/chrome/browser/resources/chromeos/zip_archiver/cpp/volume_archive_minizip.cc index 3031aa7..debbf4ca 100644 --- a/chrome/browser/resources/chromeos/zip_archiver/cpp/volume_archive_minizip.cc +++ b/chrome/browser/resources/chromeos/zip_archiver/cpp/volume_archive_minizip.cc
@@ -21,7 +21,6 @@ const char kArchiveNextHeaderError[] = "Failed to open current file in archive."; const char kArchiveReadDataError[] = "Failed to read archive data."; -const char kArchiveReadFreeError[] = "Failed to close archive."; // The size of the buffer used to skip unnecessary data. Should be positive and // UINT16_MAX or less. unzReadCurrentFile in third_party/minizip/src/unzip.c @@ -225,7 +224,11 @@ decompressed_error_(false) {} VolumeArchiveMinizip::~VolumeArchiveMinizip() { - Cleanup(); + if (zip_file_) { + if (unzClose(zip_file_) != UNZ_OK) { + LOG(WARNING) << "Failed to close archive."; + } + } } bool VolumeArchiveMinizip::Init(const std::string& encoding) { @@ -489,20 +492,6 @@ decompressed_data_size_ = bytes_read; } -bool VolumeArchiveMinizip::Cleanup() { - bool returnValue = true; - if (zip_file_) { - if (unzClose(zip_file_) != UNZ_OK) { - set_error_message(kArchiveReadFreeError); - returnValue = false; - } - } - zip_file_ = nullptr; - password_cache_.reset(); - - return returnValue; -} - int64_t VolumeArchiveMinizip::ReadData(int64_t offset, int64_t length, const char** buffer) {
diff --git a/chrome/browser/resources/chromeos/zip_archiver/cpp/volume_archive_minizip.h b/chrome/browser/resources/chromeos/zip_archiver/cpp/volume_archive_minizip.h index 0a91456..7196fae 100644 --- a/chrome/browser/resources/chromeos/zip_archiver/cpp/volume_archive_minizip.h +++ b/chrome/browser/resources/chromeos/zip_archiver/cpp/volume_archive_minizip.h
@@ -70,9 +70,6 @@ // See volume_archive_interface.h. void MaybeDecompressAhead() override; - // See volume_archive_interface.h. - bool Cleanup() override; - int64_t reader_data_size() const { return reader_data_size_; } // Custom functions need to access private variables of
diff --git a/chrome/browser/safe_browsing/download_protection/download_protection_service_unittest.cc b/chrome/browser/safe_browsing/download_protection/download_protection_service_unittest.cc index d83c432..5e9fa228 100644 --- a/chrome/browser/safe_browsing/download_protection/download_protection_service_unittest.cc +++ b/chrome/browser/safe_browsing/download_protection/download_protection_service_unittest.cc
@@ -2681,8 +2681,7 @@ TEST_F(DownloadProtectionServiceTest, CheckNotExtendedReportedDisabledDoesNotSendFeedback) { - PrefService* prefs = profile_->GetPrefs(); - prefs->SetBoolean(GetExtendedReportingPrefName(*prefs), false); + SetExtendedReportingPreference(false); NiceMockDownloadItem item; EXPECT_FALSE(download_service_->MaybeBeginFeedbackForDownload(
diff --git a/chrome/browser/subresource_filter/ad_tagging_browsertest.cc b/chrome/browser/subresource_filter/ad_tagging_browsertest.cc index c12e437e..f2819dcb 100644 --- a/chrome/browser/subresource_filter/ad_tagging_browsertest.cc +++ b/chrome/browser/subresource_filter/ad_tagging_browsertest.cc
@@ -444,11 +444,11 @@ ExpectLatestWindowOpenUkmEntry( ukm_recorder, expected_num_entries, false /* from_main_frame */, main_frame_url, ad_frame /* from_ad_subframe */, - false /* from_ad_script */); + ad_frame /* from_ad_script */); ExpectWindowOpenUmaStatus( - histogram_tester, 0 /* adscript_adframe */, - expected_num_from_ad_subframe /* nonadscript_adframe */, - 0 /* adscript_nonadframe */, + histogram_tester, + expected_num_from_ad_subframe /* adscript_adframe */, + 0 /* nonadscript_adframe */, 0 /* adscript_nonadframe */, expected_num_entries - expected_num_from_ad_subframe /* nonadscript_nonadframe */); }
diff --git a/chrome/browser/sync/test/integration/single_client_history_delete_directives_sync_test.cc b/chrome/browser/sync/test/integration/single_client_history_delete_directives_sync_test.cc index ac71bf2..86edd23a 100644 --- a/chrome/browser/sync/test/integration/single_client_history_delete_directives_sync_test.cc +++ b/chrome/browser/sync/test/integration/single_client_history_delete_directives_sync_test.cc
@@ -5,7 +5,9 @@ #include <stddef.h> #include "base/macros.h" +#include "base/run_loop.h" #include "base/task/cancelable_task_tracker.h" +#include "base/test/bind_test_util.h" #include "chrome/browser/history/history_service_factory.h" #include "chrome/browser/history/web_history_service_factory.h" #include "chrome/browser/sync/test/integration/feature_toggler.h" @@ -15,6 +17,7 @@ #include "components/history/core/browser/history_service.h" #include "components/history/core/browser/history_types.h" #include "components/sync/driver/sync_driver_switches.h" +#include "components/sync/engine_impl/loopback_server/persistent_unique_client_entity.h" #include "components/sync/protocol/sync.pb.h" #include "components/sync/test/fake_server/fake_server.h" @@ -22,6 +25,11 @@ using sync_pb::HistoryDeleteDirectiveSpecifics; +int64_t TimeToUnixUsec(base::Time time) { + DCHECK(!time.is_null()); + return (time - base::Time::UnixEpoch()).InMicroseconds(); +} + // Allows to wait until the number of server-side entities is equal to a // expected number. class HistoryDeleteDirectivesEqualityChecker @@ -76,6 +84,28 @@ .Wait(); } + // Uses HistoryService to look up whether any history entry exists that + // exactly matches timestamp |time|. + bool LookupLocalHistoryEntry(base::Time time) { + history::HistoryService* history_service = + HistoryServiceFactory::GetForProfileWithoutCreating(GetProfile(0)); + + bool exists = false; + base::RunLoop loop; + base::CancelableTaskTracker task_tracker; + history_service->GetHistoryCount( + /*begin_time=*/time, + /*end_time=*/time + base::TimeDelta::FromMicroseconds(1), + base::BindLambdaForTesting([&](history::HistoryCountResult result) { + ASSERT_TRUE(result.success); + exists = (result.count != 0); + loop.Quit(); + }), + &task_tracker); + loop.Run(); + return exists; + } + private: DISALLOW_COPY_AND_ASSIGN(SingleClientHistoryDeleteDirectivesSyncTest); }; @@ -101,6 +131,48 @@ EXPECT_TRUE(WaitForHistoryDeleteDirectives(1)); } +IN_PROC_BROWSER_TEST_P(SingleClientHistoryDeleteDirectivesSyncTest, + ShouldProcessDeleteDirectiveDuringStartup) { + const GURL kPageUrl = GURL("http://foo.com"); + const base::Time kHistoryEntryTime = base::Time::Now(); + + ASSERT_TRUE(SetupClients()); + + // Initially (before sync starts) there is a local history entry. + history::HistoryService* history_service = + HistoryServiceFactory::GetForProfileWithoutCreating(GetProfile(0)); + history_service->AddPage(kPageUrl, kHistoryEntryTime, + history::SOURCE_BROWSED); + + // Initially (before sync starts) there is a remote delete directive. + sync_pb::EntitySpecifics specifics; + sync_pb::TimeRangeDirective* time_range_directive = + specifics.mutable_history_delete_directive() + ->mutable_time_range_directive(); + time_range_directive->set_start_time_usec(TimeToUnixUsec(kHistoryEntryTime)); + time_range_directive->set_end_time_usec(TimeToUnixUsec(kHistoryEntryTime) + + 1); + + fake_server_->InjectEntity( + syncer::PersistentUniqueClientEntity::CreateFromEntitySpecifics( + "name", specifics, /*creation_time=*/0, /*last_modified_time=*/0)); + EXPECT_TRUE(WaitForHistoryDeleteDirectives(1)); + + // Verify history exists prior to starting sync. + ASSERT_TRUE(LookupLocalHistoryEntry(kHistoryEntryTime)); + + ASSERT_TRUE(SetupSync()); + + // Verify history entry was deleted. + EXPECT_FALSE(LookupLocalHistoryEntry(kHistoryEntryTime)); + + // No deletion should be sent to the server. There's no way to verify this + // reliably in an integration test (i.e. it could eventually be deleted), but + // this should be a good approximation considering there was a round-trip to + // the history DB. + EXPECT_TRUE(WaitForHistoryDeleteDirectives(1)); +} + INSTANTIATE_TEST_CASE_P(USS, SingleClientHistoryDeleteDirectivesSyncTest, ::testing::Values(false, true));
diff --git a/chrome/browser/task_manager/providers/web_contents/web_contents_task_provider.cc b/chrome/browser/task_manager/providers/web_contents/web_contents_task_provider.cc index 53ee253..ce3daf49 100644 --- a/chrome/browser/task_manager/providers/web_contents/web_contents_task_provider.cc +++ b/chrome/browser/task_manager/providers/web_contents/web_contents_task_provider.cc
@@ -71,6 +71,10 @@ // notifies the provider's observer of the tasks removal. void ClearTaskForFrame(RenderFrameHost* render_frame_host); + // Same as |ClearTaskForFrame|, but for every descendant of + // |ancestor|. + void ClearTasksForDescendantsOf(RenderFrameHost* ancestor); + // Calls |on_task| for each task managed by this WebContentsEntry. void ForEachTask(const base::Callback<void(RendererTask*)>& on_task); @@ -164,7 +168,13 @@ void WebContentsEntry::RenderFrameHostChanged(RenderFrameHost* old_host, RenderFrameHost* new_host) { DCHECK(new_host->IsCurrent()); + + // The navigating frame and its subframes are now pending deletion. Stop + // tracking them immediately rather than when they are destroyed. The order of + // deletion is important. The children must be removed first. + ClearTasksForDescendantsOf(old_host); ClearTaskForFrame(old_host); + CreateTaskForFrame(new_host); } @@ -358,6 +368,20 @@ DCHECK(tasks_by_frames_.empty() == (main_frame_site_instance_ == nullptr)); } +void WebContentsEntry::ClearTasksForDescendantsOf(RenderFrameHost* ancestor) { + // 1) Collect descendants. + std::vector<RenderFrameHost*> descendants; + for (auto it : tasks_by_frames_) { + RenderFrameHost* frame = it.first; + if (frame->IsDescendantOf(ancestor)) + descendants.push_back(frame); + } + + // 2) Delete them. + for (RenderFrameHost* rfh : descendants) + ClearTaskForFrame(rfh); +} + void WebContentsEntry::ForEachTask( const base::Callback<void(RendererTask*)>& on_task) { for (const auto& pair : frames_by_site_instance_) {
diff --git a/chrome/browser/ui/BUILD.gn b/chrome/browser/ui/BUILD.gn index d64d67c..108b54de 100644 --- a/chrome/browser/ui/BUILD.gn +++ b/chrome/browser/ui/BUILD.gn
@@ -855,6 +855,8 @@ "global_error/global_error_service.h", "global_error/global_error_service_factory.cc", "global_error/global_error_service_factory.h", + "hats/hats_helper.cc", + "hats/hats_helper.h", "hats/hats_service.cc", "hats/hats_service.h", "hats/hats_service_factory.cc", @@ -1759,6 +1761,10 @@ "signin_view_controller.h", "signin_view_controller_delegate.cc", "signin_view_controller_delegate.h", + "views/close_bubble_on_tab_activation_helper.cc", + "views/close_bubble_on_tab_activation_helper.h", + "views/hats/hats_bubble_view.cc", + "views/hats/hats_bubble_view.h", "webui/discards/discards_ui.cc", "webui/discards/discards_ui.h", "webui/signin/inline_login_handler.cc", @@ -1789,8 +1795,6 @@ "sync/one_click_signin_sync_starter.h", "user_manager.cc", "user_manager.h", - "views/close_bubble_on_tab_activation_helper.cc", - "views/close_bubble_on_tab_activation_helper.h", "views/external_protocol_dialog.cc", "views/external_protocol_dialog.h", "views/profiles/badged_profile_photo.cc",
diff --git a/chrome/browser/ui/browser_dialogs.h b/chrome/browser/ui/browser_dialogs.h index c0c7c211..f68bd5a7 100644 --- a/chrome/browser/ui/browser_dialogs.h +++ b/chrome/browser/ui/browser_dialogs.h
@@ -280,6 +280,7 @@ DOWNLOAD_OPEN_CONFIRMATION = 87, ARC_DATA_REMOVAL_CONFIRMATION = 88, CROSTINI_UPGRADE = 89, + HATS_BUBBLE = 90, MAX_VALUE };
diff --git a/chrome/browser/ui/browser_window.h b/chrome/browser/ui/browser_window.h index c4bd804f..21ee7f04 100644 --- a/chrome/browser/ui/browser_window.h +++ b/chrome/browser/ui/browser_window.h
@@ -404,6 +404,11 @@ signin_metrics::AccessPoint access_point, bool is_source_keyboard) = 0; +#if defined(OS_CHROMEOS) || defined(OS_MACOSX) || defined(OS_WIN) || \ + defined(OS_LINUX) + virtual void ShowHatsBubbleFromAppMenuButton() = 0; +#endif + // Returns the height inset for RenderView when detached bookmark bar is // shown. Invoked when a new RenderHostView is created for a non-NTP // navigation entry and the bookmark bar is detached.
diff --git a/chrome/browser/ui/exclusive_access/fullscreen_controller_interactive_browsertest.cc b/chrome/browser/ui/exclusive_access/fullscreen_controller_interactive_browsertest.cc index b401d81..698112bb 100644 --- a/chrome/browser/ui/exclusive_access/fullscreen_controller_interactive_browsertest.cc +++ b/chrome/browser/ui/exclusive_access/fullscreen_controller_interactive_browsertest.cc
@@ -516,21 +516,13 @@ } // Flaky on Linux, CrOS: http://crbug.com/159000 -#if defined(OS_LINUX) || defined(OS_CHROMEOS) -#define MAYBE_MouseLockSilentAfterTargetUnlock \ - DISABLED_MouseLockSilentAfterTargetUnlock -#elif defined(OS_WIN) // Flaky on Windows; see https://crbug.com/791539. -#define MAYBE_MouseLockSilentAfterTargetUnlock \ - DISABLED_MouseLockSilentAfterTargetUnlock -#else -#define MAYBE_MouseLockSilentAfterTargetUnlock MouseLockSilentAfterTargetUnlock -#endif +// Flaky on Mac: https://crbug.com/876617. // Tests mouse lock can be exited and re-entered by an application silently // with no UI distraction for users. IN_PROC_BROWSER_TEST_F(FullscreenControllerInteractiveTest, - MAYBE_MouseLockSilentAfterTargetUnlock) { + DISABLED_MouseLockSilentAfterTargetUnlock) { SetWebContentsGrantedSilentMouseLockPermission(); ASSERT_TRUE(embedded_test_server()->Start()); ui_test_utils::NavigateToURL(
diff --git a/chrome/browser/ui/hats/hats_helper.cc b/chrome/browser/ui/hats/hats_helper.cc new file mode 100644 index 0000000..bfeee83 --- /dev/null +++ b/chrome/browser/ui/hats/hats_helper.cc
@@ -0,0 +1,42 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/ui/hats/hats_helper.h" + +#include <memory> + +#include "base/task/post_task.h" +#include "chrome/browser/profiles/profile.h" +#include "chrome/browser/search/instant_service.h" +#include "chrome/browser/search/instant_service_factory.h" +#include "chrome/browser/search/search.h" +#include "chrome/browser/ui/hats/hats_service.h" +#include "chrome/browser/ui/hats/hats_service_factory.h" +#include "chrome/common/chrome_features.h" +#include "components/search/search.h" +#include "content/public/browser/browser_task_traits.h" +#include "content/public/browser/browser_thread.h" + +HatsHelper::HatsHelper(content::WebContents* web_contents) + : WebContentsObserver(web_contents), web_contents_(web_contents) { + DCHECK(search::IsInstantExtendedAPIEnabled()); +} + +HatsHelper::~HatsHelper() {} + +void HatsHelper::DidFinishLoad(content::RenderFrameHost* render_frame_host, + const GURL& /* validated_url */) { + if (!render_frame_host->GetParent() && search::IsInstantNTP(web_contents_)) { + HatsService* hats_service = + HatsServiceFactory::GetForProfile(profile(), true); + + if (hats_service) { + hats_service->LaunchSatisfactionSurvey(); + } + } +} + +Profile* HatsHelper::profile() const { + return Profile::FromBrowserContext(web_contents_->GetBrowserContext()); +}
diff --git a/chrome/browser/ui/hats/hats_helper.h b/chrome/browser/ui/hats/hats_helper.h new file mode 100644 index 0000000..2ecd6b7 --- /dev/null +++ b/chrome/browser/ui/hats/hats_helper.h
@@ -0,0 +1,41 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_UI_HATS_HATS_HELPER_H_ +#define CHROME_BROWSER_UI_HATS_HATS_HELPER_H_ + +#include "base/macros.h" +#include "content/public/browser/web_contents_observer.h" +#include "content/public/browser/web_contents_user_data.h" + +namespace content { +class WebContents; +} + +class Profile; + +// This is a browser side per tab helper that allows an entry trigger to +// launch Happiness Tracking Surveys (HaTS) +class HatsHelper : public content::WebContentsObserver, + public content::WebContentsUserData<HatsHelper> { + public: + ~HatsHelper() override; + + private: + friend class content::WebContentsUserData<HatsHelper>; + + explicit HatsHelper(content::WebContents* web_contents); + + // Overridden from contents::WebContentsObserver: + void DidFinishLoad(content::RenderFrameHost* render_frame_host, + const GURL& validated_url) override; + + Profile* profile() const; + + content::WebContents* web_contents_; + + DISALLOW_COPY_AND_ASSIGN(HatsHelper); +}; + +#endif // CHROME_BROWSER_UI_HATS_HATS_HELPER_H_
diff --git a/chrome/browser/ui/hats/hats_service.cc b/chrome/browser/ui/hats/hats_service.cc index 1fdb040..192af11 100644 --- a/chrome/browser/ui/hats/hats_service.cc +++ b/chrome/browser/ui/hats/hats_service.cc
@@ -12,6 +12,7 @@ #include "base/rand_util.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/ui/browser_finder.h" +#include "chrome/browser/ui/browser_window.h" #include "chrome/common/chrome_features.h" #include "content/public/browser/browser_thread.h" @@ -29,6 +30,8 @@ const char kHatsSurveyEnSiteIDDefault[] = "z4cctguzopq5x2ftal6vdgjrui"; +const char kHatsSurveyTriggerSatisfaction[] = "satisfaction"; + HatsFinchConfig CreateHatsFinchConfig() { HatsFinchConfig config; config.trigger = base::FeatureParam<std::string>( @@ -59,7 +62,27 @@ HatsService::HatsService(Profile* profile) : profile_(profile), hats_finch_config_(CreateHatsFinchConfig()) {} -bool HatsService::ShouldShowSurvey() { - return (base::RandDouble() < hats_finch_config_.probability); - // TODO add pref checks to avoid too many surveys for a single profile +void HatsService::LaunchSatisfactionSurvey() { + if (ShouldShowSurvey(kHatsSurveyTriggerSatisfaction)) { + Browser* browser = chrome::FindBrowserWithActiveWindow(); + if (browser && browser->is_type_tabbed()) + browser->window()->ShowHatsBubbleFromAppMenuButton(); + } } + +bool HatsService::ShouldShowSurvey(const std::string& trigger) const { + if ((hats_finch_config_.trigger == trigger || + hats_finch_config_.trigger == kHatsSurveyTriggerDefault) && + !launch_hats_) { + if (base::RandDouble() < hats_finch_config_.probability) { + // we only want to ever show hats once per profile. + launch_hats_ = true; + return true; + } + // TODO add pref checks to avoid too many surveys for a single profile + } + return false; +} + +// static +bool HatsService::launch_hats_ = false;
diff --git a/chrome/browser/ui/hats/hats_service.h b/chrome/browser/ui/hats/hats_service.h index 192b0cd8..a8f8db9 100644 --- a/chrome/browser/ui/hats/hats_service.h +++ b/chrome/browser/ui/hats/hats_service.h
@@ -36,9 +36,18 @@ class HatsService : public KeyedService { public: explicit HatsService(Profile* profile); - bool ShouldShowSurvey(); + + // This is the public function that will launch the "satisfaction" survey if + // it's appropriate. + void LaunchSatisfactionSurvey(); private: + // This returns true is the survey trigger specified should be shown. + bool ShouldShowSurvey(const std::string& trigger) const; + + // a temporary flag to ensure that hats is not launched multiple times + // TODO: replace with pref lookup + static bool launch_hats_; Profile* profile_; const HatsFinchConfig hats_finch_config_;
diff --git a/chrome/browser/ui/search/search_tab_helper.cc b/chrome/browser/ui/search/search_tab_helper.cc index fdba4119f..4c73a9e 100644 --- a/chrome/browser/ui/search/search_tab_helper.cc +++ b/chrome/browser/ui/search/search_tab_helper.cc
@@ -19,8 +19,6 @@ #include "chrome/browser/ui/browser_finder.h" #include "chrome/browser/ui/browser_window.h" #include "chrome/browser/ui/chrome_select_file_policy.h" -#include "chrome/browser/ui/hats/hats_service.h" -#include "chrome/browser/ui/hats/hats_service_factory.h" #include "chrome/browser/ui/location_bar/location_bar.h" #include "chrome/browser/ui/omnibox/clipboard_utils.h" #include "chrome/browser/ui/search/ntp_user_data_logger.h" @@ -219,24 +217,8 @@ void SearchTabHelper::DidFinishLoad(content::RenderFrameHost* render_frame_host, const GURL& /* validated_url */) { - if (!render_frame_host->GetParent()) { - if (search::IsInstantNTP(web_contents_)) { - RecordNewTabLoadTime(web_contents_); - -#if !defined(OS_ANDROID) - if (base::FeatureList::IsEnabled( - features::kHappinessTrackingSurveysForDesktop)) { - HatsService* hats_service = - HatsServiceFactory::GetForProfile(profile(), true); - - // In icognito mode, hats_service will be null. - if (hats_service && hats_service->ShouldShowSurvey()) { - // TODO launch bubble; - } - } -#endif // !defined(OS_ANDROID) - } - } + if (!render_frame_host->GetParent() && search::IsInstantNTP(web_contents_)) + RecordNewTabLoadTime(web_contents_); } void SearchTabHelper::NavigationEntryCommitted(
diff --git a/chrome/browser/ui/tab_helpers.cc b/chrome/browser/ui/tab_helpers.cc index d2d948e..b912d6f 100644 --- a/chrome/browser/ui/tab_helpers.cc +++ b/chrome/browser/ui/tab_helpers.cc
@@ -118,6 +118,7 @@ #if defined(OS_WIN) || defined(OS_MACOSX) || defined(OS_LINUX) #include "chrome/browser/ui/blocked_content/framebust_block_tab_helper.h" +#include "chrome/browser/ui/hats/hats_helper.h" #endif #if BUILDFLAG(ENABLE_OFFLINE_PAGES) @@ -313,6 +314,13 @@ metrics::DesktopSessionDurationObserver::CreateForWebContents(web_contents); #endif +#if defined(OS_WIN) || defined(OS_MACOSX) || defined(OS_LINUX) + if (base::FeatureList::IsEnabled( + features::kHappinessTrackingSurveysForDesktop)) { + HatsHelper::CreateForWebContents(web_contents); + } +#endif + // --- Feature tab helpers behind flags --- #if BUILDFLAG(ENABLE_OFFLINE_PAGES)
diff --git a/chrome/browser/ui/views/frame/browser_view.cc b/chrome/browser/ui/views/frame/browser_view.cc index 3df230e7..91ca3ec 100644 --- a/chrome/browser/ui/views/frame/browser_view.cc +++ b/chrome/browser/ui/views/frame/browser_view.cc
@@ -84,6 +84,7 @@ #include "chrome/browser/ui/views/frame/top_container_view.h" #include "chrome/browser/ui/views/frame/web_contents_close_handler.h" #include "chrome/browser/ui/views/fullscreen_control/fullscreen_control_host.h" +#include "chrome/browser/ui/views/hats/hats_bubble_view.h" #include "chrome/browser/ui/views/ime/ime_warning_bubble_view.h" #include "chrome/browser/ui/views/infobars/infobar_container_view.h" #include "chrome/browser/ui/views/location_bar/location_bar_view.h" @@ -2842,6 +2843,29 @@ #endif } +#if !defined(OS_ANDROID) +void BrowserView::ShowHatsBubbleFromAppMenuButton() { + // Never show any HaTS bubble in Incognito. + if (!IsRegularOrGuestSession()) + return; + + AppMenuButton* app_menu_button = + toolbar_button_provider()->GetAppMenuButton(); + + // Do not show Hatsbubble if there is no avatar menu button to anchor from + if (!app_menu_button) + return; + + DCHECK(app_menu_button->GetWidget()); + views::BubbleDialogDelegateView* bubble = HatsBubbleView::CreateHatsBubble( + app_menu_button, browser(), + app_menu_button->GetWidget()->GetNativeView()); + + bubble->SetHighlightedButton(app_menu_button); + bubble->GetWidget()->Show(); +} +#endif + void BrowserView::ShowAvatarBubbleFromAvatarButton( AvatarBubbleMode mode, const signin::ManageAccountsParams& manage_accounts_params,
diff --git a/chrome/browser/ui/views/frame/browser_view.h b/chrome/browser/ui/views/frame/browser_view.h index 6c42eb8..bbebcffd 100644 --- a/chrome/browser/ui/views/frame/browser_view.h +++ b/chrome/browser/ui/views/frame/browser_view.h
@@ -392,6 +392,7 @@ FindBar* CreateFindBar() override; web_modal::WebContentsModalDialogHost* GetWebContentsModalDialogHost() override; + void ShowHatsBubbleFromAppMenuButton() override; void ShowAvatarBubbleFromAvatarButton( AvatarBubbleMode mode, const signin::ManageAccountsParams& manage_accounts_params,
diff --git a/chrome/browser/ui/views/hats/hats_browsertest.cc b/chrome/browser/ui/views/hats/hats_browsertest.cc new file mode 100644 index 0000000..86cad24 --- /dev/null +++ b/chrome/browser/ui/views/hats/hats_browsertest.cc
@@ -0,0 +1,30 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include <memory> + +#include "chrome/browser/ui/browser.h" +#include "chrome/browser/ui/test/test_browser_dialog.h" +#include "chrome/browser/ui/views/frame/browser_view.h" +#include "chrome/browser/ui/views/hats/hats_bubble_view.h" + +class HatsBubbleTest : public DialogBrowserTest { + public: + HatsBubbleTest() {} + + // DialogBrowserTest: + void ShowUi(const std::string& name) override { + ASSERT_TRUE(browser()->is_type_tabbed()); + BrowserView::GetBrowserViewForBrowser(InProcessBrowserTest::browser()) + ->ShowHatsBubbleFromAppMenuButton(); + } + + private: + DISALLOW_COPY_AND_ASSIGN(HatsBubbleTest); +}; + +// Test that calls ShowUi("default"). +IN_PROC_BROWSER_TEST_F(HatsBubbleTest, InvokeUi_default) { + ShowAndVerifyUi(); +}
diff --git a/chrome/browser/ui/views/hats/hats_bubble_view.cc b/chrome/browser/ui/views/hats/hats_bubble_view.cc new file mode 100644 index 0000000..2365474c --- /dev/null +++ b/chrome/browser/ui/views/hats/hats_bubble_view.cc
@@ -0,0 +1,67 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/ui/views/hats/hats_bubble_view.h" + +#include "base/macros.h" +#include "base/metrics/user_metrics.h" +#include "base/strings/string16.h" +#include "chrome/browser/platform_util.h" +#include "chrome/browser/ui/browser_dialogs.h" +#include "chrome/browser/ui/views/frame/app_menu_button.h" +#include "content/public/browser/navigation_handle.h" +#include "content/public/browser/web_contents.h" +#include "ui/base/material_design/material_design_controller.h" +#include "ui/base/ui_features.h" +#include "ui/views/layout/grid_layout.h" +#include "ui/views/view.h" +#include "ui/views/widget/widget.h" + +// static +HatsBubbleView* HatsBubbleView::instance_ = nullptr; + +views::BubbleDialogDelegateView* HatsBubbleView::GetHatsBubble() { + return instance_; +} + +// static +views::BubbleDialogDelegateView* HatsBubbleView::CreateHatsBubble( + AppMenuButton* anchor_button, + Browser* browser, + gfx::NativeView parent_view) { + base::RecordAction(base::UserMetricsAction("HatsBubble.Show")); + + return new HatsBubbleView(anchor_button, browser, parent_view); +} + +HatsBubbleView::HatsBubbleView(AppMenuButton* anchor_button, + Browser* browser, + gfx::NativeView parent_view) + : BubbleDialogDelegateView(anchor_button, views::BubbleBorder::TOP_LEFT), + close_bubble_helper_(this, browser) { + chrome::RecordDialogCreation(chrome::DialogIdentifier::HATS_BUBBLE); + + set_parent_window(parent_view); + + // TODO: this->AddChildView(WebUI) + + views::BubbleDialogDelegateView::CreateBubble(this); + + instance_ = this; +} + +HatsBubbleView::~HatsBubbleView() {} + +int HatsBubbleView::GetDialogButtons() const { + return ui::DIALOG_BUTTON_NONE; +} + +bool HatsBubbleView::ShouldShowCloseButton() const { + return true; +} + +void HatsBubbleView::OnWidgetDestroying(views::Widget* widget) { + BubbleDialogDelegateView::OnWidgetDestroying(widget); + instance_ = nullptr; +}
diff --git a/chrome/browser/ui/views/hats/hats_bubble_view.h b/chrome/browser/ui/views/hats/hats_bubble_view.h new file mode 100644 index 0000000..1608412 --- /dev/null +++ b/chrome/browser/ui/views/hats/hats_bubble_view.h
@@ -0,0 +1,46 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_UI_VIEWS_HATS_HATS_BUBBLE_VIEW_H_ +#define CHROME_BROWSER_UI_VIEWS_HATS_HATS_BUBBLE_VIEW_H_ + +#include <stddef.h> + +#include "base/macros.h" +#include "chrome/browser/ui/views/close_bubble_on_tab_activation_helper.h" +#include "ui/views/bubble/bubble_dialog_delegate_view.h" + +class AppMenuButton; + +// This bubble view is displayed when a Happiness tracking survey is triggered. +// It displays a WebUI that hosts the survey. +class HatsBubbleView : public views::BubbleDialogDelegateView { + public: + // Returns a pointer to the Hats Bubble being shown. For testing only. + static views::BubbleDialogDelegateView* GetHatsBubble(); + // Shows the bubble if one is not already showing. + static views::BubbleDialogDelegateView* CreateHatsBubble( + AppMenuButton* anchor_button, + Browser* browser, + gfx::NativeView parent_view); + + protected: + // views::BubbleDialogDelegateView: + int GetDialogButtons() const override; + bool ShouldShowCloseButton() const override; + void OnWidgetDestroying(views::Widget* widget) override; + + private: + HatsBubbleView(AppMenuButton* anchor_button, + Browser* browser, + gfx::NativeView parent_view); + ~HatsBubbleView() override; + + static HatsBubbleView* instance_; + CloseBubbleOnTabActivationHelper close_bubble_helper_; + + DISALLOW_COPY_AND_ASSIGN(HatsBubbleView); +}; + +#endif // CHROME_BROWSER_UI_VIEWS_HATS_HATS_BUBBLE_VIEW_H_
diff --git a/chrome/browser/unified_consent/chrome_unified_consent_service_client.cc b/chrome/browser/unified_consent/chrome_unified_consent_service_client.cc index 6e60b19..fb5c5de 100644 --- a/chrome/browser/unified_consent/chrome_unified_consent_service_client.cc +++ b/chrome/browser/unified_consent/chrome_unified_consent_service_client.cc
@@ -32,10 +32,9 @@ prefs::kNetworkPredictionOptions, pref_service_); ObserveServicePrefChange(Service::kSafeBrowsing, prefs::kSafeBrowsingEnabled, pref_service_); - ObserveServicePrefChange( - Service::kSafeBrowsingExtendedReporting, - safe_browsing::GetExtendedReportingPrefName(*pref_service_), - pref_service_); + ObserveServicePrefChange(Service::kSafeBrowsingExtendedReporting, + prefs::kSafeBrowsingScoutReportingEnabled, + pref_service_); ObserveServicePrefChange(Service::kSearchSuggest, prefs::kSearchSuggestEnabled, pref_service_); ObserveServicePrefChange(Service::kSpellCheck,
diff --git a/chrome/common/page_load_metrics/page_load_metrics.mojom b/chrome/common/page_load_metrics/page_load_metrics.mojom index fbff6e4..9e3a7bc 100644 --- a/chrome/common/page_load_metrics/page_load_metrics.mojom +++ b/chrome/common/page_load_metrics/page_load_metrics.mojom
@@ -167,6 +167,10 @@ // is the aggregate of the |delta_bytes| from each timing update. int64 received_data_length = 0; + // The length of the response body for the resource before removing any + // content encodings. + int64 encoded_body_length = 0; + // Whether this resource load has completed. bool is_complete; @@ -183,6 +187,9 @@ // Whether this resource was loaded in the top-level frame. bool is_main_frame_resource; + // Whether this resource was fetched from the http cache. + bool was_fetched_via_cache; + // Mime type for the resource found in the network response header. string mime_type; };
diff --git a/chrome/common/pref_names.cc b/chrome/common/pref_names.cc index f09813a5..6c7f8282 100644 --- a/chrome/common/pref_names.cc +++ b/chrome/common/pref_names.cc
@@ -869,6 +869,12 @@ // Last time that the kChildScreenTime pref was reset. const char kLastChildScreenTimeReset[] = "last_child_screen_time_reset"; +// Boolean pref indicating whether the NTLM authentication protocol should be +// enabled when mounting an SMB share with a user credential by the Network File +// Shares for Chrome OS feature. +const char kNTLMShareAuthenticationEnabled[] = + "network_file_shares.ntlm_share_authentication.enabled"; + #endif // defined(OS_CHROMEOS) // A boolean pref set to true if a Home button to open the Home pages should be
diff --git a/chrome/common/pref_names.h b/chrome/common/pref_names.h index c6ddc29..d6f88f7 100644 --- a/chrome/common/pref_names.h +++ b/chrome/common/pref_names.h
@@ -280,6 +280,7 @@ extern const char kChildScreenTimeMilliseconds[]; extern const char kLastChildScreenTimeSaved[]; extern const char kLastChildScreenTimeReset[]; +extern const char kNTLMShareAuthenticationEnabled[]; #endif // defined(OS_CHROMEOS) extern const char kShowHomeButton[]; extern const char kSpeechRecognitionFilterProfanities[];
diff --git a/chrome/install_static/install_constants.h b/chrome/install_static/install_constants.h index dfccd1b..cc4a113 100644 --- a/chrome/install_static/install_constants.h +++ b/chrome/install_static/install_constants.h
@@ -65,13 +65,17 @@ // name registered with Default Programs on Windows. const wchar_t* base_app_name; - // The unsuffixed portion of the AppUserModelId. The AppUserModelId is used to - // group an app's windows together on the Windows taskbar along with its + // Used for the following: + // * The unsuffixed portion of the AppUserModelId. The AppUserModelId is used + // to group an app's windows together on the Windows taskbar along with its // corresponding shortcuts; see // https://msdn.microsoft.com/library/windows/desktop/dd378459.aspx for more // information. Use ShellUtil::GetBrowserModelId to get the suffixed value -- // it is almost never correct to use the unsuffixed (base) portion of this id // directly. + // * The prefix for the Elevation Service Name. See + // install_static::GetElevationServiceDisplayName() and + // install_static::GetElevationServiceName(). const wchar_t* base_app_id; // The prefix for the browser's ProgID. This prefix may be no more than 11
diff --git a/chrome/install_static/install_util.cc b/chrome/install_static/install_util.cc index fb6bf84..b9024b28 100644 --- a/chrome/install_static/install_util.cc +++ b/chrome/install_static/install_util.cc
@@ -405,6 +405,18 @@ return InstallDetails::Get().elevator_clsid(); } +std::wstring GetElevationServiceName() { + std::wstring name = GetElevationServiceDisplayName(); + name.erase(std::remove_if(name.begin(), name.end(), isspace), name.end()); + return name; +} + +std::wstring GetElevationServiceDisplayName() { + static constexpr wchar_t kElevationServiceDisplayName[] = + L" Elevation Service"; + return GetBaseAppName() + kElevationServiceDisplayName; +} + std::wstring GetBaseAppName() { return InstallDetails::Get().mode().base_app_name; }
diff --git a/chrome/install_static/install_util.h b/chrome/install_static/install_util.h index 1c2cd074..f04f980 100644 --- a/chrome/install_static/install_util.h +++ b/chrome/install_static/install_util.h
@@ -109,8 +109,10 @@ // the Windows OS. const CLSID& GetToastActivatorClsid(); -// The CLSID of the COM server that provides silent elevation functionality. +// Return the Elevation Service CLSID, Name, and Display Name respectively. const CLSID& GetElevatorClsid(); +std::wstring GetElevationServiceName(); +std::wstring GetElevationServiceDisplayName(); // Returns the unsuffixed application name of this program. This is the base of // the name registered with Default Programs. IMPORTANT: This must only be
diff --git a/chrome/installer/mini_installer/chrome.release b/chrome/installer/mini_installer/chrome.release index 29da5235..01f69e5 100644 --- a/chrome/installer/mini_installer/chrome.release +++ b/chrome/installer/mini_installer/chrome.release
@@ -23,6 +23,7 @@ chrome_elf.dll: %(VersionDir)s\ chrome_watcher.dll: %(VersionDir)s\ d3dcompiler_47.dll: %(VersionDir)s\ +elevation_service.exe: %(VersionDir)s\ eventlog_provider.dll: %(VersionDir)s\ ffmpeg.dll: %(VersionDir)s\ icudt.dll: %(VersionDir)s\
diff --git a/chrome/installer/setup/install_service_work_item.cc b/chrome/installer/setup/install_service_work_item.cc index cbfb0f95..a6caeb9e 100644 --- a/chrome/installer/setup/install_service_work_item.cc +++ b/chrome/installer/setup/install_service_work_item.cc
@@ -4,6 +4,7 @@ #include "chrome/installer/setup/install_service_work_item.h" +#include "base/command_line.h" #include "chrome/installer/setup/install_service_work_item_impl.h" namespace installer { @@ -11,7 +12,7 @@ InstallServiceWorkItem::InstallServiceWorkItem( const base::string16& service_name, const base::string16& display_name, - const base::string16& service_cmd_line) + const base::CommandLine& service_cmd_line) : impl_(std::make_unique<InstallServiceWorkItemImpl>(service_name, display_name, service_cmd_line)) {} @@ -26,4 +27,12 @@ impl_->RollbackImpl(); } +// static +bool InstallServiceWorkItem::DeleteService(const base::string16& service_name) { + return InstallServiceWorkItemImpl( + service_name, base::string16(), + base::CommandLine(base::CommandLine::NO_PROGRAM)) + .DeleteServiceImpl(); +} + } // namespace installer
diff --git a/chrome/installer/setup/install_service_work_item.h b/chrome/installer/setup/install_service_work_item.h index ec480bf1..75bcfd60 100644 --- a/chrome/installer/setup/install_service_work_item.h +++ b/chrome/installer/setup/install_service_work_item.h
@@ -18,6 +18,10 @@ #include "base/strings/string16.h" #include "chrome/installer/util/work_item.h" +namespace base { +class CommandLine; +} // namespace base + namespace installer { class InstallServiceWorkItemImpl; @@ -38,10 +42,12 @@ // "C:\Program Files (x86)\Google\Chrome\ElevationService.exe" /svc InstallServiceWorkItem(const base::string16& service_name, const base::string16& display_name, - const base::string16& service_cmd_line); + const base::CommandLine& service_cmd_line); ~InstallServiceWorkItem() override; + static bool DeleteService(const base::string16& service_name); + private: friend class InstallServiceWorkItemTest;
diff --git a/chrome/installer/setup/install_service_work_item_impl.cc b/chrome/installer/setup/install_service_work_item_impl.cc index 3d983e8..120ddc5 100644 --- a/chrome/installer/setup/install_service_work_item_impl.cc +++ b/chrome/installer/setup/install_service_work_item_impl.cc
@@ -8,6 +8,7 @@ #include <memory> #include <utility> +#include "base/command_line.h" #include "base/logging.h" #include "base/strings/stringprintf.h" #include "base/time/time.h" @@ -59,10 +60,10 @@ InstallServiceWorkItemImpl::InstallServiceWorkItemImpl( const base::string16& service_name, const base::string16& display_name, - const base::string16& service_cmd_line) + const base::CommandLine& service_cmd_line) : service_name_(service_name), display_name_(display_name), - service_cmd_line_(service_cmd_line), + service_cmd_line_(service_cmd_line.GetCommandLineString()), rollback_existing_service_(false), rollback_new_service_(false), original_service_still_exists_(false) {} @@ -140,6 +141,34 @@ LOG_IF(WARNING, !ReinstallOriginalService()); } +bool InstallServiceWorkItemImpl::DeleteServiceImpl() { + scm_.Set(::OpenSCManager(nullptr, nullptr, SC_MANAGER_CONNECT)); + if (!scm_.IsValid()) { + DPLOG(ERROR) << "::OpenSCManager Failed"; + return false; + } + + if (!OpenService()) + return false; + + if (!DeleteCurrentService()) + return false; + + // If the service cannot be deleted, the service name value is not deleted. + // This is to allow for identifying that an existing instance of the service + // is still installed when a future install or upgrade runs. + base::win::RegKey key; + auto result = key.Open(HKEY_LOCAL_MACHINE, + install_static::GetClientStateKeyPath().c_str(), + KEY_SET_VALUE | KEY_WOW64_32KEY); + if (result != ERROR_SUCCESS) + return result == ERROR_FILE_NOT_FOUND || result == ERROR_PATH_NOT_FOUND; + + result = key.DeleteValue(service_name_.c_str()); + return result == ERROR_SUCCESS || result == ERROR_FILE_NOT_FOUND || + result == ERROR_PATH_NOT_FOUND; +} + bool InstallServiceWorkItemImpl::IsServiceCorrectlyConfigured( const ServiceConfig& config) { return config.type == kServiceType && @@ -229,7 +258,7 @@ base::string16 InstallServiceWorkItemImpl::GetCurrentServiceName() const { base::win::RegKey key; - LONG result = key.Open(HKEY_LOCAL_MACHINE, + auto result = key.Open(HKEY_LOCAL_MACHINE, install_static::GetClientStateKeyPath().c_str(), KEY_QUERY_VALUE | KEY_WOW64_32KEY); if (result != ERROR_SUCCESS)
diff --git a/chrome/installer/setup/install_service_work_item_impl.h b/chrome/installer/setup/install_service_work_item_impl.h index 610e827..33d8862 100644 --- a/chrome/installer/setup/install_service_work_item_impl.h +++ b/chrome/installer/setup/install_service_work_item_impl.h
@@ -13,6 +13,12 @@ #include "base/win/scoped_handle.h" #include "base/win/windows_types.h" +namespace base { + +class CommandLine; + +} // namespace base + namespace installer { // Helper class for the implementation of InstallServiceWorkItem. @@ -43,12 +49,13 @@ InstallServiceWorkItemImpl(const base::string16& service_name, const base::string16& display_name, - const base::string16& service_cmd_line); + const base::CommandLine& service_cmd_line); ~InstallServiceWorkItemImpl(); bool DoImpl(); void RollbackImpl(); + bool DeleteServiceImpl(); // Member functions that help with service installation or upgrades. bool IsServiceCorrectlyConfigured(const ServiceConfig& config);
diff --git a/chrome/installer/setup/install_service_work_item_unittest.cc b/chrome/installer/setup/install_service_work_item_unittest.cc index 59bdf11..e06da7ad 100644 --- a/chrome/installer/setup/install_service_work_item_unittest.cc +++ b/chrome/installer/setup/install_service_work_item_unittest.cc
@@ -8,6 +8,8 @@ #include <memory> #include <vector> +#include "base/command_line.h" +#include "base/files/file_path.h" #include "base/stl_util.h" #include "base/win/registry.h" #include "chrome/install_static/install_util.h" @@ -20,7 +22,8 @@ constexpr base::char16 kServiceName[] = L"InstallServiceWorkItemService"; constexpr base::char16 kServiceDisplayName[] = L"InstallServiceWorkItemService"; -constexpr base::char16 kServiceCmdLine[] = L"c:\\windows\\system32\\cmd.exe"; +constexpr base::FilePath::CharType kServiceProgramPath[] = + FILE_PATH_LITERAL("c:\\windows\\system32\\cmd.exe"); } // namespace @@ -63,7 +66,8 @@ TEST_F(InstallServiceWorkItemTest, Do_FreshInstall) { auto item = std::make_unique<InstallServiceWorkItem>( - kServiceName, kServiceDisplayName, kServiceCmdLine); + kServiceName, kServiceDisplayName, + base::CommandLine(base::FilePath(kServiceProgramPath))); ASSERT_TRUE(item->Do()); EXPECT_TRUE(GetImpl(item.get())->OpenService()); @@ -73,16 +77,30 @@ EXPECT_FALSE(GetImpl(item.get())->OpenService()); } +TEST_F(InstallServiceWorkItemTest, Do_FreshInstallThenDeleteService) { + auto item = std::make_unique<InstallServiceWorkItem>( + kServiceName, kServiceDisplayName, + base::CommandLine(base::FilePath(kServiceProgramPath))); + + ASSERT_TRUE(item->Do()); + EXPECT_TRUE(GetImpl(item.get())->OpenService()); + EXPECT_TRUE(IsServiceCorrectlyConfigured(item.get())); + + EXPECT_TRUE(InstallServiceWorkItem::DeleteService(kServiceName)); +} + TEST_F(InstallServiceWorkItemTest, Do_UpgradeNoChanges) { auto item = std::make_unique<InstallServiceWorkItem>( - kServiceName, kServiceDisplayName, kServiceCmdLine); + kServiceName, kServiceDisplayName, + base::CommandLine(base::FilePath(kServiceProgramPath))); ASSERT_TRUE(item->Do()); EXPECT_TRUE(IsServiceCorrectlyConfigured(item.get())); // Same command line: auto item_upgrade = std::make_unique<InstallServiceWorkItem>( - kServiceName, kServiceDisplayName, kServiceCmdLine); + kServiceName, kServiceDisplayName, + base::CommandLine(base::FilePath(kServiceProgramPath))); EXPECT_TRUE(item_upgrade->Do()); item_upgrade->Rollback(); @@ -93,14 +111,16 @@ TEST_F(InstallServiceWorkItemTest, Do_UpgradeChangedCmdLine) { auto item = std::make_unique<InstallServiceWorkItem>( - kServiceName, kServiceDisplayName, kServiceCmdLine); + kServiceName, kServiceDisplayName, + base::CommandLine(base::FilePath(kServiceProgramPath))); ASSERT_TRUE(item->Do()); EXPECT_TRUE(IsServiceCorrectlyConfigured(item.get())); // New command line. auto item_upgrade = std::make_unique<InstallServiceWorkItem>( - kServiceName, kServiceDisplayName, L"NewCmd.exe new cmd line"); + kServiceName, kServiceDisplayName, + base::CommandLine::FromString(L"NewCmd.exe arg1 arg2")); EXPECT_TRUE(item_upgrade->Do()); item_upgrade->Rollback(); @@ -119,7 +139,8 @@ install_static::GetClientStateKeyPath().c_str(), KEY_WRITE | KEY_WOW64_32KEY)); auto item = std::make_unique<InstallServiceWorkItem>( - kServiceName, kServiceDisplayName, kServiceCmdLine); + kServiceName, kServiceDisplayName, + base::CommandLine(base::FilePath(kServiceProgramPath))); EXPECT_STREQ(kServiceName, GetImpl(item.get())->GetCurrentServiceName().c_str());
diff --git a/chrome/installer/setup/install_worker.cc b/chrome/installer/setup/install_worker.cc index b837e1b..84b6268b 100644 --- a/chrome/installer/setup/install_worker.cc +++ b/chrome/installer/setup/install_worker.cc
@@ -36,6 +36,7 @@ #include "chrome/install_static/install_details.h" #include "chrome/install_static/install_modes.h" #include "chrome/install_static/install_util.h" +#include "chrome/installer/setup/install_service_work_item.h" #include "chrome/installer/setup/installer_state.h" #include "chrome/installer/setup/setup_constants.h" #include "chrome/installer/setup/setup_util.h" @@ -429,6 +430,42 @@ static_cast<DWORD>(consent), true); } +// Adds work items to register the Elevation Service with Windows. Only for +// system level installs. +void AddElevationServiceWorkItems(const base::FilePath& elevation_service_path, + WorkItemList* list) { + DCHECK(::IsUserAnAdmin()); + const HKEY root = HKEY_LOCAL_MACHINE; + + if (elevation_service_path.empty()) { + LOG(DFATAL) << "The path to elevation_service.exe is invalid."; + return; + } + + const base::string16 clsid_reg_path = GetElevationServiceClsidRegistryPath(); + const base::string16 appid_reg_path = GetElevationServiceAppidRegistryPath(); + + // Delete any old registrations first, taking into account 32-bit -> 64-bit or + // 64-bit -> 32-bit migration. + for (const auto& reg_path : {clsid_reg_path, appid_reg_path}) { + for (const auto& key_flag : {KEY_WOW64_32KEY, KEY_WOW64_64KEY}) + list->AddDeleteRegKeyWorkItem(root, reg_path, key_flag); + } + + list->AddWorkItem(new InstallServiceWorkItem( + install_static::GetElevationServiceName(), + install_static::GetElevationServiceDisplayName(), + base::CommandLine(elevation_service_path))); + + list->AddCreateRegKeyWorkItem(root, clsid_reg_path, WorkItem::kWow64Default); + list->AddSetRegValueWorkItem(root, clsid_reg_path, WorkItem::kWow64Default, + L"AppID", GetElevationServiceGuid(L""), true); + list->AddCreateRegKeyWorkItem(root, appid_reg_path, WorkItem::kWow64Default); + list->AddSetRegValueWorkItem(root, appid_reg_path, WorkItem::kWow64Default, + L"LocalService", + install_static::GetElevationServiceName(), true); +} + } // namespace // This method adds work items to create (or update) Chrome uninstall entry in @@ -850,6 +887,11 @@ installer_state.root_key(), GetNotificationHelperPath(target_path, new_version), install_list); + if (installer_state.system_install()) { + AddElevationServiceWorkItems( + GetElevationServicePath(target_path, new_version), install_list); + } + InstallUtil::AddUpdateDowngradeVersionItem( installer_state.root_key(), current_version, new_version, install_list);
diff --git a/chrome/installer/setup/setup_util.cc b/chrome/installer/setup/setup_util.cc index 76294c6c..20efce4 100644 --- a/chrome/installer/setup/setup_util.cc +++ b/chrome/installer/setup/setup_util.cc
@@ -858,4 +858,25 @@ .Append(kNotificationHelperExe); } +base::FilePath GetElevationServicePath(const base::FilePath& target_path, + const base::Version& version) { + return target_path.AppendASCII(version.GetString()) + .Append(kElevationServiceExe); +} + +base::string16 GetElevationServiceGuid(base::StringPiece16 prefix) { + base::string16 result = + InstallUtil::String16FromGUID(install_static::GetElevatorClsid()); + result.insert(0, prefix.data(), prefix.size()); + return result; +} + +base::string16 GetElevationServiceClsidRegistryPath() { + return GetElevationServiceGuid(L"Software\\Classes\\CLSID\\"); +} + +base::string16 GetElevationServiceAppidRegistryPath() { + return GetElevationServiceGuid(L"Software\\Classes\\AppID\\"); +} + } // namespace installer
diff --git a/chrome/installer/setup/setup_util.h b/chrome/installer/setup/setup_util.h index f1e921c..bf5e00a1 100644 --- a/chrome/installer/setup/setup_util.h +++ b/chrome/installer/setup/setup_util.h
@@ -12,6 +12,7 @@ #include <stdint.h> #include <memory> +#include <string> #include <vector> #include "base/optional.h" @@ -157,6 +158,17 @@ base::FilePath GetNotificationHelperPath(const base::FilePath& target_path, const base::Version& version); +// Returns the file path to elevation_service.exe (in |version| directory). +base::FilePath GetElevationServicePath(const base::FilePath& target_path, + const base::Version& version); + +// Returns the Elevation Service GUID prefixed with |prefix|. +base::string16 GetElevationServiceGuid(base::StringPiece16 prefix); + +// Return the elevation service registry paths. +base::string16 GetElevationServiceClsidRegistryPath(); +base::string16 GetElevationServiceAppidRegistryPath(); + } // namespace installer #endif // CHROME_INSTALLER_SETUP_SETUP_UTIL_H_
diff --git a/chrome/installer/setup/uninstall.cc b/chrome/installer/setup/uninstall.cc index 189b970..75deeac 100644 --- a/chrome/installer/setup/uninstall.cc +++ b/chrome/installer/setup/uninstall.cc
@@ -35,6 +35,7 @@ #include "chrome/install_static/install_util.h" #include "chrome/installer/setup/brand_behaviors.h" #include "chrome/installer/setup/install.h" +#include "chrome/installer/setup/install_service_work_item.h" #include "chrome/installer/setup/install_worker.h" #include "chrome/installer/setup/installer_state.h" #include "chrome/installer/setup/launch_chrome.h" @@ -633,6 +634,19 @@ LOG(DFATAL) << "Cannot retrieve the toast activator registry path"; } + if (installer_state.system_install()) { + // Delete Software\Classes\CLSID and AppId\|elevation_service_clsid|. + const base::string16 clsid_reg_path = + GetElevationServiceClsidRegistryPath(); + const base::string16 appid_reg_path = + GetElevationServiceAppidRegistryPath(); + for (const auto& reg_path : {clsid_reg_path, appid_reg_path}) + InstallUtil::DeleteRegistryKey(root, reg_path, WorkItem::kWow64Default); + + LOG_IF(WARNING, !InstallServiceWorkItem::DeleteService( + install_static::GetElevationServiceName())); + } + // Delete all Start Menu Internet registrations that refer to this Chrome. { using base::win::RegistryKeyIterator;
diff --git a/chrome/installer/util/install_util.cc b/chrome/installer/util/install_util.cc index 5febc08..c53541e7 100644 --- a/chrome/installer/util/install_util.cc +++ b/chrome/installer/util/install_util.cc
@@ -392,18 +392,23 @@ } // static -base::string16 InstallUtil::GetToastActivatorRegistryPath() { - // CLSID has a string format of "{xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}", - // which contains 38 characters. The length is 39 to make space for the - // string terminator. +base::string16 InstallUtil::String16FromGUID(const GUID& guid) { + // A GUID has a string format of "{xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}", + // which contains 38 characters. The length is 39 inclusive of the string + // terminator. constexpr int kGuidLength = 39; base::string16 guid_string; - if (::StringFromGUID2(install_static::GetToastActivatorClsid(), - base::WriteInto(&guid_string, kGuidLength), - kGuidLength) != kGuidLength) { - return base::string16(); - } - return L"Software\\Classes\\CLSID\\" + guid_string; + + const int length_with_terminator = ::StringFromGUID2( + guid, base::WriteInto(&guid_string, kGuidLength), kGuidLength); + DCHECK_EQ(length_with_terminator, kGuidLength); + return guid_string; +} + +// static +base::string16 InstallUtil::GetToastActivatorRegistryPath() { + return L"Software\\Classes\\CLSID\\" + + String16FromGUID(install_static::GetToastActivatorClsid()); } // static
diff --git a/chrome/installer/util/install_util.h b/chrome/installer/util/install_util.h index 9f6b3e6..332e153d 100644 --- a/chrome/installer/util/install_util.h +++ b/chrome/installer/util/install_util.h
@@ -81,8 +81,10 @@ // CLSID registered. static bool IsStartMenuShortcutWithActivatorGuidInstalled(); - // Returns the toast activator registry path if found, or an empty string in - // case of error. + // Returns a string representation of |guid|. + static base::string16 String16FromGUID(const GUID& guid); + + // Returns the toast activator registry path. static base::string16 GetToastActivatorRegistryPath(); // Populates |path| with EULA sentinel file path. Returns false on error.
diff --git a/chrome/installer/util/util_constants.cc b/chrome/installer/util/util_constants.cc index 2d4b8ac..38d6a94 100644 --- a/chrome/installer/util/util_constants.cc +++ b/chrome/installer/util/util_constants.cc
@@ -205,6 +205,10 @@ const wchar_t kUninstallDisplayNameField[] = L"DisplayName"; const wchar_t kUninstallInstallationDate[] = L"installation_date"; +// Elevation Service constants. +const base::FilePath::CharType kElevationServiceExe[] = + FILE_PATH_LITERAL("elevation_service.exe"); + // Google Update installer result API. const wchar_t kInstallerError[] = L"InstallerError"; const wchar_t kInstallerExtraCode1[] = L"InstallerExtraCode1";
diff --git a/chrome/installer/util/util_constants.h b/chrome/installer/util/util_constants.h index 9e39d2c5..a2b932c 100644 --- a/chrome/installer/util/util_constants.h +++ b/chrome/installer/util/util_constants.h
@@ -10,6 +10,8 @@ #include <stddef.h> +#include "base/files/file_path.h" + namespace installer { // Return status of installer. Values in this enum must not change. Always add @@ -218,6 +220,9 @@ extern const wchar_t kUninstallInstallationDate[]; extern const wchar_t kUninstallStringField[]; +// Elevation Service constants. +extern const base::FilePath::CharType kElevationServiceExe[]; + // Google Update installer result API. extern const wchar_t kInstallerError[]; extern const wchar_t kInstallerExtraCode1[];
diff --git a/chrome/renderer/page_load_metrics/page_resource_data_use.cc b/chrome/renderer/page_load_metrics/page_resource_data_use.cc index 2aa2752..091d32e 100644 --- a/chrome/renderer/page_load_metrics/page_resource_data_use.cc +++ b/chrome/renderer/page_load_metrics/page_resource_data_use.cc
@@ -19,7 +19,8 @@ is_complete_(false), is_canceled_(false), reported_as_ad_resource_(false), - is_main_frame_resource_(false) {} + is_main_frame_resource_(false), + was_fetched_via_cache_(false) {} PageResourceDataUse::PageResourceDataUse(const PageResourceDataUse& other) = default; @@ -34,6 +35,7 @@ mime_type_ = response_head.mime_type; total_received_bytes_ = 0; last_update_bytes_ = 0; + was_fetched_via_cache_ = response_head.was_fetched_via_cache; } void PageResourceDataUse::DidReceiveTransferSizeUpdate( @@ -45,6 +47,7 @@ const network::URLLoaderCompletionStatus& status) { // Report the difference in received bytes. is_complete_ = true; + encoded_body_length_ = status.encoded_body_length; int64_t delta_bytes = status.encoded_data_length - total_received_bytes_; if (delta_bytes > 0) { total_received_bytes_ += delta_bytes; @@ -89,6 +92,8 @@ resource_data_update->reported_as_ad_resource = reported_as_ad_resource_; resource_data_update->is_main_frame_resource = is_main_frame_resource_; resource_data_update->mime_type = mime_type_; + resource_data_update->encoded_body_length = encoded_body_length_; + resource_data_update->was_fetched_via_cache = was_fetched_via_cache_; return resource_data_update; } } // namespace page_load_metrics
diff --git a/chrome/renderer/page_load_metrics/page_resource_data_use.h b/chrome/renderer/page_load_metrics/page_resource_data_use.h index 278a783..aab2340c 100644 --- a/chrome/renderer/page_load_metrics/page_resource_data_use.h +++ b/chrome/renderer/page_load_metrics/page_resource_data_use.h
@@ -62,11 +62,13 @@ uint64_t total_received_bytes_; uint64_t last_update_bytes_; + uint64_t encoded_body_length_ = 0; bool is_complete_; bool is_canceled_; bool reported_as_ad_resource_; bool is_main_frame_resource_; + bool was_fetched_via_cache_; std::string mime_type_;
diff --git a/chrome/services/media_gallery_util/media_parser_android.cc b/chrome/services/media_gallery_util/media_parser_android.cc index 7aa662c..b1317d9f 100644 --- a/chrome/services/media_gallery_util/media_parser_android.cc +++ b/chrome/services/media_gallery_util/media_parser_android.cc
@@ -4,6 +4,7 @@ #include "chrome/services/media_gallery_util/media_parser_android.h" +#include "base/optional.h" #include "base/task/post_task.h" #include "base/task/task_traits.h" #include "chrome/services/media_gallery_util/ipc_data_source.h" @@ -28,7 +29,7 @@ if (!frame) { std::move(video_frame_callback) - .Run(false, chrome::mojom::VideoFrameData::New(), config); + .Run(false, chrome::mojom::VideoFrameData::New(), base::nullopt); return; } @@ -47,7 +48,7 @@ const media::VideoDecoderConfig& config) { if (!success || data.empty()) { std::move(video_frame_callback) - .Run(false, chrome::mojom::VideoFrameData::New(), config); + .Run(false, chrome::mojom::VideoFrameData::New(), base::nullopt); return; } @@ -67,7 +68,7 @@ if (config.codec() != media::VideoCodec::kCodecVP8 && config.codec() != media::VideoCodec::kCodecVP9) { std::move(video_frame_callback) - .Run(false, chrome::mojom::VideoFrameData::New(), config); + .Run(false, chrome::mojom::VideoFrameData::New(), base::nullopt); return; }
diff --git a/chrome/services/media_gallery_util/media_parser_android_unittest.cc b/chrome/services/media_gallery_util/media_parser_android_unittest.cc index 14b0a43..5b009985 100644 --- a/chrome/services/media_gallery_util/media_parser_android_unittest.cc +++ b/chrome/services/media_gallery_util/media_parser_android_unittest.cc
@@ -9,6 +9,7 @@ #include "base/bind_helpers.h" #include "base/files/file_util.h" +#include "base/files/scoped_temp_dir.h" #include "base/macros.h" #include "base/run_loop.h" #include "base/test/bind_test_util.h" @@ -25,7 +26,7 @@ struct ExtractVideoFrameResult { bool success = false; chrome::mojom::VideoFrameDataPtr video_frame_data; - media::VideoDecoderConfig config; + base::Optional<media::VideoDecoderConfig> config; }; #if BUILDFLAG(USE_PROPRIETARY_CODECS) @@ -87,6 +88,7 @@ void SetUp() override { parser_ = std::make_unique<MediaParserAndroid>(ref_factory_.CreateRef()); + ASSERT_TRUE(temp_dir_.CreateUniqueTempDir()); } void TearDown() override { parser_.reset(); } @@ -94,9 +96,10 @@ protected: MediaParserAndroid* parser() { return parser_.get(); } - ExtractVideoFrameResult ExtractFrame(const std::string& file_name, + const base::FilePath& temp_dir() const { return temp_dir_.GetPath(); } + + ExtractVideoFrameResult ExtractFrame(const base::FilePath& file_path, const std::string& mime_type) { - auto file_path = media::GetTestDataFilePath(file_name); int64_t size = 0; EXPECT_TRUE(base::GetFileSize(file_path, &size)); @@ -109,7 +112,7 @@ mime_type, size, std::move(data_source_ptr), base::BindLambdaForTesting( [&](bool success, chrome::mojom::VideoFrameDataPtr video_frame_data, - const media::VideoDecoderConfig& config) { + const base::Optional<media::VideoDecoderConfig>& config) { result.success = success; result.video_frame_data = std::move(video_frame_data); result.config = config; @@ -123,6 +126,7 @@ private: std::unique_ptr<MediaParserAndroid> parser_; + base::ScopedTempDir temp_dir_; service_manager::ServiceContextRefFactory ref_factory_; base::test::ScopedTaskEnvironment scoped_task_environment_; @@ -134,7 +138,8 @@ // Test to verify an encoded video frame can be extracted for h264 codec video // file. Decoding needs to happen in other process. TEST_F(MediaParserAndroidTest, VideoFrameExtractionH264) { - auto result = ExtractFrame("bear.mp4", "video/mp4"); + auto result = + ExtractFrame(media::GetTestDataFilePath("bear.mp4"), "video/mp4"); EXPECT_TRUE(result.success); EXPECT_EQ(result.video_frame_data->which(), chrome::mojom::VideoFrameData::Tag::ENCODED_DATA); @@ -146,7 +151,8 @@ // Test to verify a decoded video frame can be extracted for vp8 codec video // file with YUV420 color format. TEST_F(MediaParserAndroidTest, VideoFrameExtractionVp8) { - auto result = ExtractFrame("bear-vp8-webvtt.webm", "video/webm"); + auto result = ExtractFrame(media::GetTestDataFilePath("bear-vp8-webvtt.webm"), + "video/webm"); EXPECT_TRUE(result.success); EXPECT_EQ(result.video_frame_data->which(), chrome::mojom::VideoFrameData::Tag::DECODED_FRAME); @@ -162,7 +168,8 @@ // Test to verify a decoded video frame can be extracted for vp8 codec with // alpha plane. TEST_F(MediaParserAndroidTest, VideoFrameExtractionVp8WithAlphaPlane) { - auto result = ExtractFrame("bear-vp8a.webm", "video/webm"); + auto result = + ExtractFrame(media::GetTestDataFilePath("bear-vp8a.webm"), "video/webm"); EXPECT_TRUE(result.success); EXPECT_EQ(result.video_frame_data->which(), @@ -176,4 +183,13 @@ media::VideoFrame::StorageType::STORAGE_MOJO_SHARED_BUFFER); } +// Test to verify frame extraction will fail on invalid video file. +TEST_F(MediaParserAndroidTest, VideoFrameExtractionInvalidFile) { + base::FilePath dummy_file = temp_dir().AppendASCII("test.txt"); + EXPECT_GT(base::WriteFile(dummy_file, "123", sizeof("123")), 0); + + auto result = ExtractFrame(dummy_file, "video/webm"); + EXPECT_FALSE(result.success); +} + } // namespace
diff --git a/chrome/services/media_gallery_util/public/mojom/media_parser.mojom b/chrome/services/media_gallery_util/public/mojom/media_parser.mojom index cb381b6..4ac236e8 100644 --- a/chrome/services/media_gallery_util/public/mojom/media_parser.mojom +++ b/chrome/services/media_gallery_util/public/mojom/media_parser.mojom
@@ -38,7 +38,7 @@ MediaDataSource media_data_source) => (bool success, VideoFrameData frame_data, - media.mojom.VideoDecoderConfig config); + media.mojom.VideoDecoderConfig? config); // Validates the passed media file with sanity checks, and file decoding // for at most |decode_time| wall clock time. Returns |success| true if
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn index 35cf2b4d..7cfc24b 100644 --- a/chrome/test/BUILD.gn +++ b/chrome/test/BUILD.gn
@@ -255,6 +255,10 @@ "../browser/chromeos/ownership/fake_owner_settings_service.h", "../browser/chromeos/settings/scoped_cros_settings_test_helper.cc", "../browser/chromeos/settings/scoped_cros_settings_test_helper.h", + "../browser/component_updater/fake_cros_component_manager.cc", + "../browser/component_updater/fake_cros_component_manager.h", + "base/browser_process_platform_part_test_api_chromeos.cc", + "base/browser_process_platform_part_test_api_chromeos.h", "base/default_ash_event_generator_delegate.cc", "base/default_ash_event_generator_delegate.h", ] @@ -908,6 +912,7 @@ "../browser/ui/views/chrome_cleaner_reboot_dialog_browsertest_win.cc", "../browser/ui/views/content_setting_bubble_contents_browsertest.cc", "../browser/ui/views/device_chooser_browsertest.cc", + "../browser/ui/views/hats/hats_browsertest.cc", "../browser/ui/views/try_chrome_dialog_win/try_chrome_dialog_browsertest.cc", "../browser/ui/views/webauthn/authenticator_dialog_view_browsertest.cc", "../browser/ui/webauthn/authenticator_dialog_browsertest.cc", @@ -3529,6 +3534,7 @@ "../browser/extensions/api/file_system/file_system_api_unittest.cc", "../browser/extensions/api/identity/extension_token_key_unittest.cc", "../browser/extensions/api/identity/gaia_web_auth_flow_unittest.cc", + "../browser/extensions/api/identity/identity_api_unittest.cc", "../browser/extensions/api/identity/identity_mint_queue_unittest.cc", "../browser/extensions/api/image_writer_private/destroy_partitions_operation_unittest.cc", "../browser/extensions/api/image_writer_private/operation_manager_unittest.cc",
diff --git a/chrome/test/base/browser_process_platform_part_test_api_chromeos.cc b/chrome/test/base/browser_process_platform_part_test_api_chromeos.cc new file mode 100644 index 0000000..56a6017 --- /dev/null +++ b/chrome/test/base/browser_process_platform_part_test_api_chromeos.cc
@@ -0,0 +1,34 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/test/base/browser_process_platform_part_test_api_chromeos.h" + +#include <utility> + +#include "chrome/browser/browser_process_platform_part_chromeos.h" +#include "chrome/browser/component_updater/cros_component_manager.h" + +BrowserProcessPlatformPartTestApi::BrowserProcessPlatformPartTestApi( + BrowserProcessPlatformPart* platform_part) + : platform_part_(platform_part) {} + +BrowserProcessPlatformPartTestApi::~BrowserProcessPlatformPartTestApi() { + DCHECK(!platform_part_->using_testing_cros_component_manager_); +} + +void BrowserProcessPlatformPartTestApi::InitializeCrosComponentManager( + std::unique_ptr<component_updater::CrOSComponentManager> + cros_component_manager) { + DCHECK(!platform_part_->using_testing_cros_component_manager_); + DCHECK(!platform_part_->cros_component_manager_); + + platform_part_->using_testing_cros_component_manager_ = true; + platform_part_->cros_component_manager_ = std::move(cros_component_manager); +} + +void BrowserProcessPlatformPartTestApi::ShutdownCrosComponentManager() { + DCHECK(platform_part_->using_testing_cros_component_manager_); + platform_part_->using_testing_cros_component_manager_ = false; + platform_part_->cros_component_manager_.reset(); +}
diff --git a/chrome/test/base/browser_process_platform_part_test_api_chromeos.h b/chrome/test/base/browser_process_platform_part_test_api_chromeos.h new file mode 100644 index 0000000..e87d000 --- /dev/null +++ b/chrome/test/base/browser_process_platform_part_test_api_chromeos.h
@@ -0,0 +1,41 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_TEST_BASE_BROWSER_PROCESS_PLATFORM_PART_TEST_API_CHROMEOS_H_ +#define CHROME_TEST_BASE_BROWSER_PROCESS_PLATFORM_PART_TEST_API_CHROMEOS_H_ + +#include <memory> + +#include "base/macros.h" + +class BrowserProcessPlatformPart; + +namespace component_updater { +class CrOSComponentManager; +} + +// Used to override parts of BrowserProcessPlatformParts in tests. +class BrowserProcessPlatformPartTestApi { + public: + explicit BrowserProcessPlatformPartTestApi( + BrowserProcessPlatformPart* platform_part); + ~BrowserProcessPlatformPartTestApi(); + + // Initializes cros component manager for tests. Expects that cros component + // manager has not previously been initialized. + void InitializeCrosComponentManager( + std::unique_ptr<component_updater::CrOSComponentManager> + cros_component_manager); + + // Shuts down the cros component manager set by + // InitializeCrosComponentManager(). + void ShutdownCrosComponentManager(); + + private: + BrowserProcessPlatformPart* const platform_part_; + + DISALLOW_COPY_AND_ASSIGN(BrowserProcessPlatformPartTestApi); +}; + +#endif // CHROME_TEST_BASE_BROWSER_PROCESS_PLATFORM_PART_TEST_API_CHROMEOS_H_
diff --git a/chrome/test/base/test_browser_window.h b/chrome/test/base/test_browser_window.h index 7e9cbb0..4d5e2b67 100644 --- a/chrome/test/base/test_browser_window.h +++ b/chrome/test/base/test_browser_window.h
@@ -10,6 +10,7 @@ #include <vector> #include "base/macros.h" +#include "build/build_config.h" #include "chrome/browser/download/test_download_shelf.h" #include "chrome/browser/ui/browser.h" #include "chrome/browser/ui/browser_dialogs.h" @@ -149,6 +150,12 @@ const signin::ManageAccountsParams& manage_accounts_params, signin_metrics::AccessPoint access_point, bool is_source_keyboard) override {} + +#if defined(OS_CHROMEOS) || defined(OS_MACOSX) || defined(OS_WIN) || \ + defined(OS_LINUX) + void ShowHatsBubbleFromAppMenuButton() override {} +#endif + int GetRenderViewHeightInsetWithDetachedBookmarkBar() override; void ExecuteExtensionCommand(const extensions::Extension* extension, const extensions::Command& command) override;
diff --git a/chrome/test/chromedriver/chrome/chrome_desktop_impl.cc b/chrome/test/chromedriver/chrome/chrome_desktop_impl.cc index c5c54c4..0f1889bc 100644 --- a/chrome/test/chromedriver/chrome/chrome_desktop_impl.cc +++ b/chrome/test/chromedriver/chrome/chrome_desktop_impl.cc
@@ -176,6 +176,22 @@ if (status.IsError()) return Status(kUnknownError, "cannot get automation extension", status); + // The automation extension page has been loaded, but it might not be + // initialized yet. Wait for up to 10 seconds for a function on the page + // to become defined, as a signal that the page is initialized. + base::TimeTicks deadline = + base::TimeTicks::Now() + base::TimeDelta::FromSeconds(10); + while (base::TimeTicks::Now() < deadline) { + std::unique_ptr<base::Value> result; + status = web_view->EvaluateScript( + std::string(), "typeof launchApp === 'function'", &result); + if (status.IsError()) + return Status(kUnknownError, "cannot get automation extension", status); + if (result->is_bool() && result->GetBool()) + break; + base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(50)); + } + automation_extension_.reset(new AutomationExtension(std::move(web_view))); } *extension = automation_extension_.get();
diff --git a/chrome/test/chromedriver/client/chromedriver.py b/chrome/test/chromedriver/client/chromedriver.py index f1d3074..4d9bcde 100644 --- a/chrome/test/chromedriver/client/chromedriver.py +++ b/chrome/test/chromedriver/client/chromedriver.py
@@ -12,6 +12,7 @@ ELEMENT_KEY_W3C = "element-6066-11e4-a52e-4f735466cecf" ELEMENT_KEY = "ELEMENT" +MAX_RETRY_COUNT = 3 class ChromeDriverException(Exception): pass @@ -122,17 +123,32 @@ class ChromeDriver(object): """Starts and controls a single Chrome instance on this machine.""" - def __init__(self, server_url, chrome_binary=None, android_package=None, - android_activity=None, android_process=None, - android_use_running_app=None, chrome_switches=None, - chrome_extensions=None, chrome_log_path=None, - debugger_address=None, logging_prefs=None, - mobile_emulation=None, experimental_options=None, - download_dir=None, network_connection=None, - send_w3c_capability=None, send_w3c_request=None, - page_load_strategy=None, unexpected_alert_behaviour=None, - devtools_events_to_log=None, accept_insecure_certs=None, - timeouts=None, test_name=None): + retry_count = 0 + + def __init__(self, *args, **kwargs): + try: + self._InternalInit(*args, **kwargs) + except Exception as e: + if not e.message.startswith('timed out'): + raise + else: + if ChromeDriver.retry_count < MAX_RETRY_COUNT: + ChromeDriver.retry_count = ChromeDriver.retry_count + 1 + self._InternalInit(*args, **kwargs) + else: + raise + + def _InternalInit(self, server_url, chrome_binary=None, android_package=None, + android_activity=None, android_process=None, + android_use_running_app=None, chrome_switches=None, + chrome_extensions=None, chrome_log_path=None, + debugger_address=None, logging_prefs=None, + mobile_emulation=None, experimental_options=None, + download_dir=None, network_connection=None, + send_w3c_capability=None, send_w3c_request=None, + page_load_strategy=None, unexpected_alert_behaviour=None, + devtools_events_to_log=None, accept_insecure_certs=None, + timeouts=None, test_name=None): self._executor = command_executor.CommandExecutor(server_url) self.w3c_compliant = False
diff --git a/chrome/test/chromedriver/net/websocket.cc b/chrome/test/chromedriver/net/websocket.cc index c8f01bd..1eacaf3 100644 --- a/chrome/test/chromedriver/net/websocket.cc +++ b/chrome/test/chromedriver/net/websocket.cc
@@ -59,14 +59,17 @@ } // namespace -WebSocket::WebSocket(const GURL& url, WebSocketListener* listener) +WebSocket::WebSocket(const GURL& url, + WebSocketListener* listener, + size_t read_buffer_size) : url_(url), listener_(listener), state_(INITIALIZED), write_buffer_(base::MakeRefCounted<net::DrainableIOBuffer>( base::MakeRefCounted<net::IOBuffer>(0), 0)), - read_buffer_(base::MakeRefCounted<net::IOBufferWithSize>(4096)) {} + read_buffer_( + base::MakeRefCounted<net::IOBufferWithSize>(read_buffer_size)) {} WebSocket::~WebSocket() { CHECK(thread_checker_.CalledOnValidThread());
diff --git a/chrome/test/chromedriver/net/websocket.h b/chrome/test/chromedriver/net/websocket.h index afbc9932..e67e0f4 100644 --- a/chrome/test/chromedriver/net/websocket.h +++ b/chrome/test/chromedriver/net/websocket.h
@@ -28,7 +28,9 @@ class WebSocket { public: // |url| must be an IP v4/v6 literal, not a host name. - WebSocket(const GURL& url, WebSocketListener* listener); + WebSocket(const GURL& url, + WebSocketListener* listener, + size_t read_buffer_size = 4096); virtual ~WebSocket(); // Initializes the WebSocket connection. Invokes the given callback with
diff --git a/chrome/test/chromedriver/net/websocket_unittest.cc b/chrome/test/chromedriver/net/websocket_unittest.cc index 352a89f8..65690d7 100644 --- a/chrome/test/chromedriver/net/websocket_unittest.cc +++ b/chrome/test/chromedriver/net/websocket_unittest.cc
@@ -91,7 +91,10 @@ std::unique_ptr<WebSocket> CreateWebSocket(const GURL& url, WebSocketListener* listener) { int error; - std::unique_ptr<WebSocket> sock(new WebSocket(url, listener)); + std::unique_ptr<WebSocket> sock( + read_buffer_size_ == 0 + ? new WebSocket(url, listener) + : new WebSocket(url, listener, read_buffer_size_)); base::RunLoop run_loop; sock->Connect(base::Bind(&OnConnectFinished, &run_loop, &error)); loop_.task_runner()->PostDelayedTask(FROM_HERE, run_loop.QuitClosure(), @@ -120,8 +123,11 @@ run_loop.Run(); } + void SetReadBufferSize(size_t size) { read_buffer_size_ = size; } + base::MessageLoopForIO loop_; TestHttpServer server_; + size_t read_buffer_size_ = 0; }; } // namespace @@ -195,6 +201,16 @@ SendReceive(messages); } +TEST_F(WebSocketTest, SendReceiveManyPacks) { + std::vector<std::string> messages; + // A message size of 1 << 16 crashes code with https://crbug.com/877105 bug + // on Linux and Windows, but a size of 1 << 17 is needed to cause crash on + // Mac. We use message size 1 << 18 for some extra margin to ensure bug repro. + messages.push_back(std::string(1 << 18, 'a')); + SetReadBufferSize(1); + SendReceive(messages); +} + TEST_F(WebSocketTest, SendReceiveMultiple) { std::vector<std::string> messages; messages.push_back("1");
diff --git a/chrome/test/chromedriver/test/run_py_tests.py b/chrome/test/chromedriver/test/run_py_tests.py index 9dcf8d6..8cdbecff 100755 --- a/chrome/test/chromedriver/test/run_py_tests.py +++ b/chrome/test/chromedriver/test/run_py_tests.py
@@ -2984,6 +2984,14 @@ self.CreateDriver('http://[::1]:' + str(chromedriver_server.GetPort())) + +# 'Z' in the beginning is to make test executed in the end of suite. +class ZChromeStartRetryCountTest(unittest.TestCase): + + def testChromeStartRetryCount(self): + self.assertEquals(0, chromedriver.ChromeDriver.retry_count, + "Chrome was retried to start during suite execution") + if __name__ == '__main__': parser = optparse.OptionParser() parser.add_option(
diff --git a/chrome/test/data/policy/policy_test_cases.json b/chrome/test/data/policy/policy_test_cases.json index 9dbe4798..7fef3a56 100644 --- a/chrome/test/data/policy/policy_test_cases.json +++ b/chrome/test/data/policy/policy_test_cases.json
@@ -3371,6 +3371,14 @@ ] }, + "NTLMShareAuthenticationEnabled": { + "os": ["chromeos"], + "test_policy": { "NTLMShareAuthenticationEnabled": true }, + "pref_mappings": [ + { "pref": "network_file_shares.ntlm_share_authentication.enabled" } + ] + }, + "----- Chrome OS device policies ---------------------------------------": {}, "DevicePolicyRefreshRate": {
diff --git a/chrome/test/mini_installer/config/chrome_beta_installed.prop b/chrome/test/mini_installer/config/chrome_beta_installed.prop index 9c4efb5..a03cc61 100644 --- a/chrome/test/mini_installer/config/chrome_beta_installed.prop +++ b/chrome/test/mini_installer/config/chrome_beta_installed.prop
@@ -50,6 +50,12 @@ "data": "$LOCAL_APPDATA\\$CHROME_DIR_BETA\\Application\\$MINI_INSTALLER_FILE_VERSION\\notification_helper.exe" } }, + "HKEY_CURRENT_USER\\Software\\Classes\\CLSID\\$CHROME_ELEVATOR_CLSID_BETA": { + "exists": "forbidden" + }, + "HKEY_CURRENT_USER\\Software\\Classes\\AppID\\$CHROME_ELEVATOR_CLSID_BETA": { + "exists": "forbidden" + }, "HKEY_CURRENT_USER\\Software\\Classes\\$CHROME_SHORT_NAME_BETA$USER_SPECIFIC_REGISTRY_SUFFIX": { "exists": "forbidden" }
diff --git a/chrome/test/mini_installer/config/chrome_beta_not_installed.prop b/chrome/test/mini_installer/config/chrome_beta_not_installed.prop index 7ddd34a..00fe2108 100644 --- a/chrome/test/mini_installer/config/chrome_beta_not_installed.prop +++ b/chrome/test/mini_installer/config/chrome_beta_not_installed.prop
@@ -31,6 +31,12 @@ }, "HKEY_CURRENT_USER\\Software\\Classes\\CLSID\\$CHROME_TOAST_ACTIVATOR_CLSID_BETA": { "exists": "forbidden" + }, + "HKEY_CURRENT_USER\\Software\\Classes\\CLSID\\$CHROME_ELEVATOR_CLSID_BETA": { + "exists": "forbidden" + }, + "HKEY_CURRENT_USER\\Software\\Classes\\AppID\\$CHROME_ELEVATOR_CLSID_BETA": { + "exists": "forbidden" } } }
diff --git a/chrome/test/mini_installer/config/chrome_canary_installed.prop b/chrome/test/mini_installer/config/chrome_canary_installed.prop index 75860b6..9224185 100644 --- a/chrome/test/mini_installer/config/chrome_canary_installed.prop +++ b/chrome/test/mini_installer/config/chrome_canary_installed.prop
@@ -50,6 +50,12 @@ "data": "$LOCAL_APPDATA\\$CHROME_DIR_SXS\\Application\\$MINI_INSTALLER_FILE_VERSION\\notification_helper.exe" } }, + "HKEY_CURRENT_USER\\Software\\Classes\\CLSID\\$CHROME_ELEVATOR_CLSID_SXS": { + "exists": "forbidden" + }, + "HKEY_CURRENT_USER\\Software\\Classes\\AppID\\$CHROME_ELEVATOR_CLSID_SXS": { + "exists": "forbidden" + }, "HKEY_CURRENT_USER\\Software\\Classes\\$CHROME_SHORT_NAME_SXS$USER_SPECIFIC_REGISTRY_SUFFIX": { "exists": "forbidden" }
diff --git a/chrome/test/mini_installer/config/chrome_canary_not_installed.prop b/chrome/test/mini_installer/config/chrome_canary_not_installed.prop index 1455f4bf..cd63c19 100644 --- a/chrome/test/mini_installer/config/chrome_canary_not_installed.prop +++ b/chrome/test/mini_installer/config/chrome_canary_not_installed.prop
@@ -31,6 +31,12 @@ }, "HKEY_CURRENT_USER\\Software\\Classes\\CLSID\\$CHROME_TOAST_ACTIVATOR_CLSID_SXS": { "exists": "forbidden" + }, + "HKEY_CURRENT_USER\\Software\\Classes\\CLSID\\$CHROME_ELEVATOR_CLSID_SXS": { + "exists": "forbidden" + }, + "HKEY_CURRENT_USER\\Software\\Classes\\AppID\\$CHROME_ELEVATOR_CLSID_SXS": { + "exists": "forbidden" } } }
diff --git a/chrome/test/mini_installer/config/chrome_dev_installed.prop b/chrome/test/mini_installer/config/chrome_dev_installed.prop index 7f3f82282..abe79429 100644 --- a/chrome/test/mini_installer/config/chrome_dev_installed.prop +++ b/chrome/test/mini_installer/config/chrome_dev_installed.prop
@@ -50,6 +50,12 @@ "data": "$LOCAL_APPDATA\\$CHROME_DIR_DEV\\Application\\$MINI_INSTALLER_FILE_VERSION\\notification_helper.exe" } }, + "HKEY_CURRENT_USER\\Software\\Classes\\CLSID\\$CHROME_ELEVATOR_CLSID_DEV": { + "exists": "forbidden" + }, + "HKEY_CURRENT_USER\\Software\\Classes\\AppID\\$CHROME_ELEVATOR_CLSID_DEV": { + "exists": "forbidden" + }, "HKEY_CURRENT_USER\\Software\\Classes\\$CHROME_SHORT_NAME_DEV$USER_SPECIFIC_REGISTRY_SUFFIX": { "exists": "forbidden" }
diff --git a/chrome/test/mini_installer/config/chrome_dev_not_installed.prop b/chrome/test/mini_installer/config/chrome_dev_not_installed.prop index 1a0e0aa..1278f8b 100644 --- a/chrome/test/mini_installer/config/chrome_dev_not_installed.prop +++ b/chrome/test/mini_installer/config/chrome_dev_not_installed.prop
@@ -31,6 +31,12 @@ }, "HKEY_CURRENT_USER\\Software\\Classes\\CLSID\\$CHROME_TOAST_ACTIVATOR_CLSID_DEV": { "exists": "forbidden" + }, + "HKEY_CURRENT_USER\\Software\\Classes\\CLSID\\$CHROME_ELEVATOR_CLSID_DEV": { + "exists": "forbidden" + }, + "HKEY_CURRENT_USER\\Software\\Classes\\AppID\\$CHROME_ELEVATOR_CLSID_DEV": { + "exists": "forbidden" } } }
diff --git a/chrome/test/mini_installer/config/chrome_multi_system_installed.prop b/chrome/test/mini_installer/config/chrome_multi_system_installed.prop index 1624cd7..7bba016 100644 --- a/chrome/test/mini_installer/config/chrome_multi_system_installed.prop +++ b/chrome/test/mini_installer/config/chrome_multi_system_installed.prop
@@ -62,6 +62,53 @@ "data": "$PROGRAM_FILES\\$CHROME_DIR\\Application\\$PREVIOUS_VERSION_MINI_INSTALLER_FILE_VERSION\\notification_helper.exe" } }, + "HKEY_LOCAL_MACHINE\\Software\\Classes\\CLSID\\$CHROME_ELEVATOR_CLSID": { + "exists": "required", + "values": { + "AppID": { + "type": "SZ", + "data": "$CHROME_ELEVATOR_CLSID" + } + } + }, + "HKEY_LOCAL_MACHINE\\Software\\Classes\\AppID\\$CHROME_ELEVATOR_CLSID": { + "exists": "required", + "values": { + "LocalService": { + "type": "SZ", + "data": "$CHROME_ELEVATION_SERVICE_NAME" + } + } + }, + "HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Services\\$CHROME_ELEVATION_SERVICE_NAME": { + "exists": "required", + "values": { + "Type": { + "type": "DWORD", + "data": 16 + }, + "Start": { + "type": "DWORD", + "data": 3 + }, + "ErrorControl": { + "type": "DWORD", + "data": 1 + }, + "ImagePath": { + "type": "EXPAND_SZ", + "data": "\"$PROGRAM_FILES\\$CHROME_DIR\\Application\\$PREVIOUS_VERSION_MINI_INSTALLER_FILE_VERSION\\elevation_service.exe\"" + }, + "DisplayName": { + "type": "SZ", + "data": "$CHROME_ELEVATION_SERVICE_DISPLAY_NAME" + }, + "ObjectName": { + "type": "SZ", + "data": "LocalSystem" + } + } + }, "HKEY_LOCAL_MACHINE\\Software\\Classes\\$CHROME_SHORT_NAME": { "exists": "forbidden" }
diff --git a/chrome/test/mini_installer/config/chrome_multi_user_installed.prop b/chrome/test/mini_installer/config/chrome_multi_user_installed.prop index 56d1d77..08a1caa 100644 --- a/chrome/test/mini_installer/config/chrome_multi_user_installed.prop +++ b/chrome/test/mini_installer/config/chrome_multi_user_installed.prop
@@ -62,6 +62,12 @@ "data": "$LOCAL_APPDATA\\$CHROME_DIR\\Application\\$PREVIOUS_VERSION_MINI_INSTALLER_FILE_VERSION\\notification_helper.exe" } }, + "HKEY_CURRENT_USER\\Software\\Classes\\CLSID\\$CHROME_ELEVATOR_CLSID": { + "exists": "forbidden" + }, + "HKEY_CURRENT_USER\\Software\\Classes\\AppID\\$CHROME_ELEVATOR_CLSID": { + "exists": "forbidden" + }, "HKEY_CURRENT_USER\\Software\\Classes\\$CHROME_SHORT_NAME$USER_SPECIFIC_REGISTRY_SUFFIX": { "exists": "forbidden" }
diff --git a/chrome/test/mini_installer/config/chrome_system_installed.prop b/chrome/test/mini_installer/config/chrome_system_installed.prop index f49b860..e4453a8 100644 --- a/chrome/test/mini_installer/config/chrome_system_installed.prop +++ b/chrome/test/mini_installer/config/chrome_system_installed.prop
@@ -73,6 +73,53 @@ "data": "$PROGRAM_FILES\\$CHROME_DIR\\Application\\$MINI_INSTALLER_FILE_VERSION\\notification_helper.exe" } }, + "HKEY_LOCAL_MACHINE\\Software\\Classes\\CLSID\\$CHROME_ELEVATOR_CLSID": { + "exists": "required", + "values": { + "AppID": { + "type": "SZ", + "data": "$CHROME_ELEVATOR_CLSID" + } + } + }, + "HKEY_LOCAL_MACHINE\\Software\\Classes\\AppID\\$CHROME_ELEVATOR_CLSID": { + "exists": "required", + "values": { + "LocalService": { + "type": "SZ", + "data": "$CHROME_ELEVATION_SERVICE_NAME" + } + } + }, + "HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Services\\$CHROME_ELEVATION_SERVICE_NAME": { + "exists": "required", + "values": { + "Type": { + "type": "DWORD", + "data": 16 + }, + "Start": { + "type": "DWORD", + "data": 3 + }, + "ErrorControl": { + "type": "DWORD", + "data": 1 + }, + "ImagePath": { + "type": "EXPAND_SZ", + "data": "\"$PROGRAM_FILES\\$CHROME_DIR\\Application\\$MINI_INSTALLER_FILE_VERSION\\elevation_service.exe\"" + }, + "DisplayName": { + "type": "SZ", + "data": "$CHROME_ELEVATION_SERVICE_DISPLAY_NAME" + }, + "ObjectName": { + "type": "SZ", + "data": "LocalSystem" + } + } + }, "HKEY_LOCAL_MACHINE\\Software\\Classes\\$CHROME_SHORT_NAME": { "exists": "forbidden" },
diff --git a/chrome/test/mini_installer/config/chrome_system_not_installed.prop b/chrome/test/mini_installer/config/chrome_system_not_installed.prop index 580ffbe..60a6d0b 100644 --- a/chrome/test/mini_installer/config/chrome_system_not_installed.prop +++ b/chrome/test/mini_installer/config/chrome_system_not_installed.prop
@@ -37,6 +37,15 @@ }, "HKEY_LOCAL_MACHINE\\Software\\Classes\\CLSID\\$CHROME_TOAST_ACTIVATOR_CLSID": { "exists": "forbidden" + }, + "HKEY_LOCAL_MACHINE\\Software\\Classes\\CLSID\\$CHROME_ELEVATOR_CLSID": { + "exists": "forbidden" + }, + "HKEY_LOCAL_MACHINE\\Software\\Classes\\AppID\\$CHROME_ELEVATOR_CLSID": { + "exists": "forbidden" + }, + "HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Services\\$CHROME_ELEVATION_SERVICE_NAME": { + "exists": "forbidden" } } }
diff --git a/chrome/test/mini_installer/config/chrome_user_installed.prop b/chrome/test/mini_installer/config/chrome_user_installed.prop index b1ba621..acd6c87 100644 --- a/chrome/test/mini_installer/config/chrome_user_installed.prop +++ b/chrome/test/mini_installer/config/chrome_user_installed.prop
@@ -58,6 +58,12 @@ "data": "$LOCAL_APPDATA\\$CHROME_DIR\\Application\\$MINI_INSTALLER_FILE_VERSION\\notification_helper.exe" } }, + "HKEY_CURRENT_USER\\Software\\Classes\\CLSID\\$CHROME_ELEVATOR_CLSID": { + "exists": "forbidden" + }, + "HKEY_CURRENT_USER\\Software\\Classes\\AppID\\$CHROME_ELEVATOR_CLSID": { + "exists": "forbidden" + }, "HKEY_CURRENT_USER\\Software\\Classes\\$CHROME_SHORT_NAME$USER_SPECIFIC_REGISTRY_SUFFIX": { "exists": "forbidden" }
diff --git a/chrome/test/mini_installer/config/chrome_user_not_installed.prop b/chrome/test/mini_installer/config/chrome_user_not_installed.prop index ad44ddf..88e8a7a 100644 --- a/chrome/test/mini_installer/config/chrome_user_not_installed.prop +++ b/chrome/test/mini_installer/config/chrome_user_not_installed.prop
@@ -37,6 +37,12 @@ }, "HKEY_CURRENT_USER\\Software\\Classes\\CLSID\\$CHROME_TOAST_ACTIVATOR_CLSID": { "exists": "forbidden" + }, + "HKEY_CURRENT_USER\\Software\\Classes\\CLSID\\$CHROME_ELEVATOR_CLSID": { + "exists": "forbidden" + }, + "HKEY_CURRENT_USER\\Software\\Classes\\AppID\\$CHROME_ELEVATOR_CLSID": { + "exists": "forbidden" } } }
diff --git a/chrome/test/mini_installer/config/previous_chrome_canary_installed.prop b/chrome/test/mini_installer/config/previous_chrome_canary_installed.prop index f0d94b5..520e9de7 100644 --- a/chrome/test/mini_installer/config/previous_chrome_canary_installed.prop +++ b/chrome/test/mini_installer/config/previous_chrome_canary_installed.prop
@@ -42,6 +42,12 @@ "data": "$LOCAL_APPDATA\\$CHROME_DIR_SXS\\Application\\$PREVIOUS_VERSION_MINI_INSTALLER_FILE_VERSION\\notification_helper.exe" } }, + "HKEY_CURRENT_USER\\Software\\Classes\\CLSID\\$CHROME_ELEVATOR_CLSID_SXS": { + "exists": "forbidden" + }, + "HKEY_CURRENT_USER\\Software\\Classes\\AppID\\$CHROME_ELEVATOR_CLSID_SXS": { + "exists": "forbidden" + }, "HKEY_CURRENT_USER\\Software\\Classes\\$CHROME_SHORT_NAME_SXS$USER_SPECIFIC_REGISTRY_SUFFIX": { "exists": "forbidden" }
diff --git a/chrome/test/mini_installer/config/previous_chrome_system_installed.prop b/chrome/test/mini_installer/config/previous_chrome_system_installed.prop index e3c47cb..8a84ac4 100644 --- a/chrome/test/mini_installer/config/previous_chrome_system_installed.prop +++ b/chrome/test/mini_installer/config/previous_chrome_system_installed.prop
@@ -71,6 +71,53 @@ "data": "$PROGRAM_FILES\\$CHROME_DIR\\Application\\$PREVIOUS_VERSION_MINI_INSTALLER_FILE_VERSION\\notification_helper.exe" } }, + "HKEY_LOCAL_MACHINE\\Software\\Classes\\CLSID\\$CHROME_ELEVATOR_CLSID": { + "exists": "required", + "values": { + "AppID": { + "type": "SZ", + "data": "$CHROME_ELEVATOR_CLSID" + } + } + }, + "HKEY_LOCAL_MACHINE\\Software\\Classes\\AppID\\$CHROME_ELEVATOR_CLSID": { + "exists": "required", + "values": { + "LocalService": { + "type": "SZ", + "data": "$CHROME_ELEVATION_SERVICE_NAME" + } + } + }, + "HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Services\\$CHROME_ELEVATION_SERVICE_NAME": { + "exists": "required", + "values": { + "Type": { + "type": "DWORD", + "data": 16 + }, + "Start": { + "type": "DWORD", + "data": 3 + }, + "ErrorControl": { + "type": "DWORD", + "data": 1 + }, + "ImagePath": { + "type": "EXPAND_SZ", + "data": "\"$PROGRAM_FILES\\$CHROME_DIR\\Application\\$PREVIOUS_VERSION_MINI_INSTALLER_FILE_VERSION\\elevation_service.exe\"" + }, + "DisplayName": { + "type": "SZ", + "data": "$CHROME_ELEVATION_SERVICE_DISPLAY_NAME" + }, + "ObjectName": { + "type": "SZ", + "data": "LocalSystem" + } + } + }, "HKEY_LOCAL_MACHINE\\Software\\Classes\\$CHROME_SHORT_NAME": { "exists": "forbidden" },
diff --git a/chrome/test/mini_installer/config/previous_chrome_user_installed.prop b/chrome/test/mini_installer/config/previous_chrome_user_installed.prop index 8fdcbf4..9278d83 100644 --- a/chrome/test/mini_installer/config/previous_chrome_user_installed.prop +++ b/chrome/test/mini_installer/config/previous_chrome_user_installed.prop
@@ -56,6 +56,12 @@ "data": "$LOCAL_APPDATA\\$CHROME_DIR\\Application\\$PREVIOUS_VERSION_MINI_INSTALLER_FILE_VERSION\\notification_helper.exe" } }, + "HKEY_CURRENT_USER\\Software\\Classes\\CLSID\\$CHROME_ELEVATOR_CLSID": { + "exists": "forbidden" + }, + "HKEY_CURRENT_USER\\Software\\Classes\\AppID\\$CHROME_ELEVATOR_CLSID": { + "exists": "forbidden" + }, "HKEY_CURRENT_USER\\Software\\Classes\\$CHROME_SHORT_NAME$USER_SPECIFIC_REGISTRY_SUFFIX": { "exists": "forbidden" }
diff --git a/chrome/test/mini_installer/variable_expander.py b/chrome/test/mini_installer/variable_expander.py index 1eeea332..ea3bade7 100644 --- a/chrome/test/mini_installer/variable_expander.py +++ b/chrome/test/mini_installer/variable_expander.py
@@ -121,6 +121,25 @@ Chrome Dev. * $CHROME_TOAST_ACTIVATOR_CLSID_SXS: NotificationActivator's CLSID for Chrome SxS. + * $CHROME_ELEVATOR_CLSID: Elevator Service CLSID for Chrome. + * $CHROME_ELEVATOR_CLSID_BETA: Elevator Service CLSID for Chrome Beta. + * $CHROME_ELEVATOR_CLSID_DEV: Elevator Service CLSID for Chrome Dev. + * $CHROME_ELEVATOR_CLSID_SXS: Elevator Service CLSID for Chrome SxS. + * $CHROME_ELEVATION_SERVICE_NAME: Elevation Service Name for Chrome. + * $CHROME_ELEVATION_SERVICE_NAME_BETA: Elevation Service Name for Chrome + Beta. + * $CHROME_ELEVATION_SERVICE_NAME_DEV: Elevation Service Name for Chrome + Dev. + * $CHROME_ELEVATION_SERVICE_NAME_SXS: Elevation Service Name for Chrome + SxS. + * $CHROME_ELEVATION_SERVICE_DISPLAY_NAME: Elevation Service Display Name + for Chrome. + * $CHROME_ELEVATION_SERVICE_DISPLAY_NAME_BETA: Elevation Service Display + Name for Chrome Beta. + * $CHROME_ELEVATION_SERVICE_DISPLAY_NAME_DEV: Elevation Service Display + Name for Chrome Dev. + * $CHROME_ELEVATION_SERVICE_DISPLAY_NAME_SXS: Elevation Service Display + Name for Chrome SxS. Args: mini_installer_path: The path to a mini_installer. @@ -206,6 +225,29 @@ '{F01C03EB-D431-4C83-8D7A-902771E732FA}'), 'CHROME_TOAST_ACTIVATOR_CLSID_SXS': ( '{FA372A6E-149F-4E95-832D-8F698D40AD7F}'), + 'CHROME_ELEVATOR_CLSID': ('{708860E0-F641-4611-8895-7D867DD3675B}'), + 'CHROME_ELEVATOR_CLSID_BETA': ( + '{DD2646BA-3707-4BF8-B9A7-038691A68FC2}'), + 'CHROME_ELEVATOR_CLSID_DEV': ( + '{DA7FDCA5-2CAA-4637-AA17-0740584DE7DA}'), + 'CHROME_ELEVATOR_CLSID_SXS': ( + '{704C2872-2049-435E-A469-0A534313C42B}'), + 'CHROME_ELEVATION_SERVICE_NAME': ( + 'GoogleChromeElevationService'), + 'CHROME_ELEVATION_SERVICE_NAME_BETA': ( + 'GoogleChromeBetaElevationService'), + 'CHROME_ELEVATION_SERVICE_NAME_DEV': ( + 'GoogleChromeDevElevationService'), + 'CHROME_ELEVATION_SERVICE_NAME_SXS': ( + 'GoogleChromeCanaryElevationService'), + 'CHROME_ELEVATION_SERVICE_DISPLAY_NAME': ( + 'Google Chrome Elevation Service'), + 'CHROME_ELEVATION_SERVICE_DISPLAY_NAME_BETA': ( + 'Google Chrome Beta Elevation Service'), + 'CHROME_ELEVATION_SERVICE_DISPLAY_NAME_DEV': ( + 'Google Chrome Dev Elevation Service'), + 'CHROME_ELEVATION_SERVICE_DISPLAY_NAME_SXS': ( + 'Google Chrome Canary Elevation Service'), }) elif mini_installer_product_name == 'Chromium Installer': self._variable_mapping.update({ @@ -219,6 +261,10 @@ 'CHROME_CLIENT_STATE_KEY': 'Software\\Chromium', 'CHROME_TOAST_ACTIVATOR_CLSID': ( '{635EFA6F-08D6-4EC9-BD14-8A0FDE975159}'), + 'CHROME_ELEVATOR_CLSID': ('{D133B120-6DB4-4D6B-8BFE-83BF8CA1B1B0}'), + 'CHROME_ELEVATION_SERVICE_NAME': 'ChromiumElevationService', + 'CHROME_ELEVATION_SERVICE_DISPLAY_NAME': ( + 'Chromium Elevation Service'), }) else: raise KeyError("Unknown mini_installer product name '%s'" %
diff --git a/chrome/tools/build/win/FILES.cfg b/chrome/tools/build/win/FILES.cfg index ac6ff1e..888b3f1d 100644 --- a/chrome/tools/build/win/FILES.cfg +++ b/chrome/tools/build/win/FILES.cfg
@@ -803,4 +803,15 @@ 'archive': 'chromedriver_win32-syms.zip', 'optional': ['official'], }, + # Elevation service files: + { + 'filename': 'elevation_service.exe', + 'buildtype': ['dev', 'official'], + 'filegroup': ['default', 'symsrc'], + }, + { + 'filename': 'elevation_service.exe.pdb', + 'buildtype': ['dev', 'official'], + 'archive': 'chrome-win32-syms.zip', + }, ]
diff --git a/chromeos/components/proximity_auth/proximity_auth_local_state_pref_manager.cc b/chromeos/components/proximity_auth/proximity_auth_local_state_pref_manager.cc index b84c88a..7cb0f65 100644 --- a/chromeos/components/proximity_auth/proximity_auth_local_state_pref_manager.cc +++ b/chromeos/components/proximity_auth/proximity_auth_local_state_pref_manager.cc
@@ -112,12 +112,25 @@ return static_cast<ProximityThreshold>(pref_value); } +bool ProximityAuthLocalStatePrefManager::IsChromeOSLoginAllowed() const { + bool pref_value; + const base::DictionaryValue* user_prefs = GetActiveUserPrefsDictionary(); + if (!user_prefs || + !user_prefs->GetBooleanWithoutPathExpansion( + chromeos::multidevice_setup::kSmartLockSigninAllowedPrefName, + &pref_value)) { + PA_LOG(INFO) << "Failed to get is_chrome_login_allowed, not disallowing"; + return true; + } + return pref_value; +} + void ProximityAuthLocalStatePrefManager::SetIsChromeOSLoginEnabled( bool is_enabled) { NOTREACHED(); } -bool ProximityAuthLocalStatePrefManager::IsChromeOSLoginEnabled() { +bool ProximityAuthLocalStatePrefManager::IsChromeOSLoginEnabled() const { bool pref_value; const base::DictionaryValue* user_prefs = GetActiveUserPrefsDictionary(); if (!user_prefs ||
diff --git a/chromeos/components/proximity_auth/proximity_auth_local_state_pref_manager.h b/chromeos/components/proximity_auth/proximity_auth_local_state_pref_manager.h index 1fb3424d..c006b99e 100644 --- a/chromeos/components/proximity_auth/proximity_auth_local_state_pref_manager.h +++ b/chromeos/components/proximity_auth/proximity_auth_local_state_pref_manager.h
@@ -46,7 +46,8 @@ bool IsEasyUnlockEnabled() const override; bool IsEasyUnlockEnabledStateSet() const override; ProximityThreshold GetProximityThreshold() const override; - bool IsChromeOSLoginEnabled() override; + bool IsChromeOSLoginAllowed() const override; + bool IsChromeOSLoginEnabled() const override; private: // ProximityAuthPrefManager:
diff --git a/chromeos/components/proximity_auth/proximity_auth_pref_manager.h b/chromeos/components/proximity_auth/proximity_auth_pref_manager.h index e98bcbb..8b60199 100644 --- a/chromeos/components/proximity_auth/proximity_auth_pref_manager.h +++ b/chromeos/components/proximity_auth/proximity_auth_pref_manager.h
@@ -64,10 +64,14 @@ virtual void SetProximityThreshold(ProximityThreshold value) = 0; virtual ProximityThreshold GetProximityThreshold() const = 0; - // Setting and getter for whether EasyUnlock is enabled for ChromeOS login (in + // Getter for whether EasyUnlock is allowed for ChromeOS login (in addition to + // screen lock). + virtual bool IsChromeOSLoginAllowed() const = 0; + + // Setter and getter for whether EasyUnlock is enabled for ChromeOS login (in // addition to screen lock). virtual void SetIsChromeOSLoginEnabled(bool is_enabled) = 0; - virtual bool IsChromeOSLoginEnabled() = 0; + virtual bool IsChromeOSLoginEnabled() const = 0; private: DISALLOW_COPY_AND_ASSIGN(ProximityAuthPrefManager);
diff --git a/chromeos/components/proximity_auth/proximity_auth_profile_pref_manager.cc b/chromeos/components/proximity_auth/proximity_auth_profile_pref_manager.cc index 9bf657bb..09c9521 100644 --- a/chromeos/components/proximity_auth/proximity_auth_profile_pref_manager.cc +++ b/chromeos/components/proximity_auth/proximity_auth_profile_pref_manager.cc
@@ -85,6 +85,8 @@ on_pref_changed_callback); registrar_.Add(proximity_auth::prefs::kProximityAuthIsChromeOSLoginEnabled, on_pref_changed_callback); + registrar_.Add(chromeos::multidevice_setup::kSmartLockSigninAllowedPrefName, + on_pref_changed_callback); SyncPrefsToLocalState(); } @@ -103,6 +105,9 @@ base::Value(GetProximityThreshold())); user_prefs_dict->SetKey(prefs::kProximityAuthIsChromeOSLoginEnabled, base::Value(IsChromeOSLoginEnabled())); + user_prefs_dict->SetKey( + chromeos::multidevice_setup::kSmartLockSigninAllowedPrefName, + base::Value(IsChromeOSLoginAllowed())); DictionaryPrefUpdate update(local_state_, prefs::kEasyUnlockLocalStateUserPrefs); @@ -173,13 +178,18 @@ return static_cast<ProximityThreshold>(pref_value); } +bool ProximityAuthProfilePrefManager::IsChromeOSLoginAllowed() const { + return pref_service_->GetBoolean( + chromeos::multidevice_setup::kSmartLockSigninAllowedPrefName); +} + void ProximityAuthProfilePrefManager::SetIsChromeOSLoginEnabled( bool is_enabled) { return pref_service_->SetBoolean(prefs::kProximityAuthIsChromeOSLoginEnabled, is_enabled); } -bool ProximityAuthProfilePrefManager::IsChromeOSLoginEnabled() { +bool ProximityAuthProfilePrefManager::IsChromeOSLoginEnabled() const { return pref_service_->GetBoolean(prefs::kProximityAuthIsChromeOSLoginEnabled); }
diff --git a/chromeos/components/proximity_auth/proximity_auth_profile_pref_manager.h b/chromeos/components/proximity_auth/proximity_auth_profile_pref_manager.h index 201c13b..8327942 100644 --- a/chromeos/components/proximity_auth/proximity_auth_profile_pref_manager.h +++ b/chromeos/components/proximity_auth/proximity_auth_profile_pref_manager.h
@@ -64,8 +64,9 @@ int GetPromotionShownCount() const override; void SetProximityThreshold(ProximityThreshold value) override; ProximityThreshold GetProximityThreshold() const override; + bool IsChromeOSLoginAllowed() const override; void SetIsChromeOSLoginEnabled(bool is_enabled) override; - bool IsChromeOSLoginEnabled() override; + bool IsChromeOSLoginEnabled() const override; // chromeos::multidevice_setup::MultiDeviceSetupClient::Observer: void OnFeatureStatesChanged(
diff --git a/chromeos/network/network_cert_loader.cc b/chromeos/network/network_cert_loader.cc index 24173ed..9fbfd09 100644 --- a/chromeos/network/network_cert_loader.cc +++ b/chromeos/network/network_cert_loader.cc
@@ -235,12 +235,10 @@ } NetworkCertLoader::NetworkCertLoader() : weak_factory_(this) { - system_cert_cache_ = std::make_unique<CertCache>( - base::BindRepeating(&NetworkCertLoader::OnCertCacheOrPolicyCertsUpdated, - base::Unretained(this))); - user_cert_cache_ = std::make_unique<CertCache>( - base::BindRepeating(&NetworkCertLoader::OnCertCacheOrPolicyCertsUpdated, - base::Unretained(this))); + system_cert_cache_ = std::make_unique<CertCache>(base::BindRepeating( + &NetworkCertLoader::OnCertCacheUpdated, base::Unretained(this))); + user_cert_cache_ = std::make_unique<CertCache>(base::BindRepeating( + &NetworkCertLoader::OnCertCacheUpdated, base::Unretained(this))); } NetworkCertLoader::~NetworkCertLoader() { @@ -260,7 +258,7 @@ PolicyCertificateProvider* policy_certificate_provider) { policy_certificate_provider->AddPolicyProvidedCertsObserver(this); policy_certificate_providers_.push_back(policy_certificate_provider); - OnCertCacheOrPolicyCertsUpdated(); + UpdateCertificates(); } void NetworkCertLoader::RemovePolicyCertificateProvider( @@ -271,7 +269,7 @@ DCHECK(iter != policy_certificate_providers_.end()); policy_certificate_providers_.erase(iter); policy_certificate_provider->RemovePolicyProvidedCertsObserver(this); - OnCertCacheOrPolicyCertsUpdated(); + UpdateCertificates(); } void NetworkCertLoader::AddObserver(NetworkCertLoader::Observer* observer) { @@ -340,26 +338,9 @@ return pkcs11_id; } -void NetworkCertLoader::OnCertCacheOrPolicyCertsUpdated() { +void NetworkCertLoader::OnCertCacheUpdated() { DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - VLOG(1) << "OnCertCacheOrPolicyCertsUpdated"; - - // Only trigger a notification to observers if one of the |CertCache|s has - // already loaded certificates. Don't trigger notifications if policy-provided - // certificates change before that. - // TODO(https://crbug.com/888451): When we handle client and authority - // certificates separately in NetworkCertLoader, we could fire different - // notifications for policy-provided cert changes instead of holding back - // notifications. Note that it is possible that only |system_cert_cache_| has - // loaded certificates (e.g. on the ChromeOS sign-in screen), and it is also - // possible that only |user_cert_cache_| has loaded certificates (e.g. if the - // system slot is not available for some reason, but a primary user has signed - // in). - bool has_loaded_any_certs_from_db = - user_cert_cache_->initial_load_finished() || - system_cert_cache_->initial_load_finished(); - if (!has_loaded_any_certs_from_db) - return; + VLOG(1) << "OnCertCacheUpdated"; // If user_cert_cache_ has access to system certificates and it has already // finished its initial load, it will contain system certificates which we can @@ -376,7 +357,7 @@ net::x509_util::DupCERTCertificateList( user_cert_cache_->cert_list()), std::move(system_slot)), - base::BindOnce(&NetworkCertLoader::UpdateCertificates, + base::BindOnce(&NetworkCertLoader::StoreCertsFromCache, weak_factory_.GetWeakPtr(), net::x509_util::DupCERTCertificateList( user_cert_cache_->cert_list()))); @@ -384,29 +365,61 @@ // The user's cert cache does not contain system certificates. net::ScopedCERTCertificateList system_token_client_certs = net::x509_util::DupCERTCertificateList(system_cert_cache_->cert_list()); - net::ScopedCERTCertificateList all_certs = + net::ScopedCERTCertificateList all_certs_from_cache = net::x509_util::DupCERTCertificateList(user_cert_cache_->cert_list()); - all_certs.reserve(all_certs.size() + system_token_client_certs.size()); - for (const net::ScopedCERTCertificate& cert : system_token_client_certs) - all_certs.push_back(net::x509_util::DupCERTCertificate(cert.get())); - UpdateCertificates(std::move(all_certs), - std::move(system_token_client_certs)); + all_certs_from_cache.reserve(all_certs_from_cache.size() + + system_token_client_certs.size()); + for (const net::ScopedCERTCertificate& cert : system_token_client_certs) { + all_certs_from_cache.push_back( + net::x509_util::DupCERTCertificate(cert.get())); + } + StoreCertsFromCache(std::move(all_certs_from_cache), + std::move(system_token_client_certs)); } } -void NetworkCertLoader::UpdateCertificates( - net::ScopedCERTCertificateList all_certs, +void NetworkCertLoader::StoreCertsFromCache( + net::ScopedCERTCertificateList all_certs_from_cache, net::ScopedCERTCertificateList system_token_client_certs) { DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - VLOG(1) << "UpdateCertificates: " << all_certs.size() << " (" + VLOG(1) << "StoreCertsFromCache: " << all_certs_from_cache.size() << " (" << system_token_client_certs.size() << " client certs on system slot)"; // Ignore any existing certificates. - all_certs_ = std::move(all_certs); + all_certs_from_cache_ = std::move(all_certs_from_cache); system_token_client_certs_ = std::move(system_token_client_certs); + certs_from_cache_loaded_ = true; + + UpdateCertificates(); +} + +void NetworkCertLoader::UpdateCertificates() { + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); + + // Only trigger a notification to observers if one of the |CertCache|s has + // already loaded certificates. Don't trigger notifications if policy-provided + // certificates change before that. + // TODO(https://crbug.com/888451): When we handle client and authority + // certificates separately in NetworkCertLoader, we could fire different + // notifications for policy-provided cert changes instead of holding back + // notifications. Note that it is possible that only |system_cert_cache_| has + // loaded certificates (e.g. on the ChromeOS sign-in screen), and it is also + // possible that only |user_cert_cache_| has loaded certificates (e.g. if the + // system slot is not available for some reason, but a primary user has signed + // in). + if (!certs_from_cache_loaded_) + return; + + // Copy |all_certs_from_cache_| into |all_certs_|, ignoring any existing + // certificates. + all_certs_.clear(); + all_certs_.reserve(all_certs_from_cache_.size()); + for (const net::ScopedCERTCertificate& cert : all_certs_from_cache_) + all_certs_.push_back(net::x509_util::DupCERTCertificate(cert.get())); + // Add policy-provided certificates. // TODO(https://crbug.com/888451): Instead of putting authorities and client // certs into |all_certs_| and then filtering in NetworkCertificateHandler, we @@ -429,7 +442,7 @@ const net::CertificateList& all_server_and_authority_certs, const net::CertificateList& trust_anchors) { DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - OnCertCacheOrPolicyCertsUpdated(); + UpdateCertificates(); } } // namespace chromeos
diff --git a/chromeos/network/network_cert_loader.h b/chromeos/network/network_cert_loader.h index 7e77545..05fa679 100644 --- a/chromeos/network/network_cert_loader.h +++ b/chromeos/network/network_cert_loader.h
@@ -150,15 +150,21 @@ NetworkCertLoader(); ~NetworkCertLoader() override; - // Called when |system_cert_cache_|, |user_cert_cache| or policy-provided - // certificates have potentially changed. - void OnCertCacheOrPolicyCertsUpdated(); + // Called when |system_cert_cache_| or |user_cert_cache| certificates have + // potentially changed. + void OnCertCacheUpdated(); - // Called if a certificate load task is finished. - void UpdateCertificates( + // Called as a result of |OnCertCacheUpdated|. This is a separate function, + // because |OnCertCacheUpdated| may trigger a background task for filtering + // certificates. + void StoreCertsFromCache( net::ScopedCERTCertificateList all_certs, net::ScopedCERTCertificateList system_token_client_certs); + // Called when policy-provided certificates or cache-based certificates (see + // |all_certs_from_cache_|) have potentially changed. + void UpdateCertificates(); + void NotifyCertificatesLoaded(); // PolicyCertificateProvider::Observer @@ -177,9 +183,15 @@ // certificates. net::ScopedCERTCertificateList all_certs_; + // Cached certificates loaded from the database(s). + net::ScopedCERTCertificateList all_certs_from_cache_; + // Cached certificates from system token. net::ScopedCERTCertificateList system_token_client_certs_; + // True if |StoreCertsFromCache()| was called before. + bool certs_from_cache_loaded_ = false; + std::vector<const PolicyCertificateProvider*> policy_certificate_providers_; THREAD_CHECKER(thread_checker_);
diff --git a/chromeos/services/device_sync/device_sync_base.cc b/chromeos/services/device_sync/device_sync_base.cc index 57c95fd2..fc4db5c 100644 --- a/chromeos/services/device_sync/device_sync_base.cc +++ b/chromeos/services/device_sync/device_sync_base.cc
@@ -4,13 +4,17 @@ #include <utility> +#include "base/bind.h" #include "chromeos/services/device_sync/device_sync_base.h" namespace chromeos { namespace device_sync { -DeviceSyncBase::DeviceSyncBase() = default; +DeviceSyncBase::DeviceSyncBase() { + bindings_.set_connection_error_handler(base::BindRepeating( + &DeviceSyncBase::OnDisconnection, base::Unretained(this))); +} DeviceSyncBase::~DeviceSyncBase() = default; @@ -33,6 +37,12 @@ observers_.ForAllPtrs([](auto* observer) { observer->OnNewDevicesSynced(); }); } +void DeviceSyncBase::OnDisconnection() { + // If all clients have disconnected, shut down. + if (bindings_.empty()) + Shutdown(); +} + } // namespace device_sync } // namespace chromeos
diff --git a/chromeos/services/device_sync/device_sync_base.h b/chromeos/services/device_sync/device_sync_base.h index 617b477..67346d5 100644 --- a/chromeos/services/device_sync/device_sync_base.h +++ b/chromeos/services/device_sync/device_sync_base.h
@@ -31,10 +31,16 @@ protected: DeviceSyncBase(); + // Derived types should override this function to remove references to any + // dependencies. + virtual void Shutdown() {} + void NotifyOnEnrollmentFinished(); void NotifyOnNewDevicesSynced(); private: + void OnDisconnection(); + mojo::InterfacePtrSet<mojom::DeviceSyncObserver> observers_; mojo::BindingSet<mojom::DeviceSync> bindings_; @@ -45,4 +51,4 @@ } // namespace chromeos -#endif // CHROMEOS_SERVICES_DEVICE_SYNC_DEVICE_SYNC_BASE_H_ \ No newline at end of file +#endif // CHROMEOS_SERVICES_DEVICE_SYNC_DEVICE_SYNC_BASE_H_
diff --git a/chromeos/services/device_sync/device_sync_impl.cc b/chromeos/services/device_sync/device_sync_impl.cc index be5df26..a2eed36 100644 --- a/chromeos/services/device_sync/device_sync_impl.cc +++ b/chromeos/services/device_sync/device_sync_impl.cc
@@ -262,6 +262,23 @@ NotifyOnNewDevicesSynced(); } +void DeviceSyncImpl::Shutdown() { + software_feature_manager_.reset(); + remote_device_provider_.reset(); + cryptauth_device_manager_.reset(); + cryptauth_enrollment_manager_.reset(); + cryptauth_client_factory_.reset(); + cryptauth_gcm_manager_.reset(); + pref_connection_delegate_.reset(); + + identity_manager_ = nullptr; + gcm_driver_ = nullptr; + connector_ = nullptr; + gcm_device_info_provider_ = nullptr; + url_loader_factory_ = nullptr; + clock_ = nullptr; +} + void DeviceSyncImpl::ProcessPrimaryAccountInfo( const AccountInfo& primary_account_info) { // Note: We cannot use |primary_account_info.IsValid()| here because
diff --git a/chromeos/services/device_sync/device_sync_impl.h b/chromeos/services/device_sync/device_sync_impl.h index 85ca389e..e5b3f8d 100644 --- a/chromeos/services/device_sync/device_sync_impl.h +++ b/chromeos/services/device_sync/device_sync_impl.h
@@ -141,6 +141,9 @@ base::Clock* clock, std::unique_ptr<PrefConnectionDelegate> pref_connection_delegate); + // DeviceSyncBase: + void Shutdown() override; + void ProcessPrimaryAccountInfo(const AccountInfo& primary_account_info); void ConnectToPrefStore(); void OnConnectedToPrefService(std::unique_ptr<PrefService> pref_service);
diff --git a/components/arc/common/input_method_manager.mojom b/components/arc/common/input_method_manager.mojom index 1585efc..c8d18975 100644 --- a/components/arc/common/input_method_manager.mojom +++ b/components/arc/common/input_method_manager.mojom
@@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// Next MinVersion: 4 +// Next MinVersion: 5 module arc.mojom; @@ -104,7 +104,7 @@ // This interface provides methods to control Android's InputMethodManager. // -// Next method ID: 5 +// Next method ID: 7 interface InputMethodManagerInstance { // Establishes full-duplex communication with the host. Init@0(InputMethodManagerHost host_ptr) => (); @@ -123,4 +123,10 @@ // Sends the latest TextInputState of the active text field. [MinVersion=2] UpdateTextInputState@4(TextInputState state); + + // Requests the active IME to show virtual keyboard. + [MinVersion=4] ShowVirtualKeyboard@5(); + + // Requests the active IME to hide virtual keyboard. + [MinVersion=4] HideVirtualKeyboard@6(); };
diff --git a/components/autofill/core/browser/BUILD.gn b/components/autofill/core/browser/BUILD.gn index a1948e6..5359fc93 100644 --- a/components/autofill/core/browser/BUILD.gn +++ b/components/autofill/core/browser/BUILD.gn
@@ -147,6 +147,8 @@ "phone_number_i18n.h", "popup_item_ids.h", "popup_types.h", + "randomized_encoder.cc", + "randomized_encoder.h", "rationalization_util.cc", "rationalization_util.h", "region_combobox_model.cc", @@ -278,6 +280,7 @@ "//components/variations/net", "//components/version_info", "//components/webdata/common", + "//crypto", "//google_apis", "//net", "//services/identity/public/cpp", @@ -490,6 +493,7 @@ "phone_field_unittest.cc", "phone_number_i18n_unittest.cc", "phone_number_unittest.cc", + "randomized_encoder_unittest.cc", "rationalization_util_unittest.cc", "region_combobox_model_unittest.cc", "search_field_unittest.cc",
diff --git a/components/autofill/core/browser/DEPS b/components/autofill/core/browser/DEPS index fb72964..889d643 100644 --- a/components/autofill/core/browser/DEPS +++ b/components/autofill/core/browser/DEPS
@@ -14,6 +14,7 @@ "+components/version_info", "+components/webdata/common", "+components/webdata_services", + "+crypto/hkdf.h", "+crypto/random.h", "+google_apis/gaia", "+google_apis/google_api_keys.h",
diff --git a/components/autofill/core/browser/autofill_manager_unittest.cc b/components/autofill/core/browser/autofill_manager_unittest.cc index 246ac0ef..b1e466e 100644 --- a/components/autofill/core/browser/autofill_manager_unittest.cc +++ b/components/autofill/core/browser/autofill_manager_unittest.cc
@@ -2907,6 +2907,9 @@ // Verify only the first complete number is filled when there are multiple // componentized number fields. FormData form_with_multiple_componentized_phone_fields; + form_with_multiple_componentized_phone_fields.origin = + GURL("http://www.foo.com/"); + FormFieldData field; // Default is zero, have to set to a number autofill can process. field.max_length = 10; @@ -3004,6 +3007,8 @@ std::string guid(work_profile->guid()); FormData form_with_multiple_whole_number_fields; + form_with_multiple_whole_number_fields.origin = GURL("http://www.foo.com/"); + FormFieldData field; // Default is zero, have to set to a number autofill can process. field.max_length = 10; @@ -3085,6 +3090,9 @@ // Verify only the first complete number is filled when there are multiple // componentized number fields. FormData form_with_multiple_componentized_phone_fields; + form_with_multiple_componentized_phone_fields.origin = + GURL("http://www.foo.com/"); + FormFieldData field; // Default is zero, have to set to a number autofill can process. field.max_length = 10; @@ -3188,6 +3196,8 @@ std::string guid(work_profile->guid()); FormData form_with_misclassified_extension; + form_with_misclassified_extension.origin = GURL("http://www.foo.com/"); + FormFieldData field; // Default is zero, have to set to a number autofill can process. field.max_length = 10; @@ -3278,6 +3288,8 @@ std::string guid(work_profile->guid()); FormData form_with_no_complete_number; + form_with_no_complete_number.origin = GURL("http://www.foo.com/"); + FormFieldData field; // Default is zero, have to set to a number autofill can process. field.max_length = 10; @@ -3363,6 +3375,8 @@ std::string guid(work_profile->guid()); FormData form_with_multiple_whole_number_fields; + form_with_multiple_whole_number_fields.origin = GURL("http://www.foo.com/"); + FormFieldData field; // Default is zero, have to set to a number autofill can process. field.max_length = 10; @@ -3448,6 +3462,8 @@ std::string guid(work_profile->guid()); FormData form_with_multiple_whole_number_fields; + form_with_multiple_whole_number_fields.origin = GURL("http://www.foo.com/"); + FormFieldData field; // Default is zero, have to set to a number autofill can process. field.max_length = 10; @@ -3601,6 +3617,8 @@ std::string guid(work_profile->guid()); FormData form_with_multiple_sections; + form_with_multiple_sections.origin = GURL("http://www.foo.com/"); + FormFieldData field; // Default is zero, have to set to a number autofill can process. field.max_length = 10; @@ -3800,6 +3818,8 @@ TEST_F(AutofillManagerTest, FormChangesVisibilityOfFields) { // Set up our form data. FormData form; + form.origin = GURL("http://www.foo.com/"); + FormFieldData field; // Default is zero, have to set to a number autofill can process. @@ -4238,6 +4258,7 @@ TEST_F(AutofillManagerTest, DetermineHeuristicsWithOverallPrediction) { // Set up our form data. FormData form; + form.origin = GURL("https://www.myform.com"); FormFieldData field; test::CreateTestFormField("First Name", "firstname", "", "text", &field); form.fields.push_back(field);
diff --git a/components/autofill/core/browser/autofill_metrics_unittest.cc b/components/autofill/core/browser/autofill_metrics_unittest.cc index 0307e65..03540a6e 100644 --- a/components/autofill/core/browser/autofill_metrics_unittest.cc +++ b/components/autofill/core/browser/autofill_metrics_unittest.cc
@@ -3173,6 +3173,7 @@ // Set up the form data. FormData form; form.name = ASCIIToUTF16("TestForm"); + form.origin = GURL("http://www.foo.com/"); FormFieldData field; std::vector<ServerFieldType> field_types;
diff --git a/components/autofill/core/browser/form_data_importer_unittest.cc b/components/autofill/core/browser/form_data_importer_unittest.cc index f6de5a3..b241ed5 100644 --- a/components/autofill/core/browser/form_data_importer_unittest.cc +++ b/components/autofill/core/browser/form_data_importer_unittest.cc
@@ -278,6 +278,8 @@ TEST_F(FormDataImporterTest, ImportAddressProfiles) { FormData form; + form.origin = GURL("https://wwww.foo.com"); + FormFieldData field; test::CreateTestFormField("First name:", "first_name", "George", "text", &field); @@ -316,6 +318,8 @@ TEST_F(FormDataImporterTest, ImportAddressProfiles_BadEmail) { FormData form; + form.origin = GURL("https://wwww.foo.com"); + FormFieldData field; test::CreateTestFormField("First name:", "first_name", "George", "text", &field); @@ -344,6 +348,8 @@ // Tests that a 'confirm email' field does not block profile import. TEST_F(FormDataImporterTest, ImportAddressProfiles_TwoEmails) { FormData form; + form.origin = GURL("https://wwww.foo.com"); + FormFieldData field; test::CreateTestFormField("Name:", "name", "George Washington", "text", &field); @@ -375,6 +381,8 @@ // Tests two email fields containing different values blocks profile import. TEST_F(FormDataImporterTest, ImportAddressProfiles_TwoDifferentEmails) { FormData form; + form.origin = GURL("https://wwww.foo.com"); + FormFieldData field; test::CreateTestFormField("Name:", "name", "George Washington", "text", &field); @@ -404,6 +412,8 @@ // Tests that not enough filled fields will result in not importing an address. TEST_F(FormDataImporterTest, ImportAddressProfiles_NotEnoughFilledFields) { FormData form; + form.origin = GURL("https://wwww.foo.com"); + FormFieldData field; test::CreateTestFormField("First name:", "first_name", "George", "text", &field); @@ -426,6 +436,8 @@ // United States addresses must specifiy one address line, a city, state and // zip code. FormData form; + form.origin = GURL("https://wwww.foo.com"); + FormFieldData field; test::CreateTestFormField("Name:", "name", "Barack Obama", "text", &field); form.fields.push_back(field); @@ -453,6 +465,8 @@ // British addresses do not require a state/province as the county is usually // not requested on forms. FormData form; + form.origin = GURL("https://wwww.foo.com"); + FormFieldData field; test::CreateTestFormField("Name:", "name", "David Cameron", "text", &field); form.fields.push_back(field); @@ -480,6 +494,8 @@ // Gibraltar has the most minimal set of requirements for a valid address. // There are no cities or provinces and no postal/zip code system. FormData form; + form.origin = GURL("https://wwww.foo.com"); + FormFieldData field; test::CreateTestFormField("Name:", "name", "Sir Adrian Johns", "text", &field); @@ -501,6 +517,8 @@ TEST_F(FormDataImporterTest, ImportAddressProfiles_PhoneNumberSplitAcrossMultipleFields) { FormData form; + form.origin = GURL("https://wwww.foo.com"); + FormFieldData field; test::CreateTestFormField("First name:", "first_name", "George", "text", &field); @@ -547,6 +565,8 @@ TEST_F(FormDataImporterTest, ImportAddressProfiles_MultilineAddress) { FormData form; + form.origin = GURL("https://wwww.foo.com"); + FormFieldData field; test::CreateTestFormField("First name:", "first_name", "George", "text", &field); @@ -588,6 +608,8 @@ TEST_F(FormDataImporterTest, ImportAddressProfiles_TwoValidProfilesDifferentForms) { FormData form1; + form1.origin = GURL("https://wwww.foo.com"); + FormFieldData field; test::CreateTestFormField("First name:", "first_name", "George", "text", &field); @@ -626,6 +648,8 @@ // Now create a completely different profile. FormData form2; + form2.origin = GURL("https://wwww.foo.com"); + test::CreateTestFormField("First name:", "first_name", "John", "text", &field); form2.fields.push_back(field); @@ -662,6 +686,8 @@ TEST_F(FormDataImporterTest, ImportAddressProfiles_TwoValidProfilesSameForm) { FormData form; + form.origin = GURL("https://wwww.foo.com"); + FormFieldData field; test::CreateTestFormField("First name:", "first_name", "George", "text", &field); @@ -730,6 +756,8 @@ TEST_F(FormDataImporterTest, ImportAddressProfiles_OneValidProfileSameForm_PartsHidden) { FormData form; + form.origin = GURL("https://wwww.foo.com"); + FormFieldData field; test::CreateTestFormField("First name:", "first_name", "George", "text", &field); @@ -799,6 +827,8 @@ // A maximum of two address profiles are imported per form. TEST_F(FormDataImporterTest, ImportAddressProfiles_ThreeValidProfilesSameForm) { FormData form; + form.origin = GURL("https://wwww.foo.com"); + FormFieldData field; test::CreateTestFormField("First name:", "first_name", "George", "text", &field); @@ -886,6 +916,8 @@ TEST_F(FormDataImporterTest, ImportAddressProfiles_SameProfileWithConflict) { FormData form1; + form1.origin = GURL("https://wwww.foo.com"); + FormFieldData field; test::CreateTestFormField("First name:", "first_name", "George", "text", &field); @@ -929,6 +961,8 @@ // Now create an updated profile. FormData form2; + form2.origin = GURL("https://wwww.foo.com"); + test::CreateTestFormField("First name:", "first_name", "George", "text", &field); form2.fields.push_back(field); @@ -977,6 +1011,8 @@ TEST_F(FormDataImporterTest, ImportAddressProfiles_MissingInfoInOld) { FormData form1; + form1.origin = GURL("https://wwww.foo.com"); + FormFieldData field; test::CreateTestFormField("First name:", "first_name", "George", "text", &field); @@ -1011,6 +1047,8 @@ // Submit a form with new data for the first profile. FormData form2; + form2.origin = GURL("https://wwww.foo.com"); + test::CreateTestFormField("First name:", "first_name", "George", "text", &field); form2.fields.push_back(field); @@ -1051,6 +1089,8 @@ TEST_F(FormDataImporterTest, ImportAddressProfiles_MissingInfoInNew) { FormData form1; + form1.origin = GURL("https://wwww.foo.com"); + FormFieldData field; test::CreateTestFormField("First name:", "first_name", "George", "text", &field); @@ -1092,6 +1132,8 @@ // Submit a form with new data for the first profile. FormData form2; + form2.origin = GURL("https://wwww.foo.com"); + test::CreateTestFormField("First name:", "first_name", "George", "text", &field); form2.fields.push_back(field); @@ -1129,6 +1171,8 @@ TEST_F(FormDataImporterTest, ImportAddressProfiles_InsufficientAddress) { FormData form1; + form1.origin = GURL("https://wwww.foo.com"); + FormFieldData field; test::CreateTestFormField("First name:", "first_name", "George", "text", &field); @@ -1180,6 +1224,8 @@ // Simulate a form submission with conflicting info. FormData form; + form.origin = GURL("https://wwww.foo.com"); + FormFieldData field; test::CreateTestFormField("First name:", "first_name", "Marion Mitchell", "text", &field); @@ -1238,6 +1284,8 @@ // Tests that no profile is inferred if the country is not recognized. TEST_F(FormDataImporterTest, ImportAddressProfiles_UnrecognizedCountry) { FormData form; + form.origin = GURL("https://wwww.foo.com"); + FormFieldData field; test::CreateTestFormField("First name:", "first_name", "George", "text", &field); @@ -1277,6 +1325,8 @@ TEST_F(FormDataImporterTest, ImportAddressProfiles_CompleteComposedCountryName) { FormData form; + form.origin = GURL("https://wwww.foo.com"); + FormFieldData field; test::CreateTestFormField("First name:", "first_name", "George", "text", &field); @@ -1323,6 +1373,8 @@ TEST_F(FormDataImporterTest, ImportAddressProfiles_IncompleteComposedCountryName) { FormData form; + form.origin = GURL("https://wwww.foo.com"); + FormFieldData field; test::CreateTestFormField("First name:", "first_name", "George", "text", &field); @@ -1365,6 +1417,8 @@ TEST_F(FormDataImporterTest, ImportCreditCard_Valid) { // Add a single valid credit card form. FormData form; + form.origin = GURL("https://wwww.foo.com"); + AddFullCreditCardForm(&form, "Biggie Smalls", "4111-1111-1111-1111", "01", "2999"); @@ -1393,6 +1447,8 @@ // Tests that an invalid credit card number is not extracted. TEST_F(FormDataImporterTest, ImportCreditCard_InvalidCardNumber) { FormData form; + form.origin = GURL("https://wwww.foo.com"); + AddFullCreditCardForm(&form, "Jim Johansen", "1000000000000000", "02", "2999"); @@ -1416,6 +1472,8 @@ // Tests that an invalid credit card expiration is not extracted. TEST_F(FormDataImporterTest, ImportCreditCard_InvalidExpiryDate) { FormData form; + form.origin = GURL("https://wwww.foo.com"); + AddFullCreditCardForm(&form, "Smalls Biggie", "4111-1111-1111-1111", "0", "2999"); @@ -1440,6 +1498,8 @@ TEST_F(FormDataImporterTest, ImportCreditCard_MonthSelectInvalidText) { // Add a single valid credit card form with an invalid option value. FormData form; + form.origin = GURL("https://wwww.foo.com"); + AddFullCreditCardForm(&form, "Biggie Smalls", "4111-1111-1111-1111", "Feb (2)", "2999"); // Add option values and contents to the expiration month field. @@ -1481,6 +1541,8 @@ TEST_F(FormDataImporterTest, ImportCreditCard_TwoValidCards) { // Start with a single valid credit card form. FormData form1; + form1.origin = GURL("https://wwww.foo.com"); + AddFullCreditCardForm(&form1, "Biggie Smalls", "4111-1111-1111-1111", "01", "2999"); @@ -1503,6 +1565,8 @@ // Add a second different valid credit card. FormData form2; + form2.origin = GURL("https://wwww.foo.com"); + AddFullCreditCardForm(&form2, "", "5500 0000 0000 0004", "02", "2999"); FormStructure form_structure2(form2); @@ -1527,6 +1591,8 @@ // This form has the expiration year as one field with MM/YY. TEST_F(FormDataImporterTest, ImportCreditCard_Month2DigitYearCombination) { FormData form; + form.origin = GURL("https://wwww.foo.com"); + FormFieldData field; test::CreateTestFormField("Name on card:", "name_on_card", "John MMYY", "text", &field); @@ -1546,6 +1612,8 @@ // This form has the expiration year as one field with MM/YYYY. TEST_F(FormDataImporterTest, ImportCreditCard_Month4DigitYearCombination) { FormData form; + form.origin = GURL("https://wwww.foo.com"); + FormFieldData field; test::CreateTestFormField("Name on card:", "name_on_card", "John MMYYYY", "text", &field); @@ -1565,6 +1633,8 @@ // This form has the expiration year as one field with M/YYYY. TEST_F(FormDataImporterTest, ImportCreditCard_1DigitMonth4DigitYear) { FormData form; + form.origin = GURL("https://wwww.foo.com"); + FormFieldData field; test::CreateTestFormField("Name on card:", "name_on_card", "John MYYYY", "text", &field); @@ -1583,6 +1653,8 @@ // This form has the expiration year as a 2-digit field. TEST_F(FormDataImporterTest, ImportCreditCard_2DigitYear) { FormData form; + form.origin = GURL("https://wwww.foo.com"); + FormFieldData field; test::CreateTestFormField("Name on card:", "name_on_card", "John Smith", "text", &field); @@ -1619,6 +1691,8 @@ // Type the same data as the masked card into a form. FormData form; + form.origin = GURL("https://wwww.foo.com"); + AddFullCreditCardForm(&form, "John Dillinger", "4111111111111111", "01", "2999"); @@ -1649,6 +1723,8 @@ // Type the same data as the unmasked card into a form. FormData form; + form.origin = GURL("https://wwww.foo.com"); + AddFullCreditCardForm(&form, "Clyde Barrow", "378282246310005", "04", "2999"); // The card should not be offered to be saved locally because it only matches @@ -1663,6 +1739,8 @@ TEST_F(FormDataImporterTest, ImportCreditCard_SameCreditCardWithConflict) { // Start with a single valid credit card form. FormData form1; + form1.origin = GURL("https://wwww.foo.com"); + AddFullCreditCardForm(&form1, "Biggie Smalls", "4111-1111-1111-1111", "01", "2998"); @@ -1686,6 +1764,8 @@ // Add a second different valid credit card where the year is different but // the credit card number matches. FormData form2; + form2.origin = GURL("https://wwww.foo.com"); + AddFullCreditCardForm(&form2, "Biggie Smalls", "4111 1111 1111 1111", "01", /* different year */ "2999"); @@ -1711,6 +1791,8 @@ TEST_F(FormDataImporterTest, ImportCreditCard_ShouldReturnLocalCard) { // Start with a single valid credit card form. FormData form1; + form1.origin = GURL("https://wwww.foo.com"); + AddFullCreditCardForm(&form1, "Biggie Smalls", "4111-1111-1111-1111", "01", "2998"); @@ -1734,6 +1816,8 @@ // Add a second different valid credit card where the year is different but // the credit card number matches. FormData form2; + form2.origin = GURL("https://wwww.foo.com"); + AddFullCreditCardForm(&form2, "Biggie Smalls", "4111 1111 1111 1111", "01", /* different year */ "2999"); @@ -1762,6 +1846,8 @@ TEST_F(FormDataImporterTest, ImportCreditCard_EmptyCardWithConflict) { // Start with a single valid credit card form. FormData form1; + form1.origin = GURL("https://wwww.foo.com"); + AddFullCreditCardForm(&form1, "Biggie Smalls", "4111-1111-1111-1111", "01", "2998"); @@ -1785,6 +1871,8 @@ // Add a second credit card with no number. FormData form2; + form2.origin = GURL("https://wwww.foo.com"); + AddFullCreditCardForm(&form2, "Biggie Smalls", /* no number */ nullptr, "01", "2999"); @@ -1812,6 +1900,8 @@ TEST_F(FormDataImporterTest, ImportCreditCard_MissingInfoInNew) { // Start with a single valid credit card form. FormData form1; + form1.origin = GURL("https://wwww.foo.com"); + AddFullCreditCardForm(&form1, "Biggie Smalls", "4111-1111-1111-1111", "01", "2999"); @@ -1835,6 +1925,8 @@ // Add a second different valid credit card where the name is missing but // the credit card number matches. FormData form2; + form2.origin = GURL("https://wwww.foo.com"); + AddFullCreditCardForm(&form2, /* missing name */ nullptr, "4111-1111-1111-1111", "01", "2999"); @@ -1859,6 +1951,8 @@ // Add a third credit card where the expiration date is missing. FormData form3; + form3.origin = GURL("https://wwww.foo.com"); + AddFullCreditCardForm(&form3, "Johnny McEnroe", "5555555555554444", /* no month */ nullptr, /* no year */ nullptr); @@ -1902,6 +1996,8 @@ // Add a second different valid credit card where the year is different but // the credit card number matches. FormData form; + form.origin = GURL("https://wwww.foo.com"); + AddFullCreditCardForm(&form, "Biggie Smalls", "4111-1111-1111-1111", "01", /* different year */ "2999"); @@ -1943,6 +2039,8 @@ // Import the same card info, but with different separators in the number. FormData form; + form.origin = GURL("https://wwww.foo.com"); + AddFullCreditCardForm(&form, "Biggie Smalls", "4111-1111-1111-1111", "01", "2999"); @@ -1983,6 +2081,8 @@ // Simulate a form submission with conflicting expiration year. FormData form; + form.origin = GURL("https://wwww.foo.com"); + AddFullCreditCardForm(&form, "Biggie Smalls", "4111 1111 1111 1111", "01", /* different year */ "2999"); @@ -2021,6 +2121,8 @@ // Simulate a form submission with the same card. FormData form; + form.origin = GURL("https://wwww.foo.com"); + AddFullCreditCardForm(&form, "Biggie Smalls", "4111 1111 1111 1111", "01", "2999"); @@ -2041,6 +2143,8 @@ // |imported_credit_card_record_type_| should be reset. // Simulate a form submission with a new card. FormData form2; + form2.origin = GURL("https://wwww.foo.com"); + AddFullCreditCardForm(&form2, "Biggie Smalls", "4012888888881881", "01", "2999"); @@ -2062,6 +2166,8 @@ // |imported_credit_card_record_type_| should still be reset even if // ImportCreditCard is not called. Simulate a form submission with no card. FormData form3; + form3.origin = GURL("https://wwww.foo.com"); + FormFieldData field; test::CreateTestFormField("First name:", "first_name", "George", "text", &field); @@ -2099,6 +2205,8 @@ ImportFormData_ImportCreditCardRecordType_NewCard) { // Simulate a form submission with a new credit card. FormData form; + form.origin = GURL("https://wwww.foo.com"); + AddFullCreditCardForm(&form, "Biggie Smalls", "4111 1111 1111 1111", "01", "2999"); @@ -2134,6 +2242,8 @@ // Simulate a form submission with the same card. FormData form; + form.origin = GURL("https://wwww.foo.com"); + AddFullCreditCardForm(&form, "Biggie Smalls", "4111 1111 1111 1111", "01", "2999"); @@ -2169,6 +2279,8 @@ // Simulate a form submission with the same masked server card. FormData form; + form.origin = GURL("https://wwww.foo.com"); + AddFullCreditCardForm(&form, "Biggie Smalls", "4111 1111 1111 1111", "01", "2999"); @@ -2203,6 +2315,8 @@ // Simulate a form submission with the same full server card. FormData form; + form.origin = GURL("https://wwww.foo.com"); + AddFullCreditCardForm(&form, "Biggie Smalls", "378282246310005", "04", "2999"); @@ -2224,6 +2338,8 @@ ImportFormData_ImportCreditCardRecordType_NoCard_InvalidCardNumber) { // Simulate a form submission using a credit card with an invalid card number. FormData form; + form.origin = GURL("https://wwww.foo.com"); + AddFullCreditCardForm(&form, "Biggie Smalls", "4111 1111 1111 1112", "01", "2999"); @@ -2246,6 +2362,8 @@ ImportFormData_ImportCreditCardRecordType_NoCard_ExpiredCard) { // Simulate a form submission with an expired credit card. FormData form; + form.origin = GURL("https://wwww.foo.com"); + AddFullCreditCardForm(&form, "Biggie Smalls", "4111 1111 1111 1111", "01", "1999"); @@ -2268,6 +2386,8 @@ ImportFormData_ImportCreditCardRecordType_NoCard_NoCardOnForm) { // Simulate a form submission with no credit card on form. FormData form; + form.origin = GURL("https://wwww.foo.com"); + FormFieldData field; test::CreateTestFormField("First name:", "first_name", "George", "text", &field); @@ -2308,6 +2428,8 @@ // address and the credit card. TEST_F(FormDataImporterTest, ImportFormData_OneAddressOneCreditCard) { FormData form; + form.origin = GURL("https://wwww.foo.com"); + FormFieldData field; // Address section. test::CreateTestFormField("First name:", "first_name", "George", "text", @@ -2371,6 +2493,8 @@ // import the address but does import the credit card. TEST_F(FormDataImporterTest, ImportFormData_TwoAddressesOneCreditCard) { FormData form; + form.origin = GURL("https://wwww.foo.com"); + FormFieldData field; // Address section 1. test::CreateTestFormField("First name:", "first_name", "George", "text", @@ -2441,6 +2565,8 @@ // the credit card if addresses are disabled. TEST_F(FormDataImporterTest, ImportFormData_AddressesDisabledOneCreditCard) { FormData form; + form.origin = GURL("https://wwww.foo.com"); + FormFieldData field; // Address section. test::CreateTestFormField("First name:", "first_name", "George", "text", @@ -2495,6 +2621,8 @@ // the address if credit cards are disabled. TEST_F(FormDataImporterTest, ImportFormData_OneAddressCreditCardDisabled) { FormData form; + form.origin = GURL("https://wwww.foo.com"); + FormFieldData field; // Address section. test::CreateTestFormField("First name:", "first_name", "George", "text", @@ -2553,6 +2681,8 @@ // if both addressed and credit cards are disabled. TEST_F(FormDataImporterTest, ImportFormData_AddressCreditCardDisabled) { FormData form; + form.origin = GURL("https://wwww.foo.com"); + FormFieldData field; // Address section. test::CreateTestFormField("First name:", "first_name", "George", "text", @@ -2621,6 +2751,8 @@ // A valid credit card form. A user re-enters one of their masked cards. // We should not offer to save locally. FormData form; + form.origin = GURL("https://wwww.foo.com"); + FormFieldData field; test::CreateTestFormField("Name on card:", "name_on_card", "John Dillinger", "text", &field); @@ -2668,6 +2800,8 @@ // here, either. Since it's unmasked, we know for certain that it's the same // card. FormData form; + form.origin = GURL("https://wwww.foo.com"); + FormFieldData field; test::CreateTestFormField("Name on card:", "name_on_card", "Clyde Barrow", "text", &field); @@ -2710,6 +2844,8 @@ // A user fills/enters the card's information on a checkout form. Ensure that // an expiration date match is recorded. FormData form; + form.origin = GURL("https://wwww.foo.com"); + FormFieldData field; test::CreateTestFormField("Name on card:", "name_on_card", "Clyde Barrow", "text", &field); @@ -2757,6 +2893,8 @@ // the expiration date of the card. Ensure that an expiration date mismatch // is recorded. FormData form; + form.origin = GURL("https://wwww.foo.com"); + FormFieldData field; test::CreateTestFormField("Name on card:", "name_on_card", "Clyde Barrow", "text", &field); @@ -2804,6 +2942,8 @@ // A user fills/enters the card's information on a checkout form. Ensure that // an expiration date match is recorded. FormData form; + form.origin = GURL("https://wwww.foo.com"); + FormFieldData field; test::CreateTestFormField("Name on card:", "name_on_card", "Clyde Barrow", "text", &field); @@ -2852,6 +2992,8 @@ // the expiration date of the card. Ensure that an expiration date mismatch // is recorded. FormData form; + form.origin = GURL("https://wwww.foo.com"); + FormFieldData field; test::CreateTestFormField("Name on card:", "name_on_card", "Clyde Barrow", "text", &field);
diff --git a/components/autofill/core/browser/form_structure.cc b/components/autofill/core/browser/form_structure.cc index bcf37e6..472cdfe 100644 --- a/components/autofill/core/browser/form_structure.cc +++ b/components/autofill/core/browser/form_structure.cc
@@ -61,6 +61,14 @@ const int kCommonNamePrefixRemovalFieldThreshold = 3; const int kMinCommonNamePrefixLength = 16; +// Returns true if the scheme given by |url| is one for which autfill is allowed +// to activate. By default this only returns true for HTTP and HTTPS. +bool HasAllowedScheme(const GURL& url) { + return url.SchemeIsHTTPOrHTTPS() || + base::FeatureList::IsEnabled( + features::kAutofillAllowNonHttpActivation); +} + // Helper for |EncodeUploadRequest()| that creates a bit field corresponding to // |available_field_types| and returns the hex representation as a string. std::string EncodeFieldTypes(const ServerFieldTypeSet& available_field_types) { @@ -690,6 +698,10 @@ } bool FormStructure::ShouldBeParsed() const { + // Exclude URLs not on the web via HTTP(S). + if (!HasAllowedScheme(source_url_)) + return false; + size_t min_required_fields = std::min({MinRequiredFieldsForHeuristics(), MinRequiredFieldsForQuery(), MinRequiredFieldsForUpload()}); @@ -718,6 +730,7 @@ bool FormStructure::ShouldRunHeuristics() const { return active_field_count() >= MinRequiredFieldsForHeuristics() && + HasAllowedScheme(source_url_) && (is_form_tag_ || is_formless_checkout_ || !base::FeatureList::IsEnabled( features::kAutofillRestrictUnownedFieldsToFormlessCheckout));
diff --git a/components/autofill/core/browser/form_structure_unittest.cc b/components/autofill/core/browser/form_structure_unittest.cc index d9eef3c0..0f881919 100644 --- a/components/autofill/core/browser/form_structure_unittest.cc +++ b/components/autofill/core/browser/form_structure_unittest.cc
@@ -144,6 +144,7 @@ TEST_F(FormStructureTest, FieldCount) { std::unique_ptr<FormStructure> form_structure; FormData form; + form.origin = GURL("http://www.foo.com/"); FormFieldData field; field.label = ASCIIToUTF16("username"); @@ -169,13 +170,14 @@ // The render process sends all fields to browser including fields with // autocomplete=off - form_structure.reset(new FormStructure(form)); + form_structure = std::make_unique<FormStructure>(form); EXPECT_EQ(4U, form_structure->field_count()); } TEST_F(FormStructureTest, AutofillCount) { std::unique_ptr<FormStructure> form_structure; FormData form; + form.origin = GURL("http://www.foo.com/"); FormFieldData field; field.label = ASCIIToUTF16("username"); @@ -209,7 +211,7 @@ form.fields.push_back(field); // Only text and select fields that are heuristically matched are counted. - form_structure.reset(new FormStructure(form)); + form_structure = std::make_unique<FormStructure>(form); form_structure->DetermineHeuristicTypes(); EXPECT_EQ(3U, form_structure->autofill_count()); @@ -221,7 +223,7 @@ field.should_autocomplete = false; form.fields.push_back(field); - form_structure.reset(new FormStructure(form)); + form_structure = std::make_unique<FormStructure>(form); form_structure->DetermineHeuristicTypes(); EXPECT_EQ(4U, form_structure->autofill_count()); } @@ -236,6 +238,7 @@ TEST_F(FormStructureTest, IsAutofillable) { FormData form; + form.origin = GURL("http://www.foo.com/"); FormFieldData field; // Start with a username field. It should be picked up by the password but @@ -303,6 +306,7 @@ TEST_F(FormStructureTest, ShouldBeParsed) { FormData form; + form.origin = GURL("http://www.foo.com/"); // Start with a single checkable field. FormFieldData checkable_field; @@ -396,11 +400,90 @@ CheckFormShouldBeParsed("new password", form, true, true); } +TEST_F(FormStructureTest, ShouldBeParsed_BadScheme) { + std::unique_ptr<FormStructure> form_structure; + FormData form; + FormFieldData field; + + field.label = ASCIIToUTF16("Name"); + field.name = ASCIIToUTF16("name"); + field.form_control_type = "text"; + field.autocomplete_attribute = "name"; + form.fields.push_back(field); + + field.label = ASCIIToUTF16("Email"); + field.name = ASCIIToUTF16("email"); + field.form_control_type = "text"; + field.autocomplete_attribute = "email"; + form.fields.push_back(field); + + field.label = ASCIIToUTF16("Address"); + field.name = ASCIIToUTF16("address"); + field.form_control_type = "text"; + field.autocomplete_attribute = "address-line1"; + form.fields.push_back(field); + + // Baseline, HTTP should work. + form.origin = GURL("http://wwww.foo.com/myform"); + form_structure = std::make_unique<FormStructure>(form); + form_structure->ParseFieldTypesFromAutocompleteAttributes(); + EXPECT_TRUE(form_structure->ShouldBeParsed()); + EXPECT_TRUE(form_structure->ShouldRunHeuristics()); + EXPECT_TRUE(form_structure->ShouldBeQueried()); + EXPECT_TRUE(form_structure->ShouldBeUploaded()); + + // Baseline, HTTPS should work. + form.origin = GURL("https://wwww.foo.com/myform"); + form_structure = std::make_unique<FormStructure>(form); + form_structure->ParseFieldTypesFromAutocompleteAttributes(); + EXPECT_TRUE(form_structure->ShouldBeParsed()); + EXPECT_TRUE(form_structure->ShouldRunHeuristics()); + EXPECT_TRUE(form_structure->ShouldBeQueried()); + EXPECT_TRUE(form_structure->ShouldBeUploaded()); + + // Chrome internal urls shouldn't be parsed. + form.origin = GURL("chrome://settings"); + form_structure = std::make_unique<FormStructure>(form); + form_structure->ParseFieldTypesFromAutocompleteAttributes(); + EXPECT_FALSE(form_structure->ShouldBeParsed()); + EXPECT_FALSE(form_structure->ShouldRunHeuristics()); + EXPECT_FALSE(form_structure->ShouldBeQueried()); + EXPECT_FALSE(form_structure->ShouldBeUploaded()); + + // FTP urls shouldn't be parsed. + form.origin = GURL("ftp://ftp.foo.com/form.html"); + form_structure = std::make_unique<FormStructure>(form); + form_structure->ParseFieldTypesFromAutocompleteAttributes(); + EXPECT_FALSE(form_structure->ShouldBeParsed()); + EXPECT_FALSE(form_structure->ShouldRunHeuristics()); + EXPECT_FALSE(form_structure->ShouldBeQueried()); + EXPECT_FALSE(form_structure->ShouldBeUploaded()); + + // Blob urls shouldn't be parsed. + form.origin = GURL("blob://blob.foo.com/form.html"); + form_structure = std::make_unique<FormStructure>(form); + form_structure->ParseFieldTypesFromAutocompleteAttributes(); + EXPECT_FALSE(form_structure->ShouldBeParsed()); + EXPECT_FALSE(form_structure->ShouldRunHeuristics()); + EXPECT_FALSE(form_structure->ShouldBeQueried()); + EXPECT_FALSE(form_structure->ShouldBeUploaded()); + + // About urls shouldn't be parsed. + form.origin = GURL("about://about.foo.com/form.html"); + form_structure = std::make_unique<FormStructure>(form); + form_structure->ParseFieldTypesFromAutocompleteAttributes(); + EXPECT_FALSE(form_structure->ShouldBeParsed()); + EXPECT_FALSE(form_structure->ShouldRunHeuristics()); + EXPECT_FALSE(form_structure->ShouldBeQueried()); + EXPECT_FALSE(form_structure->ShouldBeUploaded()); +} + // Tests that ShouldBeParsed returns true for a form containing less than three // fields if at least one has an autocomplete attribute. TEST_F(FormStructureTest, ShouldBeParsed_TwoFields_HasAutocomplete) { std::unique_ptr<FormStructure> form_structure; FormData form; + form.origin = GURL("http://www.foo.com/"); FormFieldData field; field.label = ASCIIToUTF16("Name"); @@ -415,7 +498,7 @@ field.autocomplete_attribute = ""; form.fields.push_back(field); - form_structure.reset(new FormStructure(form)); + form_structure = std::make_unique<FormStructure>(form); form_structure->ParseFieldTypesFromAutocompleteAttributes(); EXPECT_TRUE(form_structure->ShouldBeParsed()); } @@ -425,6 +508,7 @@ TEST_F(FormStructureTest, DetermineHeuristicTypes_AutocompleteFalse) { std::unique_ptr<FormStructure> form_structure; FormData form; + form.origin = GURL("http://www.foo.com/"); FormFieldData field; field.label = ASCIIToUTF16("Name"); @@ -445,7 +529,7 @@ field.autocomplete_attribute = "false"; form.fields.push_back(field); - form_structure.reset(new FormStructure(form)); + form_structure = std::make_unique<FormStructure>(form); form_structure->DetermineHeuristicTypes(); EXPECT_TRUE(form_structure->ShouldBeParsed()); EXPECT_EQ(3U, form_structure->autofill_count()); @@ -458,6 +542,7 @@ TEST_F(FormStructureTest, HeuristicsContactInfo) { std::unique_ptr<FormStructure> form_structure; FormData form; + form.origin = GURL("http://www.foo.com/"); FormFieldData field; field.form_control_type = "text"; @@ -499,7 +584,7 @@ field.form_control_type = "submit"; form.fields.push_back(field); - form_structure.reset(new FormStructure(form)); + form_structure = std::make_unique<FormStructure>(form); form_structure->DetermineHeuristicTypes(); EXPECT_TRUE(form_structure->IsAutofillable()); @@ -532,6 +617,7 @@ TEST_F(FormStructureTest, HeuristicsAutocompleteAttribute) { std::unique_ptr<FormStructure> form_structure; FormData form; + form.origin = GURL("http://www.foo.com/"); FormFieldData field; field.form_control_type = "text"; @@ -556,7 +642,7 @@ field.autocomplete_attribute = "upi-vpa"; form.fields.push_back(field); - form_structure.reset(new FormStructure(form)); + form_structure = std::make_unique<FormStructure>(form); form_structure->DetermineHeuristicTypes(); EXPECT_TRUE(form_structure->IsAutofillable()); EXPECT_TRUE(form_structure->has_author_specified_types()); @@ -583,6 +669,7 @@ features::kAutofillRestrictUnownedFieldsToFormlessCheckout); std::unique_ptr<FormStructure> form_structure; FormData form; + form.origin = GURL("http://www.foo.com/"); FormFieldData field; field.form_control_type = "text"; @@ -602,7 +689,7 @@ field.autocomplete_attribute = "email"; form.fields.push_back(field); - form_structure.reset(new FormStructure(form)); + form_structure = std::make_unique<FormStructure>(form); form_structure->DetermineHeuristicTypes(); EXPECT_TRUE(form_structure->IsAutofillable()); @@ -618,7 +705,7 @@ form.is_formless_checkout = false; form.is_form_tag = false; - form_structure.reset(new FormStructure(form)); + form_structure = std::make_unique<FormStructure>(form); form_structure->DetermineHeuristicTypes(); EXPECT_TRUE(form_structure->IsAutofillable()); @@ -635,6 +722,8 @@ // that the common prefix is stripped out before running heuristics. TEST_F(FormStructureTest, StripCommonNamePrefix) { FormData form; + form.origin = GURL("http://www.foo.com/"); + FormFieldData field; field.form_control_type = "text"; @@ -684,6 +773,8 @@ // stripped from the name before running the heuristics. TEST_F(FormStructureTest, StripCommonNamePrefix_SmallPrefix) { FormData form; + form.origin = GURL("http://www.foo.com/"); + FormFieldData field; field.form_control_type = "text"; @@ -718,6 +809,7 @@ TEST_F(FormStructureTest, IsCompleteCreditCardForm_Minimal) { std::unique_ptr<FormStructure> form_structure; FormData form; + form.origin = GURL("http://www.foo.com/"); FormFieldData field; field.form_control_type = "text"; @@ -735,7 +827,7 @@ field.name = ASCIIToUTF16("zip"); form.fields.push_back(field); - form_structure.reset(new FormStructure(form)); + form_structure = std::make_unique<FormStructure>(form); form_structure->DetermineHeuristicTypes(); EXPECT_TRUE(form_structure->IsCompleteCreditCardForm()); @@ -744,6 +836,7 @@ TEST_F(FormStructureTest, IsCompleteCreditCardForm_Full) { std::unique_ptr<FormStructure> form_structure; FormData form; + form.origin = GURL("http://www.foo.com/"); FormFieldData field; field.form_control_type = "text"; @@ -773,7 +866,7 @@ field.form_control_type = "submit"; form.fields.push_back(field); - form_structure.reset(new FormStructure(form)); + form_structure = std::make_unique<FormStructure>(form); form_structure->DetermineHeuristicTypes(); EXPECT_TRUE(form_structure->IsCompleteCreditCardForm()); @@ -783,6 +876,7 @@ TEST_F(FormStructureTest, IsCompleteCreditCardForm_OnlyCCNumber) { std::unique_ptr<FormStructure> form_structure; FormData form; + form.origin = GURL("http://www.foo.com/"); FormFieldData field; field.form_control_type = "text"; @@ -791,7 +885,7 @@ field.name = ASCIIToUTF16("card_number"); form.fields.push_back(field); - form_structure.reset(new FormStructure(form)); + form_structure = std::make_unique<FormStructure>(form); form_structure->DetermineHeuristicTypes(); EXPECT_FALSE(form_structure->IsCompleteCreditCardForm()); @@ -801,6 +895,7 @@ TEST_F(FormStructureTest, IsCompleteCreditCardForm_AddressForm) { std::unique_ptr<FormStructure> form_structure; FormData form; + form.origin = GURL("http://www.foo.com/"); FormFieldData field; field.form_control_type = "text"; @@ -832,7 +927,7 @@ field.label = ASCIIToUTF16("Zip code"); field.name = base::string16(); form.fields.push_back(field); - form_structure.reset(new FormStructure(form)); + form_structure = std::make_unique<FormStructure>(form); form_structure->DetermineHeuristicTypes(); EXPECT_FALSE(form_structure->IsCompleteCreditCardForm()); @@ -843,6 +938,7 @@ TEST_F(FormStructureTest, HeuristicsAutocompleteAttributePhoneTypes) { std::unique_ptr<FormStructure> form_structure; FormData form; + form.origin = GURL("http://www.foo.com/"); FormFieldData field; field.form_control_type = "text"; @@ -862,7 +958,7 @@ field.autocomplete_attribute = "tel-local-suffix"; form.fields.push_back(field); - form_structure.reset(new FormStructure(form)); + form_structure = std::make_unique<FormStructure>(form); form_structure->DetermineHeuristicTypes(); EXPECT_TRUE(form_structure->IsAutofillable()); @@ -886,6 +982,7 @@ HeuristicsAndServerPredictions_BigForm_NoAutocompleteAttribute) { std::unique_ptr<FormStructure> form_structure; FormData form; + form.origin = GURL("http://www.foo.com/"); FormFieldData field; field.form_control_type = "text"; @@ -902,7 +999,7 @@ field.name = ASCIIToUTF16("email"); form.fields.push_back(field); - form_structure.reset(new FormStructure(form)); + form_structure = std::make_unique<FormStructure>(form); form_structure->DetermineHeuristicTypes(); EXPECT_TRUE(form_structure->IsAutofillable()); EXPECT_TRUE(form_structure->ShouldBeQueried()); @@ -922,6 +1019,7 @@ HeuristicsAndServerPredictions_ValidAutocompleteAttribute) { std::unique_ptr<FormStructure> form_structure; FormData form; + form.origin = GURL("http://www.foo.com/"); FormFieldData field; field.form_control_type = "text"; @@ -941,7 +1039,7 @@ field.name = ASCIIToUTF16("email"); form.fields.push_back(field); - form_structure.reset(new FormStructure(form)); + form_structure = std::make_unique<FormStructure>(form); form_structure->DetermineHeuristicTypes(); EXPECT_TRUE(form_structure->IsAutofillable()); EXPECT_TRUE(form_structure->ShouldBeQueried()); @@ -962,6 +1060,7 @@ HeuristicsAndServerPredictions_UnrecognizedAutocompleteAttribute) { std::unique_ptr<FormStructure> form_structure; FormData form; + form.origin = GURL("http://www.foo.com/"); FormFieldData field; field.form_control_type = "text"; @@ -985,7 +1084,7 @@ field.name = ASCIIToUTF16("email"); form.fields.push_back(field); - form_structure.reset(new FormStructure(form)); + form_structure = std::make_unique<FormStructure>(form); form_structure->DetermineHeuristicTypes(); EXPECT_TRUE(form_structure->IsAutofillable()); EXPECT_TRUE(form_structure->ShouldBeQueried()); @@ -1004,6 +1103,8 @@ TEST_F(FormStructureTest, HeuristicsAndServerPredictions_SmallForm_NoAutocompleteAttribute) { FormData form; + form.origin = GURL("http://www.foo.com/"); + FormFieldData field; field.form_control_type = "text"; field.label = ASCIIToUTF16("First Name"); @@ -1076,6 +1177,7 @@ TEST_F(FormStructureTest, HeuristicsAndServerPredictions_SmallForm_ValidAutocompleteAttribute) { FormData form; + form.origin = GURL("http://www.foo.com/"); FormFieldData field; field.form_control_type = "text"; @@ -1162,6 +1264,7 @@ // considered autofillable though. TEST_F(FormStructureTest, PasswordFormShouldBeQueried) { FormData form; + form.origin = GURL("http://www.foo.com/"); // Start with a regular contact form. FormFieldData field; @@ -1195,6 +1298,7 @@ // attribute. TEST_F(FormStructureTest, HeuristicsAutocompleteAttributeWithSections) { FormData form; + form.origin = GURL("http://www.foo.com/"); FormFieldData field; field.form_control_type = "text"; @@ -1259,6 +1363,7 @@ TEST_F(FormStructureTest, HeuristicsAutocompleteAttributeWithSectionsDegenerate) { FormData form; + form.origin = GURL("http://www.foo.com/"); FormFieldData field; field.form_control_type = "text"; @@ -1302,6 +1407,7 @@ // |autocomplete| attribute. TEST_F(FormStructureTest, HeuristicsAutocompleteAttributeWithSectionsRepeated) { FormData form; + form.origin = GURL("http://www.foo.com/"); FormFieldData field; field.form_control_type = "text"; @@ -1331,6 +1437,7 @@ // local heuristics. TEST_F(FormStructureTest, HeuristicsDontOverrideAutocompleteAttributeSections) { FormData form; + form.origin = GURL("http://www.foo.com/"); FormFieldData field; field.form_control_type = "text"; @@ -1366,6 +1473,7 @@ TEST_F(FormStructureTest, HeuristicsSample8) { std::unique_ptr<FormStructure> form_structure; FormData form; + form.origin = GURL("http://www.foo.com/"); FormFieldData field; field.form_control_type = "text"; @@ -1411,7 +1519,7 @@ field.form_control_type = "submit"; form.fields.push_back(field); - form_structure.reset(new FormStructure(form)); + form_structure = std::make_unique<FormStructure>(form); form_structure->DetermineHeuristicTypes(); EXPECT_TRUE(form_structure->IsAutofillable()); ASSERT_EQ(10U, form_structure->field_count()); @@ -1443,6 +1551,7 @@ TEST_F(FormStructureTest, HeuristicsSample6) { std::unique_ptr<FormStructure> form_structure; FormData form; + form.origin = GURL("http://www.foo.com/"); FormFieldData field; field.form_control_type = "text"; @@ -1477,7 +1586,7 @@ field.form_control_type = "submit"; form.fields.push_back(field); - form_structure.reset(new FormStructure(form)); + form_structure = std::make_unique<FormStructure>(form); form_structure->DetermineHeuristicTypes(); EXPECT_TRUE(form_structure->IsAutofillable()); ASSERT_EQ(7U, form_structure->field_count()); @@ -1505,6 +1614,7 @@ TEST_F(FormStructureTest, HeuristicsLabelsOnly) { std::unique_ptr<FormStructure> form_structure; FormData form; + form.origin = GURL("http://www.foo.com/"); FormFieldData field; field.form_control_type = "text"; @@ -1542,7 +1652,7 @@ field.form_control_type = "submit"; form.fields.push_back(field); - form_structure.reset(new FormStructure(form)); + form_structure = std::make_unique<FormStructure>(form); form_structure->DetermineHeuristicTypes(); EXPECT_TRUE(form_structure->IsAutofillable()); ASSERT_EQ(8U, form_structure->field_count()); @@ -1570,6 +1680,7 @@ TEST_F(FormStructureTest, HeuristicsCreditCardInfo) { std::unique_ptr<FormStructure> form_structure; FormData form; + form.origin = GURL("http://www.foo.com/"); FormFieldData field; field.form_control_type = "text"; @@ -1599,7 +1710,7 @@ field.form_control_type = "submit"; form.fields.push_back(field); - form_structure.reset(new FormStructure(form)); + form_structure = std::make_unique<FormStructure>(form); form_structure->DetermineHeuristicTypes(); EXPECT_TRUE(form_structure->IsAutofillable()); ASSERT_EQ(6U, form_structure->field_count()); @@ -1624,6 +1735,7 @@ TEST_F(FormStructureTest, HeuristicsCreditCardInfoWithUnknownCardField) { std::unique_ptr<FormStructure> form_structure; FormData form; + form.origin = GURL("http://www.foo.com/"); FormFieldData field; field.form_control_type = "text"; @@ -1659,7 +1771,7 @@ field.form_control_type = "submit"; form.fields.push_back(field); - form_structure.reset(new FormStructure(form)); + form_structure = std::make_unique<FormStructure>(form); form_structure->DetermineHeuristicTypes(); EXPECT_TRUE(form_structure->IsAutofillable()); ASSERT_EQ(7U, form_structure->field_count()); @@ -1686,6 +1798,7 @@ TEST_F(FormStructureTest, ThreeAddressLines) { std::unique_ptr<FormStructure> form_structure; FormData form; + form.origin = GURL("http://www.foo.com/"); FormFieldData field; field.form_control_type = "text"; @@ -1706,7 +1819,7 @@ field.name = ASCIIToUTF16("city"); form.fields.push_back(field); - form_structure.reset(new FormStructure(form)); + form_structure = std::make_unique<FormStructure>(form); form_structure->DetermineHeuristicTypes(); EXPECT_TRUE(form_structure->IsAutofillable()); ASSERT_EQ(4U, form_structure->field_count()); @@ -1726,6 +1839,7 @@ TEST_F(FormStructureTest, SurplusAddressLinesIgnored) { std::unique_ptr<FormStructure> form_structure; FormData form; + form.origin = GURL("http://www.foo.com/"); FormFieldData field; field.form_control_type = "text"; @@ -1746,7 +1860,7 @@ field.name = ASCIIToUTF16("billing.address.addressLine4"); form.fields.push_back(field); - form_structure.reset(new FormStructure(form)); + form_structure = std::make_unique<FormStructure>(form); form_structure->DetermineHeuristicTypes(); ASSERT_EQ(4U, form_structure->field_count()); ASSERT_EQ(3U, form_structure->autofill_count()); @@ -1769,6 +1883,7 @@ TEST_F(FormStructureTest, ThreeAddressLinesExpedia) { std::unique_ptr<FormStructure> form_structure; FormData form; + form.origin = GURL("http://www.foo.com/"); FormFieldData field; field.form_control_type = "text"; @@ -1789,7 +1904,7 @@ field.name = ASCIIToUTF16("FOPIH_RgWebCC_0_IHAddress_adct"); form.fields.push_back(field); - form_structure.reset(new FormStructure(form)); + form_structure = std::make_unique<FormStructure>(form); form_structure->DetermineHeuristicTypes(); EXPECT_TRUE(form_structure->IsAutofillable()); ASSERT_EQ(4U, form_structure->field_count()); @@ -1811,6 +1926,7 @@ TEST_F(FormStructureTest, TwoAddressLinesEbay) { std::unique_ptr<FormStructure> form_structure; FormData form; + form.origin = GURL("http://www.foo.com/"); FormFieldData field; field.form_control_type = "text"; @@ -1827,7 +1943,7 @@ field.name = ASCIIToUTF16("city"); form.fields.push_back(field); - form_structure.reset(new FormStructure(form)); + form_structure = std::make_unique<FormStructure>(form); form_structure->DetermineHeuristicTypes(); EXPECT_TRUE(form_structure->IsAutofillable()); ASSERT_EQ(3U, form_structure->field_count()); @@ -1844,6 +1960,7 @@ TEST_F(FormStructureTest, HeuristicsStateWithProvince) { std::unique_ptr<FormStructure> form_structure; FormData form; + form.origin = GURL("http://www.foo.com/"); FormFieldData field; field.form_control_type = "text"; @@ -1860,7 +1977,7 @@ field.name = ASCIIToUTF16("State"); form.fields.push_back(field); - form_structure.reset(new FormStructure(form)); + form_structure = std::make_unique<FormStructure>(form); form_structure->DetermineHeuristicTypes(); EXPECT_TRUE(form_structure->IsAutofillable()); ASSERT_EQ(3U, form_structure->field_count()); @@ -1878,6 +1995,7 @@ TEST_F(FormStructureTest, HeuristicsWithBilling) { std::unique_ptr<FormStructure> form_structure; FormData form; + form.origin = GURL("http://www.foo.com/"); FormFieldData field; field.form_control_type = "text"; @@ -1926,7 +2044,7 @@ field.name = ASCIIToUTF16("email$emailBox"); form.fields.push_back(field); - form_structure.reset(new FormStructure(form)); + form_structure = std::make_unique<FormStructure>(form); form_structure->DetermineHeuristicTypes(); EXPECT_TRUE(form_structure->IsAutofillable()); ASSERT_EQ(11U, form_structure->field_count()); @@ -1949,6 +2067,7 @@ TEST_F(FormStructureTest, ThreePartPhoneNumber) { std::unique_ptr<FormStructure> form_structure; FormData form; + form.origin = GURL("http://www.foo.com/"); FormFieldData field; field.form_control_type = "text"; @@ -1975,7 +2094,7 @@ field.max_length = 0; form.fields.push_back(field); - form_structure.reset(new FormStructure(form)); + form_structure = std::make_unique<FormStructure>(form); form_structure->DetermineHeuristicTypes(); EXPECT_TRUE(form_structure->IsAutofillable()); ASSERT_EQ(4U, form_structure->field_count()); @@ -1994,6 +2113,7 @@ TEST_F(FormStructureTest, HeuristicsInfernoCC) { std::unique_ptr<FormStructure> form_structure; FormData form; + form.origin = GURL("http://www.foo.com/"); FormFieldData field; field.form_control_type = "text"; @@ -2018,7 +2138,7 @@ field.name = ASCIIToUTF16("expiration_year"); form.fields.push_back(field); - form_structure.reset(new FormStructure(form)); + form_structure = std::make_unique<FormStructure>(form); form_structure->DetermineHeuristicTypes(); EXPECT_TRUE(form_structure->IsAutofillable()); @@ -2044,6 +2164,7 @@ TEST_F(FormStructureTest, HeuristicsInferCCNames_NamesNotFirst) { std::unique_ptr<FormStructure> form_structure; FormData form; + form.origin = GURL("http://www.foo.com/"); FormFieldData field; field.form_control_type = "text"; @@ -2072,7 +2193,7 @@ field.name = ASCIIToUTF16("csc"); form.fields.push_back(field); - form_structure.reset(new FormStructure(form)); + form_structure = std::make_unique<FormStructure>(form); form_structure->DetermineHeuristicTypes(); EXPECT_TRUE(form_structure->IsAutofillable()); @@ -2102,6 +2223,7 @@ TEST_F(FormStructureTest, HeuristicsInferCCNames_NamesFirst) { std::unique_ptr<FormStructure> form_structure; FormData form; + form.origin = GURL("http://www.foo.com/"); FormFieldData field; field.form_control_type = "text"; @@ -2130,7 +2252,7 @@ field.name = ASCIIToUTF16("csc"); form.fields.push_back(field); - form_structure.reset(new FormStructure(form)); + form_structure = std::make_unique<FormStructure>(form); form_structure->DetermineHeuristicTypes(); EXPECT_TRUE(form_structure->IsAutofillable()); @@ -2156,6 +2278,7 @@ TEST_F(FormStructureTest, EncodeQueryRequest) { FormData form; + form.origin = GURL("http://www.foo.com/"); FormFieldData field; field.form_control_type = "text"; @@ -2196,7 +2319,7 @@ AutofillQueryContents query; query.set_client_version("6.1.1715.1442/en (GGLL)"); AutofillQueryContents::Form* query_form = query.add_form(); - query_form->set_signature(11337937696949187602U); + query_form->set_signature(form_structure.form_signature()); test::FillQueryField(query_form->add_field(), 412125936U, "name_on_card", "text"); @@ -2212,7 +2335,7 @@ std::string expected_query_string; ASSERT_TRUE(query.SerializeToString(&expected_query_string)); - const char kSignature1[] = "11337937696949187602"; + const std::string kSignature1 = form_structure.FormSignatureAsStr(); AutofillQueryContents encoded_query; ASSERT_TRUE(FormStructure::EncodeQueryRequest(forms, &encoded_signatures, @@ -2250,7 +2373,7 @@ // Add the second form to the expected proto. query_form = query.add_form(); - query_form->set_signature(8308881815906226214U); + query_form->set_signature(form_structure3.form_signature()); test::FillQueryField(query_form->add_field(), 412125936U, "name_on_card", "text"); @@ -2274,7 +2397,7 @@ &encoded_query3)); ASSERT_EQ(2U, encoded_signatures.size()); EXPECT_EQ(kSignature1, encoded_signatures[0]); - const char kSignature2[] = "8308881815906226214"; + const std::string kSignature2 = form_structure3.FormSignatureAsStr(); EXPECT_EQ(kSignature2, encoded_signatures[1]); encoded_query3.SerializeToString(&encoded_query_string); @@ -2317,7 +2440,9 @@ std::vector<ServerFieldTypeSet> possible_field_types; std::vector<ServerFieldTypeValidityStatesMap> possible_field_types_validities; FormData form; - form_structure.reset(new FormStructure(form)); + form.origin = GURL("http://www.foo.com/"); + + form_structure = std::make_unique<FormStructure>(form); form_structure->DetermineHeuristicTypes(); FormFieldData field; @@ -2371,7 +2496,7 @@ {ADDRESS_HOME_COUNTRY}, {AutofillProfile::VALID}); form.fields.push_back(checkable_field); - form_structure.reset(new FormStructure(form)); + form_structure = std::make_unique<FormStructure>(form); form_structure->set_password_attributes_vote( std::make_pair(PasswordAttribute::kHasNumeric, true)); form_structure->set_password_length_vote(10u); @@ -2400,7 +2525,7 @@ AutofillUploadContents upload; upload.set_submission(true); upload.set_client_version("6.1.1715.1442/en (GGLL)"); - upload.set_form_signature(8736493185895608956U); + upload.set_form_signature(form_structure->form_signature()); upload.set_autofill_used(false); upload.set_data_present("144200030e"); upload.set_passwords_revealed(false); @@ -2463,7 +2588,7 @@ AutofillProfile::INVALID, AutofillProfile::INVALID}); } - form_structure.reset(new FormStructure(form)); + form_structure = std::make_unique<FormStructure>(form); form_structure->set_password_attributes_vote( std::make_pair(PasswordAttribute::kHasNumeric, true)); form_structure->set_password_length_vote(10u); @@ -2478,7 +2603,7 @@ } // Adjust the expected proto string. - upload.set_form_signature(7816485729218079147U); + upload.set_form_signature(form_structure->form_signature()); upload.set_autofill_used(false); // Create an additional 2 fields (total of 7). Put the appropriate autofill // type on the different address fields. @@ -2508,7 +2633,9 @@ std::vector<ServerFieldTypeSet> possible_field_types; std::vector<ServerFieldTypeValidityStatesMap> possible_field_types_validities; FormData form; - form_structure.reset(new FormStructure(form)); + form.origin = GURL("http://www.foo.com/"); + + form_structure = std::make_unique<FormStructure>(form); form_structure->DetermineHeuristicTypes(); FormFieldData field; @@ -2562,7 +2689,7 @@ {ADDRESS_HOME_COUNTRY}, {AutofillProfile::VALID}); form.fields.push_back(checkable_field); - form_structure.reset(new FormStructure(form)); + form_structure = std::make_unique<FormStructure>(form); form_structure->set_password_attributes_vote( std::make_pair(PasswordAttribute::kHasNumeric, true)); form_structure->set_password_length_vote(10u); @@ -2591,7 +2718,7 @@ AutofillUploadContents upload; upload.set_submission(true); upload.set_client_version("6.1.1715.1442/en (GGLL)"); - upload.set_form_signature(8736493185895608956U); + upload.set_form_signature(form_structure->form_signature()); upload.set_autofill_used(false); upload.set_data_present("144200030e"); upload.set_passwords_revealed(false); @@ -2634,7 +2761,9 @@ std::vector<ServerFieldTypeSet> possible_field_types; std::vector<ServerFieldTypeValidityStatesMap> possible_field_types_validities; FormData form; - form_structure.reset(new FormStructure(form)); + form.origin = GURL("http://www.foo.com/"); + + form_structure = std::make_unique<FormStructure>(form); form_structure->DetermineHeuristicTypes(); FormFieldData field; @@ -2689,7 +2818,7 @@ {ADDRESS_HOME_COUNTRY}, {AutofillProfile::VALID, AutofillProfile::VALID}); form.fields.push_back(checkable_field); - form_structure.reset(new FormStructure(form)); + form_structure = std::make_unique<FormStructure>(form); form_structure->set_password_attributes_vote( std::make_pair(PasswordAttribute::kHasNumeric, true)); form_structure->set_password_length_vote(10u); @@ -2718,7 +2847,7 @@ AutofillUploadContents upload; upload.set_submission(true); upload.set_client_version("6.1.1715.1442/en (GGLL)"); - upload.set_form_signature(8736493185895608956U); + upload.set_form_signature(form_structure->form_signature()); upload.set_autofill_used(false); upload.set_data_present("144200030e"); upload.set_passwords_revealed(false); @@ -2759,7 +2888,9 @@ std::vector<ServerFieldTypeSet> possible_field_types; std::vector<ServerFieldTypeValidityStatesMap> possible_field_types_validities; FormData form; - form_structure.reset(new FormStructure(form)); + form.origin = GURL("http://www.foo.com/"); + + form_structure = std::make_unique<FormStructure>(form); form_structure->DetermineHeuristicTypes(); FormFieldData field; @@ -2810,7 +2941,7 @@ {ADDRESS_HOME_COUNTRY}); form.fields.push_back(checkable_field); - form_structure.reset(new FormStructure(form)); + form_structure = std::make_unique<FormStructure>(form); form_structure->set_password_attributes_vote( std::make_pair(PasswordAttribute::kHasNumeric, true)); form_structure->set_password_length_vote(10u); @@ -2842,7 +2973,7 @@ upload.set_submission(true); upload.set_submission_event(AutofillUploadContents::HTML_FORM_SUBMISSION); upload.set_client_version("6.1.1715.1442/en (GGLL)"); - upload.set_form_signature(8736493185895608956U); + upload.set_form_signature(form_structure->form_signature()); upload.set_autofill_used(false); upload.set_data_present("144200030e"); upload.set_passwords_revealed(false); @@ -2895,7 +3026,7 @@ ADDRESS_BILLING_LINE2}); } - form_structure.reset(new FormStructure(form)); + form_structure = std::make_unique<FormStructure>(form); form_structure->set_password_attributes_vote( std::make_pair(PasswordAttribute::kHasNumeric, true)); form_structure->set_password_length_vote(10u); @@ -2911,7 +3042,7 @@ } // Adjust the expected proto string. - upload.set_form_signature(7816485729218079147U); + upload.set_form_signature(form_structure->form_signature()); upload.set_autofill_used(false); upload.set_submission_event( AutofillUploadContents_SubmissionIndicatorEvent_HTML_FORM_SUBMISSION); @@ -2947,7 +3078,7 @@ {ADDRESS_HOME_LINE1, ADDRESS_HOME_LINE2, ADDRESS_BILLING_LINE1, ADDRESS_BILLING_LINE2}); } - form_structure.reset(new FormStructure(form)); + form_structure = std::make_unique<FormStructure>(form); ASSERT_EQ(form_structure->field_count(), possible_field_types.size()); ASSERT_EQ(form_structure->field_count(), possible_field_types_validities.size()); @@ -2968,7 +3099,9 @@ std::vector<ServerFieldTypeSet> possible_field_types; std::vector<ServerFieldTypeValidityStatesMap> possible_field_types_validities; FormData form; - form_structure.reset(new FormStructure(form)); + form.origin = GURL("http://www.foo.com/"); + + form_structure = std::make_unique<FormStructure>(form); form_structure->DetermineHeuristicTypes(); FormFieldData field; @@ -3004,7 +3137,7 @@ test::InitializePossibleTypesAndValidities(possible_field_types, possible_field_types_validities, {ACCOUNT_CREATION_PASSWORD}); - form_structure.reset(new FormStructure(form)); + form_structure = std::make_unique<FormStructure>(form); ASSERT_EQ(form_structure->field_count(), possible_field_types.size()); ASSERT_EQ(form_structure->field_count(), @@ -3038,7 +3171,7 @@ AutofillUploadContents upload; upload.set_submission(true); upload.set_client_version("6.1.1715.1442/en (GGLL)"); - upload.set_form_signature(5810032074788446513U); + upload.set_form_signature(form_structure->form_signature()); upload.set_autofill_used(true); upload.set_data_present("1440000000000000000802"); upload.set_action_signature(15724779818122431245U); @@ -3090,7 +3223,9 @@ std::vector<ServerFieldTypeSet> possible_field_types; std::vector<ServerFieldTypeValidityStatesMap> possible_field_types_validities; FormData form; - form_structure.reset(new FormStructure(form)); + form.origin = GURL("http://www.foo.com/"); + + form_structure = std::make_unique<FormStructure>(form); form_structure->DetermineHeuristicTypes(); FormFieldData field; @@ -3115,7 +3250,7 @@ form.fields.push_back(field); test::InitializePossibleTypesAndValidities( possible_field_types, possible_field_types_validities, {EMAIL_ADDRESS}); - form_structure.reset(new FormStructure(form)); + form_structure = std::make_unique<FormStructure>(form); ASSERT_EQ(form_structure->field_count(), possible_field_types.size()); ASSERT_EQ(form_structure->field_count(), @@ -3136,7 +3271,7 @@ AutofillUploadContents upload; upload.set_submission(true); upload.set_client_version("6.1.1715.1442/en (GGLL)"); - upload.set_form_signature(14746822798145140279U); + upload.set_form_signature(form_structure->form_signature()); upload.set_autofill_used(true); upload.set_data_present("1440"); upload.set_action_signature(15724779818122431245U); @@ -3170,7 +3305,9 @@ std::vector<ServerFieldTypeSet> possible_field_types; std::vector<ServerFieldTypeValidityStatesMap> possible_field_types_validities; FormData form; - form_structure.reset(new FormStructure(form)); + form.origin = GURL("http://www.foo.com/"); + + form_structure = std::make_unique<FormStructure>(form); form_structure->DetermineHeuristicTypes(); FormFieldData field; @@ -3206,7 +3343,7 @@ form.fields.push_back(field); test::InitializePossibleTypesAndValidities( possible_field_types, possible_field_types_validities, {EMAIL_ADDRESS}); - form_structure.reset(new FormStructure(form)); + form_structure = std::make_unique<FormStructure>(form); ASSERT_EQ(form_structure->field_count(), possible_field_types.size()); ASSERT_EQ(form_structure->field_count(), @@ -3227,7 +3364,7 @@ AutofillUploadContents upload; upload.set_submission(true); upload.set_client_version("6.1.1715.1442/en (GGLL)"); - upload.set_form_signature(14746822798145140279U); + upload.set_form_signature(form_structure->form_signature()); upload.set_autofill_used(true); upload.set_data_present("1440"); upload.set_passwords_revealed(false); @@ -3263,7 +3400,9 @@ std::vector<ServerFieldTypeSet> possible_field_types; std::vector<ServerFieldTypeValidityStatesMap> possible_field_types_validities; FormData form; - form_structure.reset(new FormStructure(form)); + form.origin = GURL("http://www.foo.com/"); + + form_structure = std::make_unique<FormStructure>(form); form_structure->DetermineHeuristicTypes(); FormFieldData field; @@ -3285,7 +3424,7 @@ form.fields.push_back(field); test::InitializePossibleTypesAndValidities( possible_field_types, possible_field_types_validities, {EMAIL_ADDRESS}); - form_structure.reset(new FormStructure(form)); + form_structure = std::make_unique<FormStructure>(form); ASSERT_EQ(form_structure->field_count(), possible_field_types.size()); ASSERT_EQ(form_structure->field_count(), @@ -3306,7 +3445,7 @@ AutofillUploadContents upload; upload.set_submission(false); upload.set_client_version("6.1.1715.1442/en (GGLL)"); - upload.set_form_signature(14746822798145140279U); + upload.set_form_signature(form_structure->form_signature()); upload.set_autofill_used(true); upload.set_data_present("1440"); upload.set_action_signature(15724779818122431245U); @@ -3339,7 +3478,9 @@ std::vector<ServerFieldTypeSet> possible_field_types; std::vector<ServerFieldTypeValidityStatesMap> possible_field_types_validities; FormData form; - form_structure.reset(new FormStructure(form)); + form.origin = GURL("http://www.foo.com/"); + + form_structure = std::make_unique<FormStructure>(form); form_structure->DetermineHeuristicTypes(); FormFieldData field; @@ -3357,7 +3498,7 @@ form.fields.push_back(field); test::InitializePossibleTypesAndValidities( possible_field_types, possible_field_types_validities, {EMAIL_ADDRESS}); - form_structure.reset(new FormStructure(form)); + form_structure = std::make_unique<FormStructure>(form); ASSERT_EQ(form_structure->field_count(), possible_field_types.size()); ASSERT_EQ(form_structure->field_count(), @@ -3378,7 +3519,7 @@ AutofillUploadContents upload; upload.set_submission(true); upload.set_client_version("6.1.1715.1442/en (GGLL)"); - upload.set_form_signature(6949133589768631292U); + upload.set_form_signature(form_structure->form_signature()); upload.set_autofill_used(true); upload.set_data_present("1440"); upload.set_action_signature(15724779818122431245U); @@ -3409,6 +3550,7 @@ std::vector<ServerFieldTypeSet> possible_field_types; std::vector<ServerFieldTypeValidityStatesMap> possible_field_types_validities; FormData form; + form.origin = GURL("http://www.foo.com/"); FormFieldData field; field.form_control_type = "text"; @@ -3447,7 +3589,7 @@ AutofillUploadContents upload; upload.set_submission(true); upload.set_client_version("6.1.1715.1442/en (GGLL)"); - upload.set_form_signature(6949133589768631292U); + upload.set_form_signature(form_structure->form_signature()); upload.set_autofill_used(true); upload.set_data_present("1440"); upload.set_action_signature(15724779818122431245U); @@ -3488,9 +3630,11 @@ std::vector<ServerFieldTypeSet> possible_field_types; std::vector<ServerFieldTypeValidityStatesMap> possible_field_types_validities; FormData form; + form.origin = GURL("http://www.foo.com/"); + // Setting the form name which we expect to see in the upload. form.name = ASCIIToUTF16("myform"); - form_structure.reset(new FormStructure(form)); + form_structure = std::make_unique<FormStructure>(form); form_structure->DetermineHeuristicTypes(); FormFieldData field; @@ -3506,7 +3650,7 @@ test::InitializePossibleTypesAndValidities( possible_field_types, possible_field_types_validities, {EMAIL_ADDRESS}); - form_structure.reset(new FormStructure(form)); + form_structure = std::make_unique<FormStructure>(form); form_structure->set_submission_source(SubmissionSource::FRAME_DETACHED); ASSERT_EQ(form_structure->field_count(), possible_field_types.size()); @@ -3528,7 +3672,7 @@ AutofillUploadContents upload; upload.set_submission(true); upload.set_client_version("6.1.1715.1442/en (GGLL)"); - upload.set_form_signature(2345951786066580868U); + upload.set_form_signature(form_structure->form_signature()); upload.set_autofill_used(true); upload.set_data_present("1440"); upload.set_action_signature(15724779818122431245U); @@ -3561,7 +3705,9 @@ std::vector<ServerFieldTypeSet> possible_field_types; std::vector<ServerFieldTypeValidityStatesMap> possible_field_types_validities; FormData form; - form_structure.reset(new FormStructure(form)); + form.origin = GURL("http://www.foo.com/"); + + form_structure = std::make_unique<FormStructure>(form); form_structure->DetermineHeuristicTypes(); FormFieldData field; @@ -3585,7 +3731,7 @@ form.fields.push_back(field); test::InitializePossibleTypesAndValidities( possible_field_types, possible_field_types_validities, {EMAIL_ADDRESS}); - form_structure.reset(new FormStructure(form)); + form_structure = std::make_unique<FormStructure>(form); ASSERT_EQ(form_structure->field_count(), possible_field_types.size()); ASSERT_EQ(form_structure->field_count(), @@ -3606,7 +3752,7 @@ AutofillUploadContents upload; upload.set_submission(true); upload.set_client_version("6.1.1715.1442/en (GGLL)"); - upload.set_form_signature(13043654279838250996U); + upload.set_form_signature(form_structure->form_signature()); upload.set_autofill_used(true); upload.set_data_present("1440"); upload.set_passwords_revealed(false); @@ -3641,7 +3787,9 @@ std::vector<ServerFieldTypeSet> possible_field_types; std::vector<ServerFieldTypeValidityStatesMap> possible_field_types_validities; FormData form; - form_structure.reset(new FormStructure(form)); + form.origin = GURL("http://www.foo.com/"); + + form_structure = std::make_unique<FormStructure>(form); form_structure->DetermineHeuristicTypes(); FormFieldData field; @@ -3672,7 +3820,7 @@ form.fields.push_back(field); test::InitializePossibleTypesAndValidities( possible_field_types, possible_field_types_validities, {EMAIL_ADDRESS}); - form_structure.reset(new FormStructure(form)); + form_structure = std::make_unique<FormStructure>(form); ASSERT_EQ(form_structure->field_count(), possible_field_types.size()); ASSERT_EQ(form_structure->field_count(), @@ -3693,7 +3841,7 @@ AutofillUploadContents upload; upload.set_submission(true); upload.set_client_version("6.1.1715.1442/en (GGLL)"); - upload.set_form_signature(14746822798145140279U); + upload.set_form_signature(form_structure->form_signature()); upload.set_autofill_used(true); upload.set_data_present("1440"); upload.set_passwords_revealed(false); @@ -3723,6 +3871,7 @@ // |available_types|. TEST_F(FormStructureTest, CheckDataPresence) { FormData form; + form.origin = GURL("http://www.foo.com/"); FormFieldData field; field.form_control_type = "text"; @@ -3762,7 +3911,7 @@ AutofillUploadContents upload; upload.set_submission(true); upload.set_client_version("6.1.1715.1442/en (GGLL)"); - upload.set_form_signature(6402244543831589061U); + upload.set_form_signature(form_structure.form_signature()); upload.set_autofill_used(false); upload.set_data_present(""); upload.set_passwords_revealed(false); @@ -3997,6 +4146,7 @@ std::vector<ServerFieldTypeSet> possible_field_types; std::vector<ServerFieldTypeValidityStatesMap> possible_field_types_validities; FormData form; + form.origin = GURL("http://www.foo.com/"); FormFieldData field; field.form_control_type = "text"; @@ -4026,7 +4176,7 @@ possible_field_types_validities, {ADDRESS_HOME_LINE1}); - form_structure.reset(new FormStructure(form)); + form_structure = std::make_unique<FormStructure>(form); form_structure->set_submission_source(SubmissionSource::XHR_SUCCEEDED); for (size_t i = 0; i < form_structure->field_count(); ++i) { form_structure->field(i)->set_possible_types(possible_field_types[i]); @@ -4038,7 +4188,7 @@ AutofillUploadContents upload; upload.set_submission(true); upload.set_client_version("6.1.1715.1442/en (GGLL)"); - upload.set_form_signature(18062476096658145866U); + upload.set_form_signature(form_structure->form_signature()); upload.set_autofill_used(false); upload.set_data_present("1440000360000008"); upload.set_passwords_revealed(false); @@ -4133,6 +4283,8 @@ TEST_F(FormStructureTest, EncodeUploadRequest_PasswordsRevealed) { FormData form; + form.origin = GURL("http://www.foo.com/"); + // Add 3 fields, to make the form uploadable. FormFieldData field; field.name = ASCIIToUTF16("email"); @@ -4175,25 +4327,25 @@ field.check_status = FormFieldData::CHECKABLE_BUT_UNCHECKED; form.fields.push_back(field); - form_structure.reset(new FormStructure(form)); + form_structure = std::make_unique<FormStructure>(form); EXPECT_EQ(FormStructureTest::Hash64Bit(std::string("://&&email&first")), form_structure->FormSignatureAsStr()); form.origin = GURL(std::string("http://www.facebook.com")); - form_structure.reset(new FormStructure(form)); + form_structure = std::make_unique<FormStructure>(form); EXPECT_EQ(FormStructureTest::Hash64Bit( std::string("http://www.facebook.com&&email&first")), form_structure->FormSignatureAsStr()); form.action = GURL(std::string("https://login.facebook.com/path")); - form_structure.reset(new FormStructure(form)); + form_structure = std::make_unique<FormStructure>(form); EXPECT_EQ(FormStructureTest::Hash64Bit( std::string("https://login.facebook.com&&email&first")), form_structure->FormSignatureAsStr()); form.name = ASCIIToUTF16("login_form"); - form_structure.reset(new FormStructure(form)); + form_structure = std::make_unique<FormStructure>(form); EXPECT_EQ(FormStructureTest::Hash64Bit(std::string( "https://login.facebook.com&login_form&email&first")), form_structure->FormSignatureAsStr()); @@ -4213,7 +4365,7 @@ field.label = ASCIIToUTF16("Random Field label3"); field.name = ASCIIToUTF16("12345ran123456dom123"); form.fields.push_back(field); - form_structure.reset(new FormStructure(form)); + form_structure = std::make_unique<FormStructure>(form); EXPECT_EQ(FormStructureTest::Hash64Bit( std::string("https://login.facebook.com&login_form&email&first&" "random1234&random&1ran12dom&random123")), @@ -4279,7 +4431,7 @@ AutofillQueryContents query; query.set_client_version("6.1.1715.1442/en (GGLL)"); AutofillQueryContents::Form* query_form = query.add_form(); - query_form->set_signature(18006745212084723782U); + query_form->set_signature(form_structure.form_signature()); test::FillQueryField(query_form->add_field(), 239111655U, "username", "text"); test::FillQueryField(query_form->add_field(), 420638584U, "email", "text"); @@ -4331,7 +4483,7 @@ AutofillQueryContents query; query.set_client_version("6.1.1715.1442/en (GGLL)"); AutofillQueryContents::Form* query_form = query.add_form(); - query_form->set_signature(13906559713264665730U); + query_form->set_signature(form_structure.form_signature()); test::FillQueryField(query_form->add_field(), 239111655U, "username", "text"); test::FillQueryField(query_form->add_field(), 420638584U, "email", "text"); @@ -4386,7 +4538,7 @@ AutofillQueryContents query; query.set_client_version("6.1.1715.1442/en (GGLL)"); AutofillQueryContents::Form* query_form = query.add_form(); - query_form->set_signature(13906559713264665730U); + query_form->set_signature(form_structure.form_signature()); test::FillQueryField(query_form->add_field(), 239111655U, "username", "text"); test::FillQueryField(query_form->add_field(), 420638584U, "email", "text"); @@ -4435,7 +4587,7 @@ AutofillQueryContents query; query.set_client_version("6.1.1715.1442/en (GGLL)"); AutofillQueryContents::Form* query_form = query.add_form(); - query_form->set_signature(16416961345885087496U); + query_form->set_signature(form_structure.form_signature()); test::FillQueryField(query_form->add_field(), 239111655U, "username", "text"); test::FillQueryField(query_form->add_field(), 1318412689U, nullptr, "text"); @@ -4486,7 +4638,7 @@ AutofillQueryContents query; query.set_client_version("6.1.1715.1442/en (GGLL)"); AutofillQueryContents::Form* query_form = query.add_form(); - query_form->set_signature(7635954436925888745U); + query_form->set_signature(form_structure.form_signature()); test::FillQueryField(query_form->add_field(), 239111655U, nullptr, nullptr); test::FillQueryField(query_form->add_field(), 3654076265U, nullptr, nullptr); @@ -4508,6 +4660,8 @@ TEST_F(FormStructureTest, PossibleValues) { FormData form_data; + form_data.origin = GURL("http://www.foo.com/"); + FormFieldData field; field.autocomplete_attribute = "billing country"; field.option_contents.push_back(ASCIIToUTF16("Down Under"));
diff --git a/components/autofill/core/browser/randomized_encoder.cc b/components/autofill/core/browser/randomized_encoder.cc new file mode 100644 index 0000000..13c9f58 --- /dev/null +++ b/components/autofill/core/browser/randomized_encoder.cc
@@ -0,0 +1,210 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "components/autofill/core/browser/randomized_encoder.h" + +#include <algorithm> +#include <limits> + +#include "base/format_macros.h" +#include "base/numerics/safe_conversions.h" +#include "base/stl_util.h" +#include "base/strings/stringprintf.h" +#include "crypto/hkdf.h" + +namespace autofill { + +struct RandomizedEncoder::EncodingInfo { + AutofillRandomizedValue_EncodingType encoding_type; + size_t final_size; + size_t bit_offset; + size_t bit_stride; +}; + +namespace { + +const RandomizedEncoder::EncodingInfo kEncodingInfo[] = { + // One bit per byte. These all require 8 bytes to encode and have 8-bit + // strides, starting from a different initial bit offset. + {AutofillRandomizedValue_EncodingType_BIT_0, 8, 0, 8}, + {AutofillRandomizedValue_EncodingType_BIT_1, 8, 1, 8}, + {AutofillRandomizedValue_EncodingType_BIT_2, 8, 2, 8}, + {AutofillRandomizedValue_EncodingType_BIT_3, 8, 3, 8}, + {AutofillRandomizedValue_EncodingType_BIT_4, 8, 4, 8}, + {AutofillRandomizedValue_EncodingType_BIT_5, 8, 5, 8}, + {AutofillRandomizedValue_EncodingType_BIT_6, 8, 6, 8}, + {AutofillRandomizedValue_EncodingType_BIT_7, 8, 7, 8}, + + // Four bits per byte. These require 32 bytes to encode and have 2-bit + // strides/ + {AutofillRandomizedValue_EncodingType_EVEN_BITS, 32, 0, 2}, + {AutofillRandomizedValue_EncodingType_ODD_BITS, 32, 1, 2}, + + // All bits per byte. This require 64 bytes to encode and has a 1-bit + // stride. + {AutofillRandomizedValue_EncodingType_ALL_BITS, 64, 0, 1}, +}; + +// Size related constants. +constexpr size_t kBitsPerByte = 8; +constexpr size_t kMaxEncodedLengthInBytes = 64; +constexpr size_t kMaxEncodedLengthInBits = + kMaxEncodedLengthInBytes * kBitsPerByte; + +// Find the EncodingInfo struct for |encoding_type|, else return nullptr. +const RandomizedEncoder::EncodingInfo* GetEncodingInfo( + AutofillRandomizedValue_EncodingType encoding_type) { + DCHECK(std::is_sorted(std::begin(kEncodingInfo), std::end(kEncodingInfo), + [](const RandomizedEncoder::EncodingInfo& lhs, + const RandomizedEncoder::EncodingInfo& rhs) { + return lhs.encoding_type < rhs.encoding_type; + })); + + const auto* encode_info = std::lower_bound( + std::begin(kEncodingInfo), std::end(kEncodingInfo), encoding_type, + [](const RandomizedEncoder::EncodingInfo& lhs, + AutofillRandomizedValue_EncodingType encoding_type) { + return lhs.encoding_type < encoding_type; + }); + + return (encode_info != std::end(kEncodingInfo) && + encode_info->encoding_type == encoding_type) + ? encode_info + : nullptr; +} + +// Get the |i|-th bit of |s| where |i| counts up from the 0-bit of the first +// character in |s|. It is expected that the caller guarantees that |i| is a +// valid bit-offset into |s| +inline uint8_t GetBit(base::StringPiece s, size_t i) { + DCHECK_LT(i / kBitsPerByte, s.length()); + return static_cast<bool>((s[i / kBitsPerByte]) & (1 << (i % kBitsPerByte))); +} + +// Set the |i|-th bit of |s| where |i| counts up from the 0-bit of the first +// character in |s|. It is expected that the caller guarantees that |i| is a +// valid bit-offset into |s|. +inline void SetBit(size_t i, uint8_t bit_value, std::string* s) { + DCHECK(bit_value == 0u || bit_value == 1u); + DCHECK(s); + DCHECK_LT(i / kBitsPerByte, s->length()); + + // Clear the target bit value. + (*s)[i / kBitsPerByte] &= ~(1 << (i % kBitsPerByte)); + + // Set the target bit to the input bit-value. + (*s)[i / kBitsPerByte] |= (bit_value << (i % kBitsPerByte)); +} +// Returns a pseudo-random value of length |kMaxEncodedLengthInBytes| that is +// derived from |secret|, |purpose|, |form_signature|, |field_signature| and +// |data_type|. +std::string GetPseudoRandomBits(base::StringPiece secret, + base::StringPiece purpose, + FormSignature form_signature, + FieldSignature field_signature, + base::StringPiece data_type) { + // The purpose and data_type strings are expect to be small semantic + // identifiers: "noise", "coins", "css_class", "html-name", "html_id", etc. + int purpose_length = base::checked_cast<int>(purpose.length()); + int data_type_length = base::checked_cast<int>(data_type.length()); + + // Join the descriptive information about the encoding about to be performed. + std::string info = + base::StringPrintf("%d:%.*s;%08" PRIx64 ";%08" PRIx64 ";%d:%.*s", + purpose_length, purpose_length, purpose.data(), + form_signature, static_cast<uint64_t>(field_signature), + data_type_length, data_type_length, data_type.data()); + + DVLOG(1) << "Generating pseudo-random bits from " << info; + + // Generate the pseudo-random bits. + return crypto::HkdfSha256(secret, {}, info, kMaxEncodedLengthInBytes); +} + +} // namespace + +RandomizedEncoder::RandomizedEncoder( + std::string seed, + AutofillRandomizedValue_EncodingType encoding_type) + : seed_(std::move(seed)), encoding_info_(GetEncodingInfo(encoding_type)) { + DCHECK(encoding_info_ != nullptr); +} + +std::string RandomizedEncoder::Encode(FormSignature form_signature, + FieldSignature field_signature, + base::StringPiece data_type, + base::StringPiece data_value) const { + if (!encoding_info_) { + NOTREACHED(); + return std::string(); + } + + std::string coins = GetCoins(form_signature, field_signature, data_type); + std::string noise = GetNoise(form_signature, field_signature, data_type); + + DCHECK_EQ(kMaxEncodedLengthInBytes, coins.length()); + DCHECK_EQ(kMaxEncodedLengthInBytes, noise.length()); + + // If we're encoding the bits encoding we can simply repurpose the noise + // vector and use the coins vector merge in the selected data value bits. + // For each bit, the encoded value is the true value if the coin-toss is TRUE + // or the noise value if the coin-toss is FALSE. All the bits in a given byte + // can be computed in parallel. The trailing bytes are all noise. + if (encoding_info_->encoding_type == + AutofillRandomizedValue_EncodingType_ALL_BITS) { + std::string all_bits = std::move(noise); + const size_t value_length = + std::min(data_value.length(), kMaxEncodedLengthInBytes); + for (size_t i = 0; i < value_length; ++i) { + // Initially this byte is all noise, we're replacing the bits for which + // the coin toss is 1 with the corresponding data_value bits, and keeping + // the noise bits where the coin toss is 0. + all_bits[i] = (data_value[i] & coins[i]) | (all_bits[i] & ~coins[i]); + } + return all_bits; + } + + // Otherwise, pack the select the subset of bits into an output buffer. + // This encodes every |encoding_info_->bit_stride| bit starting from + // |encoding_info_->bit_offset|. + // + // For each bit, the encoded value is the true value if the coin-toss is TRUE + // or the noise value if the coin-toss is FALSE. All the bits in a given byte + // can be computed in parallel. The trailing bytes are all noise. + std::string output(encoding_info_->final_size, 0); + const size_t value_length_in_bits = data_value.length() * kBitsPerByte; + size_t dst_offset = 0; + size_t src_offset = encoding_info_->bit_offset; + while (src_offset < kMaxEncodedLengthInBits) { + uint8_t output_bit = GetBit(noise, src_offset); + if (src_offset < value_length_in_bits) { + const uint8_t coin_bit = GetBit(coins, src_offset); + const uint8_t data_bit = GetBit(data_value, src_offset); + output_bit = ((coin_bit & data_bit) | (~coin_bit & output_bit)); + } + SetBit(dst_offset, output_bit, &output); + src_offset += encoding_info_->bit_stride; + dst_offset += 1; + } + + DCHECK_EQ(dst_offset, encoding_info_->final_size * kBitsPerByte); + return output; +} + +std::string RandomizedEncoder::GetCoins(FormSignature form_signature, + FieldSignature field_signature, + base::StringPiece data_type) const { + return GetPseudoRandomBits(seed_, "coins", form_signature, field_signature, + data_type); +} + +// Get the pseudo-random string to use at the noise bit-field. +std::string RandomizedEncoder::GetNoise(FormSignature form_signature, + FieldSignature field_signature, + base::StringPiece data_type) const { + return GetPseudoRandomBits(seed_, "noise", form_signature, field_signature, + data_type); +} + +} // namespace autofill
diff --git a/components/autofill/core/browser/randomized_encoder.h b/components/autofill/core/browser/randomized_encoder.h new file mode 100644 index 0000000..0a4979b --- /dev/null +++ b/components/autofill/core/browser/randomized_encoder.h
@@ -0,0 +1,50 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef COMPONENTS_AUTOFILL_CORE_BROWSER_RANDOMIZED_ENCODER_H_ +#define COMPONENTS_AUTOFILL_CORE_BROWSER_RANDOMIZED_ENCODER_H_ + +#include <string> + +#include "base/strings/string_piece.h" +#include "components/autofill/core/browser/proto/server.pb.h" +#include "components/autofill/core/common/signatures_util.h" + +namespace autofill { + +// Encodes string values using the differential-privacy scheme as described +// in go/autofill-metadata-upload (Google internal link). +class RandomizedEncoder { + public: + struct EncodingInfo; + + RandomizedEncoder(std::string seed, + AutofillRandomizedValue_EncodingType encoding_type); + + // Encode |data_value| using this instance's |encoding_type_|. + std::string Encode(FormSignature form_signature, + FieldSignature field_signature, + base::StringPiece data_type, + base::StringPiece data_value) const; + + protected: + // Get the pseudo-random string to use at the coin bit-field. This function + // is internal, but exposed here to facilitate testing. + std::string GetCoins(FormSignature form_signature, + FieldSignature field_signature, + base::StringPiece data_type) const; + + // Get the pseudo-random string to use at the noise bit-field. This function + // is internal, but exposed here to facilitate testing. + std::string GetNoise(FormSignature form_signature, + FieldSignature field_signature, + base::StringPiece data_type) const; + + private: + const std::string seed_; + const EncodingInfo* const encoding_info_; +}; +} // namespace autofill + +#endif // COMPONENTS_AUTOFILL_CORE_BROWSER_RANDOMIZED_ENCODER_H_
diff --git a/components/autofill/core/browser/randomized_encoder_unittest.cc b/components/autofill/core/browser/randomized_encoder_unittest.cc new file mode 100644 index 0000000..dcbc1e5 --- /dev/null +++ b/components/autofill/core/browser/randomized_encoder_unittest.cc
@@ -0,0 +1,164 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "components/autofill/core/browser/randomized_encoder.h" + +#include "base/time/time.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace { + +constexpr size_t kBitsPerByte = 8; +constexpr size_t kMaxLengthInBytes = 64; +constexpr size_t kMaxLengthInBits = kMaxLengthInBytes * kBitsPerByte; + +// Get the |i|-th bit of |s| where |i| counts up from the 0-bit of the first +// character in |s|. It is expected that the caller guarantees that |i| is a +// valid bit-offset into |s| +bool GetBit(base::StringPiece s, size_t i) { + DCHECK_LT(i / kBitsPerByte, s.length()); + return static_cast<bool>((s[i / kBitsPerByte]) & (1 << (i % kBitsPerByte))); +} + +// This is a reference encoder implementation. This implementation performs the +// all bits encoding one full byte at a time and then packs the selected bits +// into a final output buffer. +std::string ReferenceEncodeImpl(base::StringPiece coins, + base::StringPiece noise, + base::StringPiece value, + size_t bit_offset, + size_t bit_stride) { + // Encode all of the bits. + std::string all_bits = noise.as_string(); + size_t value_length = std::min(value.length(), kMaxLengthInBytes); + for (size_t i = 0; i < value_length; ++i) { + all_bits[i] = (value[i] & coins[i]) | (all_bits[i] & ~coins[i]); + } + + // Select the only the ones matching bit_offset and bit_stride. + std::string output(kMaxLengthInBytes / bit_stride, 0); + size_t src_offset = bit_offset; + size_t dst_offset = 0; + while (src_offset < kMaxLengthInBits) { + bool bit_value = GetBit(all_bits, src_offset); + output[dst_offset / kBitsPerByte] |= + (bit_value << (dst_offset % kBitsPerByte)); + src_offset += bit_stride; + dst_offset += 1; + } + return output; +} + +// A test version of the RandomizedEncoder class. Exposes "ForTest" methods. +class TestRandomizedEncoder : public autofill::RandomizedEncoder { + public: + using RandomizedEncoder::RandomizedEncoder; + using RandomizedEncoder::GetCoins; + using RandomizedEncoder::GetNoise; +}; + +// Data structure used to drive the encoding test cases. +struct EncodeParams { + // The type of encoding to perform with the RandomizedEncoder. + autofill::AutofillRandomizedValue_EncodingType encoding_type; + + // The bit offset to start from with the reference encoder. + size_t bit_offset; + + // The bit stride to select the next bit to encode with the reference encoder. + size_t bit_stride; +}; + +// A table to test cases, mapping encoding scheme to the reference encoder. +const EncodeParams kEncodeParams[] = { + // One bit per byte. These all require 8 bytes to encode and have 8-bit + // strides, starting from a different initial bit offset. + {autofill::AutofillRandomizedValue_EncodingType_BIT_0, 0, 8}, + {autofill::AutofillRandomizedValue_EncodingType_BIT_1, 1, 8}, + {autofill::AutofillRandomizedValue_EncodingType_BIT_2, 2, 8}, + {autofill::AutofillRandomizedValue_EncodingType_BIT_3, 3, 8}, + {autofill::AutofillRandomizedValue_EncodingType_BIT_4, 4, 8}, + {autofill::AutofillRandomizedValue_EncodingType_BIT_5, 5, 8}, + {autofill::AutofillRandomizedValue_EncodingType_BIT_6, 6, 8}, + {autofill::AutofillRandomizedValue_EncodingType_BIT_7, 7, 8}, + + // Four bits per byte. These require 32 bytes to encode and have 2-bit + // strides/ + {autofill::AutofillRandomizedValue_EncodingType_EVEN_BITS, 0, 2}, + {autofill::AutofillRandomizedValue_EncodingType_ODD_BITS, 1, 2}, + + // All bits per byte. This require 64 bytes to encode and has a 1-bit + // stride. + {autofill::AutofillRandomizedValue_EncodingType_ALL_BITS, 0u, 1}, +}; + +using RandomizedEncoderTest = ::testing::TestWithParam<EncodeParams>; + +} // namespace + +TEST_P(RandomizedEncoderTest, Encode) { + const autofill::FormSignature form_signature = 0x1234567812345678; + const autofill::FieldSignature field_signature = 0xCAFEBABE; + const std::string data_type = "css_class"; + const EncodeParams& params = GetParam(); + const std::string value("This is some text for testing purposes."); + + EXPECT_LT(value.length(), kMaxLengthInBytes); + + TestRandomizedEncoder encoder("this is a secret", params.encoding_type); + + // Encode the output string. + std::string actual_result = + encoder.Encode(form_signature, field_signature, data_type, value); + + // Capture the coin and noise bits used for the form, field and metadata type. + std::string coins = + encoder.GetCoins(form_signature, field_signature, data_type); + std::string noise = + encoder.GetNoise(form_signature, field_signature, data_type); + + // Use the reference encoder implementation to get the expected output. + std::string expected_result = ReferenceEncodeImpl( + coins, noise, value, params.bit_offset, params.bit_stride); + + // The results should be the same. + EXPECT_EQ(kMaxLengthInBytes / params.bit_stride, actual_result.length()); + EXPECT_EQ(expected_result, actual_result); +} + +TEST_P(RandomizedEncoderTest, EncodeLarge) { + const autofill::FormSignature form_signature = 0x8765432187654321; + const autofill::FieldSignature field_signature = 0xDEADBEEF; + const std::string data_type = "html_name"; + const EncodeParams& params = GetParam(); + const std::string value( + "This is some text for testing purposes. It exceeds the maximum encoding " + "size. This serves to validate that truncation is performed. Lots and " + " or text. Yay!"); + EXPECT_GT(value.length(), kMaxLengthInBytes); + + TestRandomizedEncoder encoder("this is a secret", params.encoding_type); + + // Encode the output string. + std::string actual_result = + encoder.Encode(form_signature, field_signature, data_type, value); + + // Capture the coin and noise bits used for the form, field and metadata type. + std::string coins = + encoder.GetCoins(form_signature, field_signature, data_type); + std::string noise = + encoder.GetNoise(form_signature, field_signature, data_type); + + // Use the reference encoder implementation to get the expected output. + std::string expected_result = ReferenceEncodeImpl( + coins, noise, value, params.bit_offset, params.bit_stride); + + // The results should be the same. + EXPECT_EQ(kMaxLengthInBytes / params.bit_stride, actual_result.length()); + EXPECT_EQ(expected_result, actual_result); +} + +INSTANTIATE_TEST_CASE_P(All, + RandomizedEncoderTest, + ::testing::ValuesIn(kEncodeParams));
diff --git a/components/autofill/core/common/autofill_features.cc b/components/autofill/core/common/autofill_features.cc index 5741b35..524658d 100644 --- a/components/autofill/core/common/autofill_features.cc +++ b/components/autofill/core/common/autofill_features.cc
@@ -21,6 +21,13 @@ namespace autofill { namespace features { +// Controls whether autofill activates on non-HTTP(S) pages. Useful for +// automated with data URLS in cases where it's too difficult to use the +// embedded test server. Generally avoid using. +// +const base::Feature kAutofillAllowNonHttpActivation{ + "AutofillAllowNonHttpActivation", base::FEATURE_DISABLED_BY_DEFAULT}; + // Controls whether the AddressNormalizer is supplied. If available, it may be // used to normalize address and will incur fetching rules from the server. const base::Feature kAutofillAddressNormalizer{ @@ -147,7 +154,7 @@ // Controls whether Autofill should rationalize repeated server type // predictions. const base::Feature kAutofillRationalizeRepeatedServerPredictions{ - "kAutofillRationalizeRepeatedServerPredictions", + "AutofillRationalizeRepeatedServerPredictions", base::FEATURE_ENABLED_BY_DEFAULT}; // Controls whether Full Server credit cards should be reset when the sync @@ -204,7 +211,7 @@ // "upload" resources. // i.e., https://other.autofill.server:port/tbproxy/af/ const base::Feature kAutofillServerCommunication{ - "kAutofillServerCommunication", base::FEATURE_ENABLED_BY_DEFAULT}; + "AutofillServerCommunication", base::FEATURE_ENABLED_BY_DEFAULT}; // Controls whether autofill suggestions are filtered by field values previously // filled by website.
diff --git a/components/autofill/core/common/autofill_features.h b/components/autofill/core/common/autofill_features.h index 589a2da..48400782 100644 --- a/components/autofill/core/common/autofill_features.h +++ b/components/autofill/core/common/autofill_features.h
@@ -21,6 +21,7 @@ namespace features { // All features in alphabetical order. +extern const base::Feature kAutofillAllowNonHttpActivation; extern const base::Feature kAutofillAddressNormalizer; extern const base::Feature kAutofillAlwaysFillAddresses; extern const base::Feature kAutofillCacheQueryResponses;
diff --git a/components/autofill_assistant/browser/controller.cc b/components/autofill_assistant/browser/controller.cc index c13bce3a..831c5dd 100644 --- a/components/autofill_assistant/browser/controller.cc +++ b/components/autofill_assistant/browser/controller.cc
@@ -281,6 +281,18 @@ } } + // Clear the status message or show the specified prompt. + std::string prompt; + for (const auto& script : runnable_scripts) { + // runnable_scripts is ordered by priority. + if (!script.initial_prompt.empty()) { + prompt = script.initial_prompt; + break; + } + } + GetUiController()->ShowStatusMessage(prompt); + + // Update the set of scripts. GetUiController()->UpdateScripts(runnable_scripts); }
diff --git a/components/autofill_assistant/browser/controller_unittest.cc b/components/autofill_assistant/browser/controller_unittest.cc index 345b240..c3619dc 100644 --- a/components/autofill_assistant/browser/controller_unittest.cc +++ b/components/autofill_assistant/browser/controller_unittest.cc
@@ -187,6 +187,35 @@ SimulateNavigateToUrl(GURL("http://a.example.com/path")); } +TEST_F(ControllerTest, ShowFirstInitialPrompt) { + SupportsScriptResponseProto script_response; + AddRunnableScript(&script_response, "script1"); + + SupportedScriptProto* script2 = + AddRunnableScript(&script_response, "script2"); + script2->mutable_presentation()->set_initial_prompt("script2 prompt"); + script2->mutable_presentation()->set_priority(10); + + SupportedScriptProto* script3 = + AddRunnableScript(&script_response, "script3"); + script3->mutable_presentation()->set_initial_prompt("script3 prompt"); + script3->mutable_presentation()->set_priority(5); + + SupportedScriptProto* script4 = + AddRunnableScript(&script_response, "script4"); + script4->mutable_presentation()->set_initial_prompt("script4 prompt"); + script4->mutable_presentation()->set_priority(8); + + SetNextScriptResponse(script_response); + + // Script3, with higher priority (lower number), wins. + EXPECT_CALL(*mock_ui_controller_, ShowStatusMessage("script3 prompt")); + EXPECT_CALL(*mock_ui_controller_, UpdateScripts(SizeIs(4))); + + // Start the flow. + SimulateNavigateToUrl(GURL("http://a.example.com/path")); +} + TEST_F(ControllerTest, Stop) { ActionsResponseProto actions_response; actions_response.add_actions()->mutable_stop();
diff --git a/components/autofill_assistant/browser/protocol_utils.cc b/components/autofill_assistant/browser/protocol_utils.cc index 975a4dd3..1b2935b 100644 --- a/components/autofill_assistant/browser/protocol_utils.cc +++ b/components/autofill_assistant/browser/protocol_utils.cc
@@ -80,6 +80,7 @@ const auto& presentation = script_proto.presentation(); script->handle.name = presentation.name(); script->handle.autostart = presentation.autostart(); + script->handle.initial_prompt = presentation.initial_prompt(); script->precondition = ScriptPrecondition::FromProto( script_proto.path(), presentation.precondition()); script->priority = presentation.priority();
diff --git a/components/autofill_assistant/browser/protocol_utils_unittest.cc b/components/autofill_assistant/browser/protocol_utils_unittest.cc index 605e77a..ea5d526 100644 --- a/components/autofill_assistant/browser/protocol_utils_unittest.cc +++ b/components/autofill_assistant/browser/protocol_utils_unittest.cc
@@ -52,6 +52,7 @@ auto* presentation = script->mutable_presentation(); presentation->set_name("name"); presentation->set_autostart(true); + presentation->set_initial_prompt("prompt"); presentation->mutable_precondition()->add_domain("www.example.com"); std::vector<std::unique_ptr<Script>> scripts; @@ -61,6 +62,7 @@ ASSERT_THAT(scripts, SizeIs(1)); EXPECT_EQ("path", scripts[0]->handle.path); EXPECT_EQ("name", scripts[0]->handle.name); + EXPECT_EQ("prompt", scripts[0]->handle.initial_prompt); EXPECT_TRUE(scripts[0]->handle.autostart); EXPECT_NE(nullptr, scripts[0]->precondition); }
diff --git a/components/autofill_assistant/browser/script.cc b/components/autofill_assistant/browser/script.cc index 62ec03f..1efb8fe 100644 --- a/components/autofill_assistant/browser/script.cc +++ b/components/autofill_assistant/browser/script.cc
@@ -8,6 +8,8 @@ ScriptHandle::ScriptHandle() : autostart(false) {} +ScriptHandle::ScriptHandle(const ScriptHandle& orig) = default; + ScriptHandle::~ScriptHandle() = default; Script::Script() : priority(0) {}
diff --git a/components/autofill_assistant/browser/script.h b/components/autofill_assistant/browser/script.h index a446f6b..0a0779b 100644 --- a/components/autofill_assistant/browser/script.h +++ b/components/autofill_assistant/browser/script.h
@@ -15,10 +15,12 @@ // Minimal information about a script necessary to display and run it. struct ScriptHandle { ScriptHandle(); + ScriptHandle(const ScriptHandle& orig); ~ScriptHandle(); std::string name; std::string path; + std::string initial_prompt; // When set to true this script can be run in 'autostart mode'. Script won't // be shown.
diff --git a/components/autofill_assistant/browser/script_precondition.cc b/components/autofill_assistant/browser/script_precondition.cc index 68948ea8..b9f3430b 100644 --- a/components/autofill_assistant/browser/script_precondition.cc +++ b/components/autofill_assistant/browser/script_precondition.cc
@@ -121,7 +121,9 @@ return true; } - const std::string path = url.path(); + std::string path = url.has_ref() + ? base::StrCat({url.PathForRequest(), "#", url.ref()}) + : url.PathForRequest(); for (auto& regexp : path_pattern_) { if (regexp->Match(path, 0, path.size(), re2::RE2::UNANCHORED, NULL, 0)) { return true;
diff --git a/components/autofill_assistant/browser/script_precondition_unittest.cc b/components/autofill_assistant/browser/script_precondition_unittest.cc index bc9da25..27e11513 100644 --- a/components/autofill_assistant/browser/script_precondition_unittest.cc +++ b/components/autofill_assistant/browser/script_precondition_unittest.cc
@@ -157,6 +157,17 @@ EXPECT_TRUE(Check(proto)); } +TEST_F(ScriptPreconditionTest, PathWithQueryAndRef) { + ScriptPreconditionProto proto; + proto.add_path_pattern("/hello.*world"); + + SetUrl("http://www.example.com/hello?q=world"); + EXPECT_TRUE(Check(proto)); + + SetUrl("http://www.example.com/hello#world"); + EXPECT_TRUE(Check(proto)); +} + TEST_F(ScriptPreconditionTest, BadPathPattern) { ScriptPreconditionProto proto; proto.add_path_pattern("invalid[");
diff --git a/components/autofill_assistant/browser/service.proto b/components/autofill_assistant/browser/service.proto index 25a55d6..e07c8ff9 100644 --- a/components/autofill_assistant/browser/service.proto +++ b/components/autofill_assistant/browser/service.proto
@@ -48,6 +48,11 @@ // be executed. No precondition means that a script can run in any case. optional ScriptPreconditionProto precondition = 3; + // Text display at the same time as the script is proposed. If more than one + // script has an initial prompt, the prompt of the highest-priority script + // wins. + optional string initial_prompt = 4; + // Display priority of the script. Lowest number has highest priority, which // means a script with priority 0 should be displayed before a script with // priority 1. @@ -98,7 +103,7 @@ message ScriptPreconditionProto { // Combined with AND: the elements referenced here must be present. repeated ElementReferenceProto elements_exist = 3; - // Pattern of the path parts of the URL. + // Pattern of the path parts of the URL, including query and '#''. repeated string path_pattern = 5; // Domain (exact match) excluding the last '/' character. repeated string domain = 6;
diff --git a/components/component_updater/component_updater_service.h b/components/component_updater/component_updater_service.h index 3ef6a1d1..03bcb3c 100644 --- a/components/component_updater/component_updater_service.h +++ b/components/component_updater/component_updater_service.h
@@ -166,7 +166,7 @@ friend class ::PluginObserver; friend class SwReporterOnDemandFetcher; #if defined(OS_CHROMEOS) - friend class CrOSComponentManager; + friend class CrOSComponentInstaller; #endif // defined(OS_CHROMEOS) friend class VrAssetsComponentInstallerPolicy;
diff --git a/components/leveldb_proto/BUILD.gn b/components/leveldb_proto/BUILD.gn index 9405633..523c133a 100644 --- a/components/leveldb_proto/BUILD.gn +++ b/components/leveldb_proto/BUILD.gn
@@ -9,6 +9,9 @@ "proto_database.cc", "proto_database.h", "proto_database_impl.h", + "proto_leveldb_wrapper.cc", + "proto_leveldb_wrapper.h", + "unique_proto_database.h", ] public_deps = [ @@ -26,6 +29,7 @@ public_deps = [ ":leveldb_proto", "//base", + "//base/test:test_support", "//components/leveldb_proto/testing/proto", ] } @@ -33,7 +37,7 @@ source_set("unit_tests") { testonly = true sources = [ - "proto_database_impl_unittest.cc", + "unique_proto_database_unittest.cc", ] deps = [ ":test_support",
diff --git a/components/leveldb_proto/leveldb_database.h b/components/leveldb_proto/leveldb_database.h index 2444e38..a226005c0 100644 --- a/components/leveldb_proto/leveldb_database.h +++ b/components/leveldb_proto/leveldb_database.h
@@ -10,10 +10,7 @@ #include <string> #include <vector> -#include "base/gtest_prod_util.h" -#include "base/macros.h" #include "base/strings/string_split.h" -#include "base/threading/thread_collision_warner.h" #include "third_party/leveldatabase/env_chromium.h" namespace base { @@ -25,7 +22,6 @@ class Cache; class DB; class Env; -class Status; } // namespace leveldb namespace leveldb_proto {
diff --git a/components/leveldb_proto/proto_database.h b/components/leveldb_proto/proto_database.h index b62bd4f..7f7d321 100644 --- a/components/leveldb_proto/proto_database.h +++ b/components/leveldb_proto/proto_database.h
@@ -6,18 +6,12 @@ #define COMPONENTS_LEVELDB_PROTO_PROTO_DATABASE_H_ #include <map> -#include <memory> -#include <string> -#include <utility> #include <vector> -#include "base/callback.h" +#include "base/sequenced_task_runner.h" +#include "base/threading/thread_checker.h" #include "components/leveldb_proto/leveldb_database.h" -#include "third_party/leveldatabase/env_chromium.h" - -namespace base { -class FilePath; -} +#include "components/leveldb_proto/proto_leveldb_wrapper.h" namespace leveldb_proto { @@ -43,6 +37,9 @@ // A list of key-value (string, T) tuples. using KeyEntryVector = std::vector<std::pair<std::string, T>>; + explicit ProtoDatabase( + const scoped_refptr<base::SequencedTaskRunner>& task_runner) + : db_wrapper_(std::make_unique<ProtoLevelDBWrapper>(task_runner)) {} virtual ~ProtoDatabase() {} // Asynchronously initializes the object with the specified |options|. @@ -50,7 +47,15 @@ virtual void Init(const char* client_name, const base::FilePath& database_dir, const leveldb_env::Options& options, - InitCallback callback) = 0; + typename ProtoDatabase<T>::InitCallback callback) = 0; + + virtual void InitWithDatabase(LevelDB* database, + const base::FilePath& database_dir, + const leveldb_env::Options& options, + InitCallback callback) { + db_wrapper_->InitWithDatabase(database, database_dir, options, + std::move(callback)); + } // Asynchronously saves |entries_to_save| and deletes entries from // |keys_to_remove| from the database. |callback| will be invoked on the @@ -58,7 +63,11 @@ virtual void UpdateEntries( std::unique_ptr<KeyEntryVector> entries_to_save, std::unique_ptr<std::vector<std::string>> keys_to_remove, - UpdateCallback callback) = 0; + UpdateCallback callback) { + db_wrapper_->template UpdateEntries<T>(std::move(entries_to_save), + std::move(keys_to_remove), + std::move(callback)); + } // Asynchronously saves |entries_to_save| and deletes entries that satisfies // the |delete_key_filter| from the database. |callback| will be invoked on @@ -67,44 +76,76 @@ virtual void UpdateEntriesWithRemoveFilter( std::unique_ptr<KeyEntryVector> entries_to_save, const LevelDB::KeyFilter& delete_key_filter, - UpdateCallback callback) = 0; + UpdateCallback callback) { + db_wrapper_->template UpdateEntriesWithRemoveFilter<T>( + std::move(entries_to_save), delete_key_filter, std::move(callback)); + } // Asynchronously loads all entries from the database and invokes |callback| // when complete. - virtual void LoadEntries(LoadCallback callback) = 0; + virtual void LoadEntries(LoadCallback callback) { + db_wrapper_->template LoadEntries<T>(std::move(callback)); + } // Asynchronously loads entries that satisfies the |filter| from the database // and invokes |callback| when complete. The filter will be called on // ProtoDatabase's taskrunner. virtual void LoadEntriesWithFilter(const LevelDB::KeyFilter& filter, - LoadCallback callback) = 0; - virtual void LoadEntriesWithFilter(const LevelDB::KeyFilter& filter, + LoadCallback callback) { + db_wrapper_->template LoadEntriesWithFilter<T>(filter, std::move(callback)); + } + + virtual void LoadEntriesWithFilter(const LevelDB::KeyFilter& key_filter, const leveldb::ReadOptions& options, const std::string& target_prefix, - LoadCallback callback) = 0; + LoadCallback callback) { + db_wrapper_->template LoadEntriesWithFilter<T>( + key_filter, options, target_prefix, std::move(callback)); + } - virtual void LoadKeysAndEntries( - typename ProtoDatabase<T>::LoadKeysAndEntriesCallback callback) = 0; + virtual void LoadKeysAndEntries(LoadKeysAndEntriesCallback callback) { + db_wrapper_->template LoadKeysAndEntries<T>(std::move(callback)); + } + virtual void LoadKeysAndEntriesWithFilter( const LevelDB::KeyFilter& filter, - typename ProtoDatabase<T>::LoadKeysAndEntriesCallback callback) = 0; + typename ProtoDatabase<T>::LoadKeysAndEntriesCallback callback) { + db_wrapper_->template LoadKeysAndEntriesWithFilter<T>(filter, + std::move(callback)); + } virtual void LoadKeysAndEntriesWithFilter( const LevelDB::KeyFilter& filter, const leveldb::ReadOptions& options, const std::string& target_prefix, - typename ProtoDatabase<T>::LoadKeysAndEntriesCallback callback) = 0; + typename ProtoDatabase<T>::LoadKeysAndEntriesCallback callback) { + db_wrapper_->template LoadKeysAndEntriesWithFilter<T>( + filter, options, target_prefix, std::move(callback)); + } // Asynchronously loads all keys from the database and invokes |callback| with // those keys when complete. - virtual void LoadKeys(LoadKeysCallback callback) = 0; + virtual void LoadKeys(LoadKeysCallback callback) { + db_wrapper_->LoadKeys(std::move(callback)); + } // Asynchronously loads a single entry, identified by |key|, from the database // and invokes |callback| when complete. If no entry with |key| is found, // a nullptr is passed to the callback, but the success flag is still true. - virtual void GetEntry(const std::string& key, GetCallback callback) = 0; + virtual void GetEntry(const std::string& key, GetCallback callback) { + db_wrapper_->template GetEntry<T>(key, std::move(callback)); + } // Asynchronously destroys the database. - virtual void Destroy(DestroyCallback callback) = 0; + virtual void Destroy(DestroyCallback callback) { + db_wrapper_->Destroy(std::move(callback)); + } + + bool GetApproximateMemoryUse(uint64_t* approx_mem_use) { + return db_wrapper_->GetApproximateMemoryUse(approx_mem_use); + } + + protected: + std::unique_ptr<ProtoLevelDBWrapper> db_wrapper_; }; // Return a new instance of Options, but with two additions: @@ -114,4 +155,4 @@ } // namespace leveldb_proto -#endif // COMPONENTS_LEVELDB_PROTO_PROTO_DATABASE_H_ +#endif // COMPONENTS_LEVELDB_PROTO_PROTO_DATABASE_H_ \ No newline at end of file
diff --git a/components/leveldb_proto/proto_database_impl.h b/components/leveldb_proto/proto_database_impl.h index b7a2202..def7f23 100644 --- a/components/leveldb_proto/proto_database_impl.h +++ b/components/leveldb_proto/proto_database_impl.h
@@ -5,483 +5,16 @@ #ifndef COMPONENTS_LEVELDB_PROTO_PROTO_DATABASE_IMPL_H_ #define COMPONENTS_LEVELDB_PROTO_PROTO_DATABASE_IMPL_H_ -#include <memory> -#include <string> -#include <utility> -#include <vector> - -#include "base/bind.h" -#include "base/files/file_path.h" -#include "base/macros.h" -#include "base/memory/ptr_util.h" -#include "base/sequenced_task_runner.h" -#include "base/strings/string_split.h" -#include "base/strings/string_util.h" -#include "base/threading/thread_checker.h" -#include "components/leveldb_proto/leveldb_database.h" -#include "components/leveldb_proto/proto_database.h" +#include "components/leveldb_proto/unique_proto_database.h" namespace leveldb_proto { -using KeyValueVector = base::StringPairs; -using KeyVector = std::vector<std::string>; - -// When the ProtoDatabaseImpl instance is deleted, in-progress asynchronous -// operations will be completed and the corresponding callbacks will be called. -// Construction/calls/destruction should all happen on the same thread. +// Part of an ongoing effort to refactor ProtoDatabase. New users of +// ProtoDatabaseImpl should avoid using this in favor of including +// unique_proto_database.h and using UniqueProtoDatabase directly. +// See https://crbug.com/870813. template <typename T> -class ProtoDatabaseImpl : public ProtoDatabase<T> { - public: - // All blocking calls/disk access will happen on the provided |task_runner|. - explicit ProtoDatabaseImpl( - const scoped_refptr<base::SequencedTaskRunner>& task_runner); - - ~ProtoDatabaseImpl() override; - - // ProtoDatabase implementation. - // TODO(cjhopman): Perhaps Init() shouldn't be exposed to users and not just - // part of the constructor - void Init(const char* client_name, - const base::FilePath& database_dir, - const leveldb_env::Options& options, - typename ProtoDatabase<T>::InitCallback callback) override; - void UpdateEntries( - std::unique_ptr<typename ProtoDatabase<T>::KeyEntryVector> - entries_to_save, - std::unique_ptr<KeyVector> keys_to_remove, - typename ProtoDatabase<T>::UpdateCallback callback) override; - void UpdateEntriesWithRemoveFilter( - std::unique_ptr<typename ProtoDatabase<T>::KeyEntryVector> - entries_to_save, - const LevelDB::KeyFilter& delete_key_filter, - typename ProtoDatabase<T>::UpdateCallback callback) override; - void LoadEntries(typename ProtoDatabase<T>::LoadCallback callback) override; - void LoadEntriesWithFilter( - const LevelDB::KeyFilter& filter, - typename ProtoDatabase<T>::LoadCallback callback) override; - void LoadEntriesWithFilter( - const LevelDB::KeyFilter& filter, - const leveldb::ReadOptions& options, - const std::string& target_prefix, - typename ProtoDatabase<T>::LoadCallback callback) override; - void LoadKeysAndEntries( - typename ProtoDatabase<T>::LoadKeysAndEntriesCallback callback) override; - void LoadKeysAndEntriesWithFilter( - const LevelDB::KeyFilter& filter, - typename ProtoDatabase<T>::LoadKeysAndEntriesCallback callback) override; - void LoadKeysAndEntriesWithFilter( - const LevelDB::KeyFilter& filter, - const leveldb::ReadOptions& options, - const std::string& target_prefix, - typename ProtoDatabase<T>::LoadKeysAndEntriesCallback callback) override; - void LoadKeys(typename ProtoDatabase<T>::LoadKeysCallback callback) override; - void GetEntry(const std::string& key, - typename ProtoDatabase<T>::GetCallback callback) override; - void Destroy(typename ProtoDatabase<T>::DestroyCallback callback) override; - - // Allow callers to provide their own Database implementation. - void InitWithDatabase(std::unique_ptr<LevelDB> database, - const base::FilePath& database_dir, - const leveldb_env::Options& options, - typename ProtoDatabase<T>::InitCallback callback); - - bool GetApproximateMemoryUse(uint64_t* approx_mem); - - private: - base::ThreadChecker thread_checker_; - - // Used to run blocking tasks in-order. - scoped_refptr<base::SequencedTaskRunner> task_runner_; - - std::unique_ptr<LevelDB> db_; - - DISALLOW_COPY_AND_ASSIGN(ProtoDatabaseImpl); -}; - -namespace { - -template <typename T> -void RunInitCallback(typename ProtoDatabase<T>::InitCallback callback, - const bool* success) { - std::move(callback).Run(*success); -} - -template <typename T> -void RunUpdateCallback(typename ProtoDatabase<T>::UpdateCallback callback, - const bool* success) { - std::move(callback).Run(*success); -} - -template <typename T> -void RunLoadCallback(typename ProtoDatabase<T>::LoadCallback callback, - bool* success, - std::unique_ptr<std::vector<T>> entries) { - std::move(callback).Run(*success, std::move(entries)); -} - -template <typename T> -void RunLoadKeysAndEntriesCallback( - typename ProtoDatabase<T>::LoadKeysAndEntriesCallback callback, - bool* success, - std::unique_ptr<std::map<std::string, T>> keys_entries) { - std::move(callback).Run(*success, std::move(keys_entries)); -} - -template <typename T> -void RunLoadKeysCallback(typename ProtoDatabase<T>::LoadKeysCallback callback, - std::unique_ptr<bool> success, - std::unique_ptr<std::vector<std::string>> keys) { - std::move(callback).Run(*success, std::move(keys)); -} - -template <typename T> -void RunGetCallback(typename ProtoDatabase<T>::GetCallback callback, - const bool* success, - const bool* found, - std::unique_ptr<T> entry) { - std::move(callback).Run(*success, *found ? std::move(entry) : nullptr); -} - -template <typename T> -void RunDestroyCallback(typename ProtoDatabase<T>::DestroyCallback callback, - const bool* success) { - std::move(callback).Run(*success); -} - -inline void InitFromTaskRunner(LevelDB* database, - const base::FilePath& database_dir, - const leveldb_env::Options& options, - bool* success) { - DCHECK(success); - - // TODO(cjhopman): Histogram for database size. - *success = database->Init(database_dir, options); -} - -inline void DestroyFromTaskRunner(std::unique_ptr<LevelDB> leveldb, - bool* success) { - CHECK(success); - - *success = leveldb->Destroy(); -} - -template <typename T> -void UpdateEntriesFromTaskRunner( - LevelDB* database, - std::unique_ptr<typename ProtoDatabase<T>::KeyEntryVector> entries_to_save, - std::unique_ptr<KeyVector> keys_to_remove, - bool* success) { - DCHECK(success); - - // Serialize the values from Proto to string before passing on to database. - KeyValueVector pairs_to_save; - for (const auto& pair : *entries_to_save) { - pairs_to_save.push_back( - std::make_pair(pair.first, pair.second.SerializeAsString())); - } - - *success = database->Save(pairs_to_save, *keys_to_remove); -} - -template <typename T> -void UpdateEntriesWithRemoveFilterFromTaskRunner( - LevelDB* database, - std::unique_ptr<typename ProtoDatabase<T>::KeyEntryVector> entries_to_save, - const LevelDB::KeyFilter& delete_key_filter, - bool* success) { - DCHECK(success); - - // Serialize the values from Proto to string before passing on to database. - KeyValueVector pairs_to_save; - for (const auto& pair : *entries_to_save) { - pairs_to_save.push_back( - std::make_pair(pair.first, pair.second.SerializeAsString())); - } - - *success = database->UpdateWithRemoveFilter(pairs_to_save, delete_key_filter); -} - -template <typename T> -void LoadKeysAndEntriesFromTaskRunner(LevelDB* database, - const LevelDB::KeyFilter& filter, - const leveldb::ReadOptions& options, - const std::string& target_prefix, - std::map<std::string, T>* keys_entries, - bool* success) { - DCHECK(success); - DCHECK(keys_entries); - - keys_entries->clear(); - - std::map<std::string, std::string> loaded_entries; - *success = database->LoadKeysAndEntriesWithFilter(filter, &loaded_entries, - options, target_prefix); - - for (const auto& pair : loaded_entries) { - T entry; - if (!entry.ParseFromString(pair.second)) { - DLOG(WARNING) << "Unable to parse leveldb_proto entry"; - // TODO(cjhopman): Decide what to do about un-parseable entries. - } - - keys_entries->insert(std::make_pair(pair.first, entry)); - } -} - -template <typename T> -void LoadEntriesFromTaskRunner(LevelDB* database, - const LevelDB::KeyFilter& filter, - const leveldb::ReadOptions& options, - const std::string& target_prefix, - std::vector<T>* entries, - bool* success) { - entries->clear(); - - std::map<std::string, T> keys_entries; - LoadKeysAndEntriesFromTaskRunner<T>(database, filter, options, target_prefix, - &keys_entries, success); - for (const auto& pair : keys_entries) - entries->push_back(pair.second); -} - -inline void LoadKeysFromTaskRunner(LevelDB* database, - std::vector<std::string>* keys, - bool* success) { - DCHECK(success); - DCHECK(keys); - keys->clear(); - *success = database->LoadKeys(keys); -} - -template <typename T> -void GetEntryFromTaskRunner(LevelDB* database, - const std::string& key, - T* entry, - bool* found, - bool* success) { - DCHECK(success); - DCHECK(found); - DCHECK(entry); - - std::string serialized_entry; - *success = database->Get(key, found, &serialized_entry); - - if (!*success) { - *found = false; - return; - } - - if (!*found) - return; - - if (!entry->ParseFromString(serialized_entry)) { - *found = false; - DLOG(WARNING) << "Unable to parse leveldb_proto entry"; - // TODO(cjhopman): Decide what to do about un-parseable entries. - } -} - -} // namespace - -template <typename T> -ProtoDatabaseImpl<T>::ProtoDatabaseImpl( - const scoped_refptr<base::SequencedTaskRunner>& task_runner) - : task_runner_(task_runner) {} - -template <typename T> -ProtoDatabaseImpl<T>::~ProtoDatabaseImpl() { - DCHECK(thread_checker_.CalledOnValidThread()); - if (db_.get() && !task_runner_->DeleteSoon(FROM_HERE, db_.release())) - DLOG(WARNING) << "Proto database will not be deleted."; -} - -template <typename T> -void ProtoDatabaseImpl<T>::Init( - const char* client_name, - const base::FilePath& database_dir, - const leveldb_env::Options& options, - typename ProtoDatabase<T>::InitCallback callback) { - DCHECK(thread_checker_.CalledOnValidThread()); - InitWithDatabase(base::WrapUnique(new LevelDB(client_name)), database_dir, - options, std::move(callback)); -} - -template <typename T> -void ProtoDatabaseImpl<T>::Destroy( - typename ProtoDatabase<T>::DestroyCallback callback) { - DCHECK(thread_checker_.CalledOnValidThread()); - DCHECK(db_); - - bool* success = new bool(false); - task_runner_->PostTaskAndReply( - FROM_HERE, base::BindOnce(DestroyFromTaskRunner, std::move(db_), success), - base::BindOnce(RunDestroyCallback<T>, std::move(callback), - base::Owned(success))); -} - -template <typename T> -void ProtoDatabaseImpl<T>::InitWithDatabase( - std::unique_ptr<LevelDB> database, - const base::FilePath& database_dir, - const leveldb_env::Options& options, - typename ProtoDatabase<T>::InitCallback callback) { - DCHECK(thread_checker_.CalledOnValidThread()); - DCHECK(!db_); - DCHECK(database); - db_ = std::move(database); - bool* success = new bool(false); - task_runner_->PostTaskAndReply( - FROM_HERE, - base::BindOnce(InitFromTaskRunner, base::Unretained(db_.get()), - database_dir, options, success), - base::BindOnce(RunInitCallback<T>, std::move(callback), - base::Owned(success))); -} - -template <typename T> -void ProtoDatabaseImpl<T>::UpdateEntries( - std::unique_ptr<typename ProtoDatabase<T>::KeyEntryVector> entries_to_save, - std::unique_ptr<KeyVector> keys_to_remove, - typename ProtoDatabase<T>::UpdateCallback callback) { - DCHECK(thread_checker_.CalledOnValidThread()); - bool* success = new bool(false); - task_runner_->PostTaskAndReply( - FROM_HERE, - base::BindOnce(UpdateEntriesFromTaskRunner<T>, - base::Unretained(db_.get()), std::move(entries_to_save), - std::move(keys_to_remove), success), - base::BindOnce(RunUpdateCallback<T>, std::move(callback), - base::Owned(success))); -} - -template <typename T> -void ProtoDatabaseImpl<T>::UpdateEntriesWithRemoveFilter( - std::unique_ptr<typename ProtoDatabase<T>::KeyEntryVector> entries_to_save, - const LevelDB::KeyFilter& delete_key_filter, - typename ProtoDatabase<T>::UpdateCallback callback) { - DCHECK(thread_checker_.CalledOnValidThread()); - bool* success = new bool(false); - - task_runner_->PostTaskAndReply( - FROM_HERE, - base::BindOnce(UpdateEntriesWithRemoveFilterFromTaskRunner<T>, - base::Unretained(db_.get()), std::move(entries_to_save), - delete_key_filter, success), - base::BindOnce(RunUpdateCallback<T>, std::move(callback), - base::Owned(success))); -} - -template <typename T> -void ProtoDatabaseImpl<T>::LoadEntries( - typename ProtoDatabase<T>::LoadCallback callback) { - LoadEntriesWithFilter(LevelDB::KeyFilter(), std::move(callback)); -} - -template <typename T> -void ProtoDatabaseImpl<T>::LoadEntriesWithFilter( - const LevelDB::KeyFilter& key_filter, - typename ProtoDatabase<T>::LoadCallback callback) { - LoadEntriesWithFilter(key_filter, leveldb::ReadOptions(), std::string(), - std::move(callback)); -} - -template <typename T> -void ProtoDatabaseImpl<T>::LoadEntriesWithFilter( - const LevelDB::KeyFilter& key_filter, - const leveldb::ReadOptions& options, - const std::string& target_prefix, - typename ProtoDatabase<T>::LoadCallback callback) { - DCHECK(thread_checker_.CalledOnValidThread()); - bool* success = new bool(false); - - auto entries = std::make_unique<std::vector<T>>(); - // Get this pointer before entries is std::move()'d so we can use it below. - std::vector<T>* entries_ptr = entries.get(); - - task_runner_->PostTaskAndReply( - FROM_HERE, - base::BindOnce(LoadEntriesFromTaskRunner<T>, base::Unretained(db_.get()), - key_filter, options, target_prefix, entries_ptr, success), - base::BindOnce(RunLoadCallback<T>, std::move(callback), - base::Owned(success), std::move(entries))); -} - -template <typename T> -void ProtoDatabaseImpl<T>::LoadKeysAndEntries( - typename ProtoDatabase<T>::LoadKeysAndEntriesCallback callback) { - LoadKeysAndEntriesWithFilter(LevelDB::KeyFilter(), std::move(callback)); -} - -template <typename T> -void ProtoDatabaseImpl<T>::LoadKeysAndEntriesWithFilter( - const LevelDB::KeyFilter& key_filter, - typename ProtoDatabase<T>::LoadKeysAndEntriesCallback callback) { - LoadKeysAndEntriesWithFilter(key_filter, leveldb::ReadOptions(), - std::string(), std::move(callback)); -} - -template <typename T> -void ProtoDatabaseImpl<T>::LoadKeysAndEntriesWithFilter( - const LevelDB::KeyFilter& key_filter, - const leveldb::ReadOptions& options, - const std::string& target_prefix, - typename ProtoDatabase<T>::LoadKeysAndEntriesCallback callback) { - DCHECK(thread_checker_.CalledOnValidThread()); - bool* success = new bool(false); - - auto keys_entries = std::make_unique<std::map<std::string, T>>(); - // Get this pointer before entries is std::move()'d so we can use it below. - std::map<std::string, T>* keys_entries_ptr = keys_entries.get(); - - task_runner_->PostTaskAndReply( - FROM_HERE, - base::BindOnce(LoadKeysAndEntriesFromTaskRunner<T>, - base::Unretained(db_.get()), key_filter, options, - target_prefix, keys_entries_ptr, success), - base::BindOnce(RunLoadKeysAndEntriesCallback<T>, std::move(callback), - base::Owned(success), std::move(keys_entries))); -} - -template <typename T> -void ProtoDatabaseImpl<T>::LoadKeys( - typename ProtoDatabase<T>::LoadKeysCallback callback) { - DCHECK(thread_checker_.CalledOnValidThread()); - auto success = std::make_unique<bool>(false); - auto keys = std::make_unique<std::vector<std::string>>(); - auto load_task = - base::Bind(LoadKeysFromTaskRunner, base::Unretained(db_.get()), - keys.get(), success.get()); - task_runner_->PostTaskAndReply( - FROM_HERE, load_task, - base::BindOnce(RunLoadKeysCallback<T>, std::move(callback), - std::move(success), std::move(keys))); -} - -template <typename T> -void ProtoDatabaseImpl<T>::GetEntry( - const std::string& key, - typename ProtoDatabase<T>::GetCallback callback) { - DCHECK(thread_checker_.CalledOnValidThread()); - bool* success = new bool(false); - bool* found = new bool(false); - - std::unique_ptr<T> entry(new T()); - // Get this pointer before entry is std::move()'d so we can use it below. - T* entry_ptr = entry.get(); - - task_runner_->PostTaskAndReply( - FROM_HERE, - base::BindOnce(GetEntryFromTaskRunner<T>, base::Unretained(db_.get()), - key, entry_ptr, found, success), - base::BindOnce(RunGetCallback<T>, std::move(callback), - base::Owned(success), base::Owned(found), - std::move(entry))); -} - -template <typename T> -bool ProtoDatabaseImpl<T>::GetApproximateMemoryUse(uint64_t* approx_mem) { - return db_->GetApproximateMemoryUse(approx_mem); -} +using ProtoDatabaseImpl = UniqueProtoDatabase<T>; } // namespace leveldb_proto
diff --git a/components/leveldb_proto/proto_database_perftest.cc b/components/leveldb_proto/proto_database_perftest.cc index 9152e726..4dbc010 100644 --- a/components/leveldb_proto/proto_database_perftest.cc +++ b/components/leveldb_proto/proto_database_perftest.cc
@@ -24,8 +24,8 @@ #include "base/threading/thread.h" #include "build/build_config.h" #include "components/leveldb_proto/leveldb_database.h" -#include "components/leveldb_proto/proto_database_impl.h" #include "components/leveldb_proto/testing/proto/test_db.pb.h" +#include "components/leveldb_proto/unique_proto_database.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" #include "testing/perf/perf_test.h" @@ -85,7 +85,7 @@ TestDatabase(const std::string& name, scoped_refptr<base::SingleThreadTaskRunner> task_runner, const base::FilePath& path) { - db_.reset(new ProtoDatabaseImpl<TestProto>(task_runner)); + db_.reset(new UniqueProtoDatabase<TestProto>(task_runner)); leveldb_env::Options options = leveldb_proto::CreateSimpleOptions(); base::RunLoop run_init_db; @@ -102,11 +102,11 @@ } bool is_initialized() const { return is_initialized_; } - ProtoDatabaseImpl<TestProto>* proto_db() const { return db_.get(); } + UniqueProtoDatabase<TestProto>* proto_db() const { return db_.get(); } private: bool is_initialized_ = false; - std::unique_ptr<ProtoDatabaseImpl<TestProto>> db_; + std::unique_ptr<UniqueProtoDatabase<TestProto>> db_; }; } // namespace
diff --git a/components/leveldb_proto/proto_leveldb_wrapper.cc b/components/leveldb_proto/proto_leveldb_wrapper.cc new file mode 100644 index 0000000..e82e4ae --- /dev/null +++ b/components/leveldb_proto/proto_leveldb_wrapper.cc
@@ -0,0 +1,114 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "components/leveldb_proto/proto_leveldb_wrapper.h" + +namespace leveldb_proto { + +namespace { + +void RunInitCallback(typename ProtoLevelDBWrapper::InitCallback callback, + const bool* success) { + std::move(callback).Run(*success); +} + +inline void InitFromTaskRunner(LevelDB* database, + const base::FilePath& database_dir, + const leveldb_env::Options& options, + bool* success) { + DCHECK(success); + + // TODO(cjhopman): Histogram for database size. + *success = database->Init(database_dir, options); +} + +void RunDestroyCallback(typename ProtoLevelDBWrapper::DestroyCallback callback, + const bool* success) { + std::move(callback).Run(*success); +} + +inline void DestroyFromTaskRunner(LevelDB* database, bool* success) { + CHECK(success); + + *success = database->Destroy(); +} + +void RunLoadKeysCallback( + typename ProtoLevelDBWrapper::LoadKeysCallback callback, + std::unique_ptr<bool> success, + std::unique_ptr<std::vector<std::string>> keys) { + std::move(callback).Run(*success, std::move(keys)); +} + +inline void LoadKeysFromTaskRunner(LevelDB* database, + std::vector<std::string>* keys, + bool* success) { + DCHECK(success); + DCHECK(keys); + keys->clear(); + *success = database->LoadKeys(keys); +} + +} // namespace + +ProtoLevelDBWrapper::ProtoLevelDBWrapper( + const scoped_refptr<base::SequencedTaskRunner>& task_runner) + : task_runner_(task_runner) {} + +ProtoLevelDBWrapper::~ProtoLevelDBWrapper() = default; + +void ProtoLevelDBWrapper::InitWithDatabase( + LevelDB* database, + const base::FilePath& database_dir, + const leveldb_env::Options& options, + typename ProtoLevelDBWrapper::InitCallback callback) { + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); + DCHECK(!db_); + DCHECK(database); + db_ = database; + bool* success = new bool(false); + task_runner_->PostTaskAndReply( + FROM_HERE, + base::BindOnce(InitFromTaskRunner, base::Unretained(db_), database_dir, + options, success), + base::BindOnce(RunInitCallback, std::move(callback), + base::Owned(success))); +} + +void ProtoLevelDBWrapper::Destroy( + typename ProtoLevelDBWrapper::DestroyCallback callback) { + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); + DCHECK(db_); + + bool* success = new bool(false); + task_runner_->PostTaskAndReply( + FROM_HERE, + base::BindOnce(DestroyFromTaskRunner, base::Unretained(db_), success), + base::BindOnce(RunDestroyCallback, std::move(callback), + base::Owned(success))); +} + +void ProtoLevelDBWrapper::LoadKeys( + typename ProtoLevelDBWrapper::LoadKeysCallback callback) { + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); + auto success = std::make_unique<bool>(false); + auto keys = std::make_unique<std::vector<std::string>>(); + auto load_task = base::BindOnce(LoadKeysFromTaskRunner, base::Unretained(db_), + keys.get(), success.get()); + task_runner_->PostTaskAndReply( + FROM_HERE, std::move(load_task), + base::BindOnce(RunLoadKeysCallback, std::move(callback), + std::move(success), std::move(keys))); +} + +bool ProtoLevelDBWrapper::GetApproximateMemoryUse(uint64_t* approx_mem_use) { + return db_->GetApproximateMemoryUse(approx_mem_use); +} + +const scoped_refptr<base::SequencedTaskRunner>& +ProtoLevelDBWrapper::task_runner() { + return task_runner_; +} + +} // namespace leveldb_proto \ No newline at end of file
diff --git a/components/leveldb_proto/proto_leveldb_wrapper.h b/components/leveldb_proto/proto_leveldb_wrapper.h new file mode 100644 index 0000000..0a2be1a --- /dev/null +++ b/components/leveldb_proto/proto_leveldb_wrapper.h
@@ -0,0 +1,430 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef COMPONENTS_LEVELDB_PROTO_PROTO_LEVELDB_WRAPPER_H_ +#define COMPONENTS_LEVELDB_PROTO_PROTO_LEVELDB_WRAPPER_H_ + +#include <memory> +#include <string> +#include <utility> +#include <vector> + +#include "base/bind.h" +#include "base/callback.h" +#include "base/memory/ptr_util.h" +#include "base/sequenced_task_runner.h" +#include "base/threading/thread_checker.h" +#include "components/leveldb_proto/leveldb_database.h" +#include "third_party/leveldatabase/env_chromium.h" + +namespace base { +class FilePath; +} + +namespace leveldb_proto { + +using KeyValueVector = base::StringPairs; +using KeyVector = std::vector<std::string>; + +// When the ProtoDatabase instance is deleted, in-progress asynchronous +// operations will be completed and the corresponding callbacks will be called. +// Construction/calls/destruction should all happen on the same thread. +class ProtoLevelDBWrapper { + public: + using InitCallback = base::OnceCallback<void(bool success)>; + using UpdateCallback = base::OnceCallback<void(bool success)>; + using LoadKeysCallback = + base::OnceCallback<void(bool success, + std::unique_ptr<std::vector<std::string>>)>; + using DestroyCallback = base::OnceCallback<void(bool success)>; + using OnCreateCallback = base::OnceCallback<void(ProtoLevelDBWrapper*)>; + + template <typename T> + class Internal { + public: + using LoadCallback = + base::OnceCallback<void(bool success, std::unique_ptr<std::vector<T>>)>; + using GetCallback = + base::OnceCallback<void(bool success, std::unique_ptr<T>)>; + using LoadKeysAndEntriesCallback = + base::OnceCallback<void(bool success, + std::unique_ptr<std::map<std::string, T>>)>; + + // A list of key-value (string, T) tuples. + using KeyEntryVector = std::vector<std::pair<std::string, T>>; + }; + + // All blocking calls/disk access will happen on the provided |task_runner|. + ProtoLevelDBWrapper( + const scoped_refptr<base::SequencedTaskRunner>& task_runner); + + virtual ~ProtoLevelDBWrapper(); + + template <typename T> + void UpdateEntries( + std::unique_ptr<typename ProtoLevelDBWrapper::Internal<T>::KeyEntryVector> + entries_to_save, + std::unique_ptr<KeyVector> keys_to_remove, + UpdateCallback callback); + + template <typename T> + void UpdateEntriesWithRemoveFilter( + std::unique_ptr<typename ProtoLevelDBWrapper::Internal<T>::KeyEntryVector> + entries_to_save, + const LevelDB::KeyFilter& delete_key_filter, + UpdateCallback callback); + + template <typename T> + void LoadEntries( + typename ProtoLevelDBWrapper::Internal<T>::LoadCallback callback); + + template <typename T> + void LoadEntriesWithFilter( + const LevelDB::KeyFilter& key_filter, + typename ProtoLevelDBWrapper::Internal<T>::LoadCallback callback); + + template <typename T> + void LoadEntriesWithFilter( + const LevelDB::KeyFilter& key_filter, + const leveldb::ReadOptions& options, + const std::string& target_prefix, + typename ProtoLevelDBWrapper::Internal<T>::LoadCallback callback); + + template <typename T> + void LoadKeysAndEntries( + typename ProtoLevelDBWrapper::Internal<T>::LoadKeysAndEntriesCallback + callback); + + template <typename T> + void LoadKeysAndEntriesWithFilter( + const LevelDB::KeyFilter& filter, + typename ProtoLevelDBWrapper::Internal<T>::LoadKeysAndEntriesCallback + callback); + + template <typename T> + void LoadKeysAndEntriesWithFilter( + const LevelDB::KeyFilter& filter, + const leveldb::ReadOptions& options, + const std::string& target_prefix, + typename ProtoLevelDBWrapper::Internal<T>::LoadKeysAndEntriesCallback + callback); + + void LoadKeys(LoadKeysCallback callback); + + template <typename T> + void GetEntry( + const std::string& key, + typename ProtoLevelDBWrapper::Internal<T>::GetCallback callback); + + void Destroy(DestroyCallback callback); + + // Allow callers to provide their own Database implementation. + void InitWithDatabase(LevelDB* database, + const base::FilePath& database_dir, + const leveldb_env::Options& options, + InitCallback callback); + + bool GetApproximateMemoryUse(uint64_t* approx_mem_use); + const scoped_refptr<base::SequencedTaskRunner>& task_runner(); + + private: + THREAD_CHECKER(thread_checker_); + + // Used to run blocking tasks in-order, must be the TaskRunner that |db_| + // relies on. + scoped_refptr<base::SequencedTaskRunner> task_runner_; + LevelDB* db_ = nullptr; + + DISALLOW_COPY_AND_ASSIGN(ProtoLevelDBWrapper); +}; + +namespace { + +template <typename T> +void RunUpdateCallback(typename ProtoLevelDBWrapper::UpdateCallback callback, + const bool* success) { + std::move(callback).Run(*success); +} + +template <typename T> +void RunLoadCallback( + typename ProtoLevelDBWrapper::Internal<T>::LoadCallback callback, + bool* success, + std::unique_ptr<std::vector<T>> entries) { + std::move(callback).Run(*success, std::move(entries)); +} + +template <typename T> +void RunLoadKeysAndEntriesCallback( + typename ProtoLevelDBWrapper::Internal<T>::LoadKeysAndEntriesCallback + callback, + bool* success, + std::unique_ptr<std::map<std::string, T>> keys_entries) { + std::move(callback).Run(*success, std::move(keys_entries)); +} + +template <typename T> +void RunGetCallback( + typename ProtoLevelDBWrapper::Internal<T>::GetCallback callback, + const bool* success, + const bool* found, + std::unique_ptr<T> entry) { + std::move(callback).Run(*success, *found ? std::move(entry) : nullptr); +} + +template <typename T> +void UpdateEntriesFromTaskRunner( + LevelDB* database, + std::unique_ptr<typename ProtoLevelDBWrapper::Internal<T>::KeyEntryVector> + entries_to_save, + std::unique_ptr<KeyVector> keys_to_remove, + bool* success) { + DCHECK(success); + + // Serialize the values from Proto to string before passing on to database. + KeyValueVector pairs_to_save; + for (const auto& pair : *entries_to_save) { + pairs_to_save.push_back( + std::make_pair(pair.first, pair.second.SerializeAsString())); + } + + *success = database->Save(pairs_to_save, *keys_to_remove); +} + +template <typename T> +void UpdateEntriesWithRemoveFilterFromTaskRunner( + LevelDB* database, + std::unique_ptr<typename ProtoLevelDBWrapper::Internal<T>::KeyEntryVector> + entries_to_save, + const LevelDB::KeyFilter& delete_key_filter, + bool* success) { + DCHECK(success); + + // Serialize the values from Proto to string before passing on to database. + KeyValueVector pairs_to_save; + for (const auto& pair : *entries_to_save) { + pairs_to_save.push_back( + std::make_pair(pair.first, pair.second.SerializeAsString())); + } + + *success = database->UpdateWithRemoveFilter(pairs_to_save, delete_key_filter); +} + +template <typename T> +void LoadKeysAndEntriesFromTaskRunner(LevelDB* database, + const LevelDB::KeyFilter& filter, + const leveldb::ReadOptions& options, + const std::string& target_prefix, + std::map<std::string, T>* keys_entries, + bool* success) { + DCHECK(success); + DCHECK(keys_entries); + + keys_entries->clear(); + + std::map<std::string, std::string> loaded_entries; + *success = database->LoadKeysAndEntriesWithFilter(filter, &loaded_entries, + options, target_prefix); + + for (const auto& pair : loaded_entries) { + T entry; + if (!entry.ParseFromString(pair.second)) { + DLOG(WARNING) << "Unable to parse leveldb_proto entry"; + // TODO(cjhopman): Decide what to do about un-parseable entries. + } + + keys_entries->insert(std::make_pair(pair.first, entry)); + } +} + +template <typename T> +void LoadEntriesFromTaskRunner(LevelDB* database, + const LevelDB::KeyFilter& filter, + const leveldb::ReadOptions& options, + const std::string& target_prefix, + std::vector<T>* entries, + bool* success) { + DCHECK(success); + DCHECK(entries); + + entries->clear(); + + std::vector<std::string> loaded_entries; + *success = + database->LoadWithFilter(filter, &loaded_entries, options, target_prefix); + + for (const auto& serialized_entry : loaded_entries) { + T entry; + if (!entry.ParseFromString(serialized_entry)) { + DLOG(WARNING) << "Unable to parse leveldb_proto entry"; + // TODO(cjhopman): Decide what to do about un-parseable entries. + } + + entries->push_back(entry); + } +} + +template <typename T> +void GetEntryFromTaskRunner(LevelDB* database, + const std::string& key, + T* entry, + bool* found, + bool* success) { + DCHECK(success); + DCHECK(found); + DCHECK(entry); + + std::string serialized_entry; + *success = database->Get(key, found, &serialized_entry); + + if (!*success) { + *found = false; + return; + } + + if (!*found) + return; + + if (!entry->ParseFromString(serialized_entry)) { + *found = false; + DLOG(WARNING) << "Unable to parse leveldb_proto entry"; + // TODO(cjhopman): Decide what to do about un-parseable entries. + } +} + +} // namespace + +template <typename T> +void ProtoLevelDBWrapper::UpdateEntries( + std::unique_ptr<typename ProtoLevelDBWrapper::Internal<T>::KeyEntryVector> + entries_to_save, + std::unique_ptr<KeyVector> keys_to_remove, + typename ProtoLevelDBWrapper::UpdateCallback callback) { + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); + bool* success = new bool(false); + task_runner_->PostTaskAndReply( + FROM_HERE, + base::BindOnce(UpdateEntriesFromTaskRunner<T>, base::Unretained(db_), + std::move(entries_to_save), std::move(keys_to_remove), + success), + base::BindOnce(RunUpdateCallback<T>, std::move(callback), + base::Owned(success))); +} + +template <typename T> +void ProtoLevelDBWrapper::UpdateEntriesWithRemoveFilter( + std::unique_ptr<typename ProtoLevelDBWrapper::Internal<T>::KeyEntryVector> + entries_to_save, + const LevelDB::KeyFilter& delete_key_filter, + typename ProtoLevelDBWrapper::UpdateCallback callback) { + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); + bool* success = new bool(false); + + task_runner_->PostTaskAndReply( + FROM_HERE, + base::BindOnce(UpdateEntriesWithRemoveFilterFromTaskRunner<T>, + base::Unretained(db_), std::move(entries_to_save), + delete_key_filter, success), + base::BindOnce(RunUpdateCallback<T>, std::move(callback), + base::Owned(success))); +} + +template <typename T> +void ProtoLevelDBWrapper::LoadEntries( + typename ProtoLevelDBWrapper::Internal<T>::LoadCallback callback) { + LoadEntriesWithFilter<T>(LevelDB::KeyFilter(), std::move(callback)); +} + +template <typename T> +void ProtoLevelDBWrapper::LoadEntriesWithFilter( + const LevelDB::KeyFilter& key_filter, + typename ProtoLevelDBWrapper::Internal<T>::LoadCallback callback) { + LoadEntriesWithFilter<T>(key_filter, leveldb::ReadOptions(), std::string(), + std::move(callback)); +} + +template <typename T> +void ProtoLevelDBWrapper::LoadEntriesWithFilter( + const LevelDB::KeyFilter& key_filter, + const leveldb::ReadOptions& options, + const std::string& target_prefix, + typename ProtoLevelDBWrapper::Internal<T>::LoadCallback callback) { + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); + bool* success = new bool(false); + + std::unique_ptr<std::vector<T>> entries(new std::vector<T>()); + // Get this pointer before entries is std::move()'d so we can use it below. + std::vector<T>* entries_ptr = entries.get(); + + task_runner_->PostTaskAndReply( + FROM_HERE, + base::BindOnce(LoadEntriesFromTaskRunner<T>, base::Unretained(db_), + key_filter, options, target_prefix, entries_ptr, success), + base::BindOnce(RunLoadCallback<T>, std::move(callback), + base::Owned(success), std::move(entries))); +} + +template <typename T> +void ProtoLevelDBWrapper::LoadKeysAndEntries( + typename ProtoLevelDBWrapper::Internal<T>::LoadKeysAndEntriesCallback + callback) { + LoadKeysAndEntriesWithFilter<T>(LevelDB::KeyFilter(), std::move(callback)); +} + +template <typename T> +void ProtoLevelDBWrapper::LoadKeysAndEntriesWithFilter( + const LevelDB::KeyFilter& key_filter, + typename ProtoLevelDBWrapper::Internal<T>::LoadKeysAndEntriesCallback + callback) { + LoadKeysAndEntriesWithFilter<T>(key_filter, leveldb::ReadOptions(), + std::string(), std::move(callback)); +} + +template <typename T> +void ProtoLevelDBWrapper::LoadKeysAndEntriesWithFilter( + const LevelDB::KeyFilter& key_filter, + const leveldb::ReadOptions& options, + const std::string& target_prefix, + typename ProtoLevelDBWrapper::Internal<T>::LoadKeysAndEntriesCallback + callback) { + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); + bool* success = new bool(false); + + auto keys_entries = std::make_unique<std::map<std::string, T>>(); + // Get this pointer before entries is std::move()'d so we can use it below. + std::map<std::string, T>* keys_entries_ptr = keys_entries.get(); + + task_runner_->PostTaskAndReply( + FROM_HERE, + base::BindOnce(LoadKeysAndEntriesFromTaskRunner<T>, base::Unretained(db_), + key_filter, options, target_prefix, keys_entries_ptr, + success), + base::BindOnce(RunLoadKeysAndEntriesCallback<T>, std::move(callback), + base::Owned(success), std::move(keys_entries))); +} + +template <typename T> +void ProtoLevelDBWrapper::GetEntry( + const std::string& key, + typename ProtoLevelDBWrapper::Internal<T>::GetCallback callback) { + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); + bool* success = new bool(false); + bool* found = new bool(false); + + std::unique_ptr<T> entry(new T()); + // Get this pointer before entry is std::move()'d so we can use it below. + T* entry_ptr = entry.get(); + + task_runner_->PostTaskAndReply( + FROM_HERE, + base::BindOnce(GetEntryFromTaskRunner<T>, base::Unretained(db_), key, + entry_ptr, found, success), + base::BindOnce(RunGetCallback<T>, std::move(callback), + base::Owned(success), base::Owned(found), + std::move(entry))); +} + +} // namespace leveldb_proto + +#endif // COMPONENTS_LEVELDB_PROTO_PROTO_LEVELDB_WRAPPER_H_ \ No newline at end of file
diff --git a/components/leveldb_proto/testing/fake_db.h b/components/leveldb_proto/testing/fake_db.h index 56ed635..5753744 100644 --- a/components/leveldb_proto/testing/fake_db.h +++ b/components/leveldb_proto/testing/fake_db.h
@@ -14,6 +14,8 @@ #include "base/bind.h" #include "base/callback.h" #include "base/files/file_path.h" +#include "base/task/post_task.h" +#include "base/test/test_simple_task_runner.h" #include "components/leveldb_proto/proto_database.h" namespace leveldb_proto { @@ -34,6 +36,11 @@ const base::FilePath& database_dir, const leveldb_env::Options& options, typename ProtoDatabase<T>::InitCallback callback) override; + void InitWithDatabase( + LevelDB* database, + const base::FilePath& database_dir, + const leveldb_env::Options& options, + typename ProtoLevelDBWrapper::InitCallback callback) override; void UpdateEntries( std::unique_ptr<typename ProtoDatabase<T>::KeyEntryVector> entries_to_save, @@ -115,7 +122,9 @@ template <typename T> FakeDB<T>::FakeDB(EntryMap* db) - : db_(db) {} + : ProtoDatabase<T>(base::MakeRefCounted<base::TestSimpleTaskRunner>()) { + db_ = db; +} template <typename T> FakeDB<T>::~FakeDB() {} @@ -130,6 +139,15 @@ } template <typename T> +void FakeDB<T>::InitWithDatabase( + LevelDB* database, + const base::FilePath& database_dir, + const leveldb_env::Options& options, + typename ProtoLevelDBWrapper::InitCallback callback) { + Init("", database_dir, options, std::move(callback)); +} + +template <typename T> void FakeDB<T>::UpdateEntries( std::unique_ptr<typename ProtoDatabase<T>::KeyEntryVector> entries_to_save, std::unique_ptr<std::vector<std::string>> keys_to_remove,
diff --git a/components/leveldb_proto/unique_proto_database.h b/components/leveldb_proto/unique_proto_database.h new file mode 100644 index 0000000..3b3fc0f --- /dev/null +++ b/components/leveldb_proto/unique_proto_database.h
@@ -0,0 +1,51 @@ +// Copyright 2014 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_LEVELDB_PROTO_UNIQUE_PROTO_DATABASE_H_ +#define COMPONENTS_LEVELDB_PROTO_UNIQUE_PROTO_DATABASE_H_ + +#include "base/sequenced_task_runner.h" +#include "base/threading/thread_checker.h" +#include "components/leveldb_proto/leveldb_database.h" +#include "components/leveldb_proto/proto_database.h" +#include "components/leveldb_proto/proto_leveldb_wrapper.h" + +namespace leveldb_proto { + +// An implementation of ProtoDatabase<T> that manages the lifecycle of a unique +// LevelDB instance. +template <typename T> +class UniqueProtoDatabase : public ProtoDatabase<T> { + public: + UniqueProtoDatabase( + const scoped_refptr<base::SequencedTaskRunner>& task_runner) + : ProtoDatabase<T>(task_runner) {} + + virtual void Init(const char* client_name, + const base::FilePath& database_dir, + const leveldb_env::Options& options, + typename ProtoDatabase<T>::InitCallback callback) override { + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); + db_ = std::make_unique<LevelDB>(client_name); + ProtoDatabase<T>::InitWithDatabase(db_.get(), database_dir, options, + std::move(callback)); + } + + virtual ~UniqueProtoDatabase() { + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); + if (db_.get() && + !this->db_wrapper_->task_runner()->DeleteSoon(FROM_HERE, db_.release())) + DLOG(WARNING) << "Proto database will not be deleted."; + } + + private: + THREAD_CHECKER(thread_checker_); + + scoped_refptr<base::SequencedTaskRunner> task_runner_; + std::unique_ptr<LevelDB> db_; +}; + +} // namespace leveldb_proto + +#endif // COMPONENTS_LEVELDB_PROTO_UNIQUE_PROTO_DATABASE_H_
diff --git a/components/leveldb_proto/proto_database_impl_unittest.cc b/components/leveldb_proto/unique_proto_database_unittest.cc similarity index 84% rename from components/leveldb_proto/proto_database_impl_unittest.cc rename to components/leveldb_proto/unique_proto_database_unittest.cc index c1053b09..721a5ec 100644 --- a/components/leveldb_proto/proto_database_impl_unittest.cc +++ b/components/leveldb_proto/unique_proto_database_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 "components/leveldb_proto/proto_database_impl.h" +#include "components/leveldb_proto/unique_proto_database.h" #include <stddef.h> @@ -174,13 +174,13 @@ } } -class ProtoDatabaseImplTest : public testing::Test { +class UniqueProtoDatabaseTest : public testing::Test { public: - ProtoDatabaseImplTest() + UniqueProtoDatabaseTest() : options_(MakeMatcher(new OptionsEqMatcher(CreateSimpleOptions()))) {} void SetUp() override { main_loop_.reset(new MessageLoop()); - db_.reset(new ProtoDatabaseImpl<TestProto>(main_loop_->task_runner())); + db_.reset(new UniqueProtoDatabase<TestProto>(main_loop_->task_runner())); } void TearDown() override { @@ -190,32 +190,32 @@ } const Matcher<const Options&> options_; - std::unique_ptr<ProtoDatabaseImpl<TestProto>> db_; + std::unique_ptr<UniqueProtoDatabase<TestProto>> db_; std::unique_ptr<MessageLoop> main_loop_; }; -// Test that ProtoDatabaseImpl calls Init on the underlying database and that +// Test that UniqueProtoDatabase calls Init on the underlying database and that // the caller's InitCallback is called with the correct value. -TEST_F(ProtoDatabaseImplTest, TestDBInitSuccess) { +TEST_F(UniqueProtoDatabaseTest, TestDBInitSuccess) { base::FilePath path(FILE_PATH_LITERAL("/fake/path")); - MockDB* mock_db = new MockDB(); + auto mock_db = std::make_unique<MockDB>(); EXPECT_CALL(*mock_db, Init(path, options_)).WillOnce(Return(true)); MockDatabaseCaller caller; EXPECT_CALL(caller, InitCallback(true)); - db_->InitWithDatabase(base::WrapUnique(mock_db), path, CreateSimpleOptions(), + db_->InitWithDatabase(mock_db.get(), path, CreateSimpleOptions(), base::BindOnce(&MockDatabaseCaller::InitCallback, base::Unretained(&caller))); base::RunLoop().RunUntilIdle(); } -TEST_F(ProtoDatabaseImplTest, TestDBInitFailure) { +TEST_F(UniqueProtoDatabaseTest, TestDBInitFailure) { base::FilePath path(FILE_PATH_LITERAL("/fake/path")); - MockDB* mock_db = new MockDB(); + auto mock_db = std::make_unique<MockDB>(); Options options; options.create_if_missing = true; EXPECT_CALL(*mock_db, Init(path, OptionsEq(options))).WillOnce(Return(false)); @@ -223,23 +223,23 @@ MockDatabaseCaller caller; EXPECT_CALL(caller, InitCallback(false)); - db_->InitWithDatabase(base::WrapUnique(mock_db), path, options, + db_->InitWithDatabase(mock_db.get(), path, options, base::BindOnce(&MockDatabaseCaller::InitCallback, base::Unretained(&caller))); base::RunLoop().RunUntilIdle(); } -TEST_F(ProtoDatabaseImplTest, TestDBDestroySuccess) { +TEST_F(UniqueProtoDatabaseTest, TestDBDestroySuccess) { base::FilePath path(FILE_PATH_LITERAL("/fake/path")); - MockDB* mock_db = new MockDB(); + auto mock_db = std::make_unique<MockDB>(); EXPECT_CALL(*mock_db, Init(path, options_)).WillOnce(Return(true)); MockDatabaseCaller caller; EXPECT_CALL(caller, InitCallback(true)); - db_->InitWithDatabase(base::WrapUnique(mock_db), path, CreateSimpleOptions(), + db_->InitWithDatabase(mock_db.get(), path, CreateSimpleOptions(), base::BindOnce(&MockDatabaseCaller::InitCallback, base::Unretained(&caller))); @@ -251,16 +251,16 @@ base::RunLoop().RunUntilIdle(); } -TEST_F(ProtoDatabaseImplTest, TestDBDestroyFailure) { +TEST_F(UniqueProtoDatabaseTest, TestDBDestroyFailure) { base::FilePath path(FILE_PATH_LITERAL("/fake/path")); - MockDB* mock_db = new MockDB(); + auto mock_db = std::make_unique<MockDB>(); EXPECT_CALL(*mock_db, Init(path, options_)).WillOnce(Return(true)); MockDatabaseCaller caller; EXPECT_CALL(caller, InitCallback(true)); - db_->InitWithDatabase(base::WrapUnique(mock_db), path, CreateSimpleOptions(), + db_->InitWithDatabase(mock_db.get(), path, CreateSimpleOptions(), base::BindOnce(&MockDatabaseCaller::InitCallback, base::Unretained(&caller))); @@ -301,47 +301,47 @@ ExpectEntryPointersEquals(expected, actual); } -// Test that ProtoDatabaseImpl calls Load on the underlying database and that +// Test that UniqueProtoDatabase calls Load on the underlying database and that // the caller's LoadCallback is called with the correct success value. Also // confirms that on success, the expected entries are passed to the caller's // LoadCallback. -TEST_F(ProtoDatabaseImplTest, TestDBLoadSuccess) { +TEST_F(UniqueProtoDatabaseTest, TestDBLoadSuccess) { base::FilePath path(FILE_PATH_LITERAL("/fake/path")); - MockDB* mock_db = new MockDB(); + auto mock_db = std::make_unique<MockDB>(); MockDatabaseCaller caller; EntryMap model = GetSmallModel(); EXPECT_CALL(*mock_db, Init(_, options_)); EXPECT_CALL(caller, InitCallback(_)); - db_->InitWithDatabase(base::WrapUnique(mock_db), path, CreateSimpleOptions(), + db_->InitWithDatabase(mock_db.get(), path, CreateSimpleOptions(), base::BindOnce(&MockDatabaseCaller::InitCallback, base::Unretained(&caller))); EXPECT_CALL(*mock_db, LoadKeysAndEntriesWithFilter(_, _, _, _)) .WillOnce(AppendLoadKeysAndEntries(model)); - EXPECT_CALL(caller, LoadCallback1(true, _)) - .WillOnce(VerifyLoadEntries(testing::ByRef(model))); - db_->LoadEntries(base::BindOnce(&MockDatabaseCaller::LoadCallback, - base::Unretained(&caller))); + EXPECT_CALL(caller, LoadKeysAndEntriesCallback1(true, _)) + .WillOnce(VerifyLoadKeysAndEntries(testing::ByRef(model))); + db_->LoadKeysAndEntries( + base::BindOnce(&MockDatabaseCaller::LoadKeysAndEntriesCallback, + base::Unretained(&caller))); base::RunLoop().RunUntilIdle(); } -TEST_F(ProtoDatabaseImplTest, TestDBLoadFailure) { +TEST_F(UniqueProtoDatabaseTest, TestDBLoadFailure) { base::FilePath path(FILE_PATH_LITERAL("/fake/path")); - MockDB* mock_db = new MockDB(); + auto mock_db = std::make_unique<MockDB>(); MockDatabaseCaller caller; EXPECT_CALL(*mock_db, Init(_, options_)); EXPECT_CALL(caller, InitCallback(_)); - db_->InitWithDatabase(base::WrapUnique(mock_db), path, CreateSimpleOptions(), + db_->InitWithDatabase(mock_db.get(), path, CreateSimpleOptions(), base::BindOnce(&MockDatabaseCaller::InitCallback, base::Unretained(&caller))); - EXPECT_CALL(*mock_db, LoadKeysAndEntriesWithFilter(_, _, _, _)) - .WillOnce(Return(false)); + EXPECT_CALL(*mock_db, LoadWithFilter(_, _, _, _)).WillOnce(Return(false)); EXPECT_CALL(caller, LoadCallback1(false, _)); db_->LoadEntries(base::BindOnce(&MockDatabaseCaller::LoadCallback, base::Unretained(&caller))); @@ -368,16 +368,16 @@ EXPECT_EQ(expected.SerializeAsString(), actual->SerializeAsString()); } -TEST_F(ProtoDatabaseImplTest, TestDBGetSuccess) { +TEST_F(UniqueProtoDatabaseTest, TestDBGetSuccess) { base::FilePath path(FILE_PATH_LITERAL("/fake/path")); - MockDB* mock_db = new MockDB(); + auto mock_db = std::make_unique<MockDB>(); MockDatabaseCaller caller; EntryMap model = GetSmallModel(); EXPECT_CALL(*mock_db, Init(_, options_)); EXPECT_CALL(caller, InitCallback(_)); - db_->InitWithDatabase(base::WrapUnique(mock_db), path, CreateSimpleOptions(), + db_->InitWithDatabase(mock_db.get(), path, CreateSimpleOptions(), base::BindOnce(&MockDatabaseCaller::InitCallback, base::Unretained(&caller))); @@ -392,7 +392,7 @@ base::RunLoop().RunUntilIdle(); } -class ProtoDatabaseImplLevelDBTest : public testing::Test { +class UniqueProtoDatabaseLevelDBTest : public testing::Test { public: void SetUp() override { main_loop_.reset(new MessageLoop()); } @@ -405,45 +405,46 @@ std::unique_ptr<MessageLoop> main_loop_; }; -TEST_F(ProtoDatabaseImplLevelDBTest, TestDBSaveAndLoadKeys) { +TEST_F(UniqueProtoDatabaseLevelDBTest, TestDBSaveAndLoadKeys) { ScopedTempDir temp_dir; ASSERT_TRUE(temp_dir.CreateUniqueTempDir()); base::Thread db_thread("dbthread"); ASSERT_TRUE(db_thread.Start()); - std::unique_ptr<ProtoDatabaseImpl<TestProto>> db( - new ProtoDatabaseImpl<TestProto>(db_thread.task_runner())); + std::unique_ptr<UniqueProtoDatabase<TestProto>> db( + new UniqueProtoDatabase<TestProto>(db_thread.task_runner())); auto expect_init_success = - base::Bind([](bool success) { EXPECT_TRUE(success); }); + base::BindOnce([](bool success) { EXPECT_TRUE(success); }); db->Init(kTestLevelDBClientName, temp_dir.GetPath(), CreateSimpleOptions(), - expect_init_success); + std::move(expect_init_success)); base::RunLoop run_update_entries; - auto expect_update_success = base::Bind( - [](base::Closure signal, bool success) { + auto expect_update_success = base::BindOnce( + [](base::OnceClosure signal, bool success) { EXPECT_TRUE(success); - signal.Run(); + std::move(signal).Run(); }, run_update_entries.QuitClosure()); TestProto test_proto; test_proto.set_data("some data"); ProtoDatabase<TestProto>::KeyEntryVector data_set( - {{"0", test_proto}, {"1", test_proto}, {"2", test_proto}}); + {{"0", test_proto}, {"1", test_proto}, {"2", test_proto}}); db->UpdateEntries( std::make_unique<ProtoDatabase<TestProto>::KeyEntryVector>(data_set), - std::make_unique<std::vector<std::string>>(), expect_update_success); + std::make_unique<std::vector<std::string>>(), + std::move(expect_update_success)); run_update_entries.Run(); base::RunLoop run_load_keys; - auto verify_loaded_keys = base::Bind( - [](base::Closure signal, bool success, + auto verify_loaded_keys = base::BindOnce( + [](base::OnceClosure signal, bool success, std::unique_ptr<std::vector<std::string>> keys) { EXPECT_TRUE(success); EXPECT_THAT(*keys, UnorderedElementsAre("0", "1", "2")); - signal.Run(); + std::move(signal).Run(); }, run_load_keys.QuitClosure()); - db->LoadKeys(verify_loaded_keys); + db->LoadKeys(std::move(verify_loaded_keys)); run_load_keys.Run(); // Shutdown database. @@ -454,16 +455,16 @@ run_destruction.Run(); } -TEST_F(ProtoDatabaseImplTest, TestDBGetNotFound) { +TEST_F(UniqueProtoDatabaseTest, TestDBGetNotFound) { base::FilePath path(FILE_PATH_LITERAL("/fake/path")); - MockDB* mock_db = new MockDB(); + auto mock_db = std::make_unique<MockDB>(); MockDatabaseCaller caller; EntryMap model = GetSmallModel(); EXPECT_CALL(*mock_db, Init(_, options_)); EXPECT_CALL(caller, InitCallback(_)); - db_->InitWithDatabase(base::WrapUnique(mock_db), path, CreateSimpleOptions(), + db_->InitWithDatabase(mock_db.get(), path, CreateSimpleOptions(), base::BindOnce(&MockDatabaseCaller::InitCallback, base::Unretained(&caller))); @@ -477,16 +478,16 @@ base::RunLoop().RunUntilIdle(); } -TEST_F(ProtoDatabaseImplTest, TestDBGetFailure) { +TEST_F(UniqueProtoDatabaseTest, TestDBGetFailure) { base::FilePath path(FILE_PATH_LITERAL("/fake/path")); - MockDB* mock_db = new MockDB(); + auto mock_db = std::make_unique<MockDB>(); MockDatabaseCaller caller; EntryMap model = GetSmallModel(); EXPECT_CALL(*mock_db, Init(_, options_)); EXPECT_CALL(caller, InitCallback(_)); - db_->InitWithDatabase(base::WrapUnique(mock_db), path, CreateSimpleOptions(), + db_->InitWithDatabase(mock_db.get(), path, CreateSimpleOptions(), base::BindOnce(&MockDatabaseCaller::InitCallback, base::Unretained(&caller))); @@ -519,19 +520,19 @@ return true; } -// Test that ProtoDatabaseImpl calls Save on the underlying database with the +// Test that UniqueProtoDatabase calls Save on the underlying database with the // correct entries to save and that the caller's SaveCallback is called with the // correct success value. -TEST_F(ProtoDatabaseImplTest, TestDBSaveSuccess) { +TEST_F(UniqueProtoDatabaseTest, TestDBSaveSuccess) { base::FilePath path(FILE_PATH_LITERAL("/fake/path")); - MockDB* mock_db = new MockDB(); + auto mock_db = std::make_unique<MockDB>(); MockDatabaseCaller caller; EntryMap model = GetSmallModel(); EXPECT_CALL(*mock_db, Init(_, options_)); EXPECT_CALL(caller, InitCallback(_)); - db_->InitWithDatabase(base::WrapUnique(mock_db), path, CreateSimpleOptions(), + db_->InitWithDatabase(mock_db.get(), path, CreateSimpleOptions(), base::BindOnce(&MockDatabaseCaller::InitCallback, base::Unretained(&caller))); @@ -551,10 +552,10 @@ base::RunLoop().RunUntilIdle(); } -TEST_F(ProtoDatabaseImplTest, TestDBSaveFailure) { +TEST_F(UniqueProtoDatabaseTest, TestDBSaveFailure) { base::FilePath path(FILE_PATH_LITERAL("/fake/path")); - MockDB* mock_db = new MockDB(); + auto mock_db = std::make_unique<MockDB>(); MockDatabaseCaller caller; std::unique_ptr<ProtoDatabase<TestProto>::KeyEntryVector> entries( new ProtoDatabase<TestProto>::KeyEntryVector()); @@ -562,7 +563,7 @@ EXPECT_CALL(*mock_db, Init(_, options_)); EXPECT_CALL(caller, InitCallback(_)); - db_->InitWithDatabase(base::WrapUnique(mock_db), path, CreateSimpleOptions(), + db_->InitWithDatabase(mock_db.get(), path, CreateSimpleOptions(), base::BindOnce(&MockDatabaseCaller::InitCallback, base::Unretained(&caller))); @@ -575,19 +576,19 @@ base::RunLoop().RunUntilIdle(); } -// Test that ProtoDatabaseImpl calls Save on the underlying database with the +// Test that UniqueProtoDatabase calls Save on the underlying database with the // correct entries to delete and that the caller's SaveCallback is called with // the correct success value. -TEST_F(ProtoDatabaseImplTest, TestDBRemoveSuccess) { +TEST_F(UniqueProtoDatabaseTest, TestDBRemoveSuccess) { base::FilePath path(FILE_PATH_LITERAL("/fake/path")); - MockDB* mock_db = new MockDB(); + auto mock_db = std::make_unique<MockDB>(); MockDatabaseCaller caller; EntryMap model = GetSmallModel(); EXPECT_CALL(*mock_db, Init(_, options_)); EXPECT_CALL(caller, InitCallback(_)); - db_->InitWithDatabase(base::WrapUnique(mock_db), path, CreateSimpleOptions(), + db_->InitWithDatabase(mock_db.get(), path, CreateSimpleOptions(), base::BindOnce(&MockDatabaseCaller::InitCallback, base::Unretained(&caller))); @@ -607,10 +608,10 @@ base::RunLoop().RunUntilIdle(); } -TEST_F(ProtoDatabaseImplTest, TestDBRemoveFailure) { +TEST_F(UniqueProtoDatabaseTest, TestDBRemoveFailure) { base::FilePath path(FILE_PATH_LITERAL("/fake/path")); - MockDB* mock_db = new MockDB(); + auto mock_db = std::make_unique<MockDB>(); MockDatabaseCaller caller; std::unique_ptr<ProtoDatabase<TestProto>::KeyEntryVector> entries( new ProtoDatabase<TestProto>::KeyEntryVector()); @@ -618,7 +619,7 @@ EXPECT_CALL(*mock_db, Init(_, options_)); EXPECT_CALL(caller, InitCallback(_)); - db_->InitWithDatabase(base::WrapUnique(mock_db), path, CreateSimpleOptions(), + db_->InitWithDatabase(mock_db.get(), path, CreateSimpleOptions(), base::BindOnce(&MockDatabaseCaller::InitCallback, base::Unretained(&caller))); @@ -633,7 +634,7 @@ // This tests that normal usage of the real database does not cause any // threading violations. -TEST(ProtoDatabaseImplThreadingTest, TestDBDestruction) { +TEST(UniqueProtoDatabaseThreadingTest, TestDBDestruction) { base::MessageLoop main_loop; ScopedTempDir temp_dir; @@ -642,8 +643,8 @@ base::Thread db_thread("dbthread"); ASSERT_TRUE(db_thread.Start()); - std::unique_ptr<ProtoDatabaseImpl<TestProto>> db( - new ProtoDatabaseImpl<TestProto>(db_thread.task_runner())); + std::unique_ptr<UniqueProtoDatabase<TestProto>> db( + new UniqueProtoDatabase<TestProto>(db_thread.task_runner())); MockDatabaseCaller caller; EXPECT_CALL(caller, InitCallback(_)); @@ -661,7 +662,7 @@ // This tests that normal usage of the real database does not cause any // threading violations. -TEST(ProtoDatabaseImplThreadingTest, TestDBDestroy) { +TEST(UniqueProtoDatabaseThreadingTest, TestDBDestroy) { base::MessageLoop main_loop; ScopedTempDir temp_dir; @@ -670,8 +671,8 @@ base::Thread db_thread("dbthread"); ASSERT_TRUE(db_thread.Start()); - std::unique_ptr<ProtoDatabaseImpl<TestProto>> db( - new ProtoDatabaseImpl<TestProto>(db_thread.task_runner())); + std::unique_ptr<UniqueProtoDatabase<TestProto>> db( + new UniqueProtoDatabase<TestProto>(db_thread.task_runner())); MockDatabaseCaller caller; EXPECT_CALL(caller, InitCallback(_)); @@ -734,15 +735,15 @@ ExpectEntryPointersEquals(model, loaded_protos); } -TEST_F(ProtoDatabaseImplLevelDBTest, TestDBSaveAndLoad) { +TEST_F(UniqueProtoDatabaseLevelDBTest, TestDBSaveAndLoad) { TestLevelDBSaveAndLoad(false); } -TEST_F(ProtoDatabaseImplLevelDBTest, TestDBCloseAndReopen) { +TEST_F(UniqueProtoDatabaseLevelDBTest, TestDBCloseAndReopen) { TestLevelDBSaveAndLoad(true); } -TEST_F(ProtoDatabaseImplLevelDBTest, TestDBLoadWithFilter) { +TEST_F(UniqueProtoDatabaseLevelDBTest, TestDBLoadWithFilter) { ScopedTempDir temp_dir; ASSERT_TRUE(temp_dir.CreateUniqueTempDir()); @@ -770,7 +771,7 @@ EXPECT_EQ(entry.SerializeAsString(), model["0"].SerializeAsString()); } -TEST_F(ProtoDatabaseImplLevelDBTest, TestDBLoadKeysAndEntries) { +TEST_F(UniqueProtoDatabaseLevelDBTest, TestDBLoadKeysAndEntries) { ScopedTempDir temp_dir; ASSERT_TRUE(temp_dir.CreateUniqueTempDir()); @@ -799,7 +800,7 @@ } } -TEST_F(ProtoDatabaseImplLevelDBTest, TestDBInitFail) { +TEST_F(UniqueProtoDatabaseLevelDBTest, TestDBInitFail) { ScopedTempDir temp_dir; ASSERT_TRUE(temp_dir.CreateUniqueTempDir()); @@ -816,7 +817,7 @@ EXPECT_FALSE(db->Save(save_entries, remove_keys)); } -TEST_F(ProtoDatabaseImplLevelDBTest, TestMemoryDatabase) { +TEST_F(UniqueProtoDatabaseLevelDBTest, TestMemoryDatabase) { std::unique_ptr<LevelDB> db(new LevelDB(kTestLevelDBClientName)); std::vector<std::string> load_entries; @@ -837,7 +838,7 @@ EXPECT_EQ(1u, second_load_entries.size()); } -TEST_F(ProtoDatabaseImplLevelDBTest, TestCorruptDBReset) { +TEST_F(UniqueProtoDatabaseLevelDBTest, TestCorruptDBReset) { ScopedTempDir temp_dir; ASSERT_TRUE(temp_dir.CreateUniqueTempDir()); @@ -867,7 +868,7 @@ ASSERT_FALSE(found); } -TEST_F(ProtoDatabaseImplLevelDBTest, TestDBDeleteWithFilter) { +TEST_F(UniqueProtoDatabaseLevelDBTest, TestDBDeleteWithFilter) { ScopedTempDir temp_dir; ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
diff --git a/components/omnibox/browser/BUILD.gn b/components/omnibox/browser/BUILD.gn index 71d1ae47..09696c5 100644 --- a/components/omnibox/browser/BUILD.gn +++ b/components/omnibox/browser/BUILD.gn
@@ -28,6 +28,7 @@ "answer_sunrise.icon", "answer_when_is.icon", "drive_docs.icon", + "drive_forms.icon", "drive_logo.icon", "drive_sheets.icon", "drive_slides.icon",
diff --git a/components/omnibox/browser/autocomplete_match.cc b/components/omnibox/browser/autocomplete_match.cc index c671b07..c989a3a 100644 --- a/components/omnibox/browser/autocomplete_match.cc +++ b/components/omnibox/browser/autocomplete_match.cc
@@ -248,6 +248,8 @@ switch (document_type) { case DocumentType::DRIVE_DOCS: return omnibox::kDriveDocsIcon; + case DocumentType::DRIVE_FORMS: + return omnibox::kDriveFormsIcon; case DocumentType::DRIVE_SHEETS: return omnibox::kDriveSheetsIcon; case DocumentType::DRIVE_SLIDES:
diff --git a/components/omnibox/browser/autocomplete_match.h b/components/omnibox/browser/autocomplete_match.h index a2c987d..65946ace 100644 --- a/components/omnibox/browser/autocomplete_match.h +++ b/components/omnibox/browser/autocomplete_match.h
@@ -117,6 +117,7 @@ enum class DocumentType { NONE, DRIVE_DOCS, + DRIVE_FORMS, DRIVE_SHEETS, DRIVE_SLIDES, DRIVE_OTHER
diff --git a/components/omnibox/browser/document_provider.cc b/components/omnibox/browser/document_provider.cc index 11c14e74..66aa66e 100644 --- a/components/omnibox/browser/document_provider.cc +++ b/components/omnibox/browser/document_provider.cc
@@ -58,6 +58,7 @@ // MIME types sent by the server for different document types. const char kDocumentMimetype[] = "application/vnd.google-apps.document"; +const char kFormMimetype[] = "application/vnd.google-apps.form"; const char kSpreadsheetMimetype[] = "application/vnd.google-apps.spreadsheet"; const char kPresentationMimetype[] = "application/vnd.google-apps.presentation"; @@ -332,6 +333,8 @@ base::string16 GetProductDescriptionString(const std::string& mimetype) { if (mimetype == kDocumentMimetype) return l10n_util::GetStringUTF16(IDS_DRIVE_SUGGESTION_DOCUMENT); + if (mimetype == kFormMimetype) + return l10n_util::GetStringUTF16(IDS_DRIVE_SUGGESTION_FORM); if (mimetype == kSpreadsheetMimetype) return l10n_util::GetStringUTF16(IDS_DRIVE_SUGGESTION_SPREADSHEET); if (mimetype == kPresentationMimetype) @@ -426,6 +429,8 @@ if (metadata->GetString("mimeType", &mimetype)) { if (mimetype == kDocumentMimetype) { match.document_type = AutocompleteMatch::DocumentType::DRIVE_DOCS; + } else if (mimetype == kFormMimetype) { + match.document_type = AutocompleteMatch::DocumentType::DRIVE_FORMS; } else if (mimetype == kSpreadsheetMimetype) { match.document_type = AutocompleteMatch::DocumentType::DRIVE_SHEETS; } else if (mimetype == kPresentationMimetype) {
diff --git a/components/omnibox/browser/vector_icons/drive_forms.icon b/components/omnibox/browser/vector_icons/drive_forms.icon new file mode 100644 index 0000000..f174d9a --- /dev/null +++ b/components/omnibox/browser/vector_icons/drive_forms.icon
@@ -0,0 +1,46 @@ +// 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. + +CANVAS_DIMENSIONS, 18, +PATH_COLOR_ARGB, 0xFF, 0x67, 0x3A, 0xB7, +MOVE_TO, 16, 0, +H_LINE_TO, 2, +CUBIC_TO, 0.9f, 0, 0, 0.9f, 0, 2, +R_V_LINE_TO, 14, +R_CUBIC_TO, 0, 1.1f, 0.9f, 2, 2, 2, +R_H_LINE_TO, 14, +R_CUBIC_TO, 1.1f, 0, 2, -0.9f, 2, -2, +V_LINE_TO, 2, +R_CUBIC_TO, 0, -1.1f, -0.9f, -2, -2, -2, +CLOSE, +MOVE_TO, 6, 14, +H_LINE_TO, 4, +R_V_LINE_TO, -2, +R_H_LINE_TO, 2, +CLOSE, +R_MOVE_TO, 0, -4, +H_LINE_TO, 4, +V_LINE_TO, 8, +R_H_LINE_TO, 2, +CLOSE, +R_MOVE_TO, 0, -4, +H_LINE_TO, 4, +V_LINE_TO, 4, +R_H_LINE_TO, 2, +CLOSE, +R_MOVE_TO, 8, 8, +H_LINE_TO, 7, +R_V_LINE_TO, -2, +R_H_LINE_TO, 7, +CLOSE, +R_MOVE_TO, 0, -4, +H_LINE_TO, 7, +V_LINE_TO, 8, +R_H_LINE_TO, 7, +CLOSE, +R_MOVE_TO, 0, -4, +H_LINE_TO, 7, +V_LINE_TO, 4, +R_H_LINE_TO, 7, +CLOSE \ No newline at end of file
diff --git a/components/omnibox_strings.grdp b/components/omnibox_strings.grdp index 50c6ac4b..97a2b9ab 100644 --- a/components/omnibox_strings.grdp +++ b/components/omnibox_strings.grdp
@@ -61,6 +61,9 @@ <message name="IDS_DRIVE_SUGGESTION_DOCUMENT" desc="Google Docs product name, for use in omnibox Docs result descriptions."> Google Docs </message> + <message name="IDS_DRIVE_SUGGESTION_FORM" desc="Google Docs product name, for use in omnibox Form result descriptions."> + Google Forms + </message> <message name="IDS_DRIVE_SUGGESTION_SPREADSHEET" desc="Google Sheets product name, for use in omnibox Sheets result descriptions."> Google Sheets </message>
diff --git a/components/password_manager/core/browser/new_password_form_manager.cc b/components/password_manager/core/browser/new_password_form_manager.cc index fe8f2cd7..310e771 100644 --- a/components/password_manager/core/browser/new_password_form_manager.cc +++ b/components/password_manager/core/browser/new_password_form_manager.cc
@@ -401,12 +401,17 @@ const PasswordManagerDriver* driver) { if (!DoesManage(submitted_form, driver)) return false; - submitted_form_ = submitted_form; - is_submitted_ = true; parsed_submitted_form_ = - ParseFormAndMakeLogging(submitted_form_, FormDataParser::Mode::kSaving); + ParseFormAndMakeLogging(submitted_form, FormDataParser::Mode::kSaving); + RecordMetricOnReadonly(parser_.readonly_status(), !!parsed_submitted_form_, FormDataParser::Mode::kSaving); + if (!parsed_submitted_form_) + return false; + + submitted_form_ = submitted_form; + is_submitted_ = true; + CreatePendingCredentials(); return true; }
diff --git a/components/password_manager/core/browser/new_password_form_manager_unittest.cc b/components/password_manager/core/browser/new_password_form_manager_unittest.cc index 00f32a4..53b1544 100644 --- a/components/password_manager/core/browser/new_password_form_manager_unittest.cc +++ b/components/password_manager/core/browser/new_password_form_manager_unittest.cc
@@ -314,10 +314,10 @@ TEST_F(NewPasswordFormManagerTest, SetSubmitted) { EXPECT_FALSE(form_manager_->is_submitted()); EXPECT_TRUE( - form_manager_->SetSubmittedFormIfIsManaged(observed_form_, &driver_)); + form_manager_->SetSubmittedFormIfIsManaged(submitted_form_, &driver_)); EXPECT_TRUE(form_manager_->is_submitted()); - FormData another_form = observed_form_; + FormData another_form = submitted_form_; another_form.name += ASCIIToUTF16("1"); // |another_form| is managed because the same |unique_renderer_id| as // |observed_form_|. @@ -338,6 +338,14 @@ EXPECT_FALSE( form_manager_->SetSubmittedFormIfIsManaged(observed_form_, nullptr)); EXPECT_FALSE(form_manager_->is_submitted()); + + // Check if the subbmitted form can not be parsed then form manager does not + // became submitted. + FormData malformed_form = submitted_form_; + malformed_form.fields.clear(); + EXPECT_FALSE( + form_manager_->SetSubmittedFormIfIsManaged(malformed_form, &driver_)); + EXPECT_FALSE(form_manager_->is_submitted()); } // Tests that when NewPasswordFormManager receives saved matches it waits for @@ -937,9 +945,9 @@ ukm::TestAutoSetUkmRecorder test_ukm_recorder; fetcher_->SetNonFederated({&saved_match_}, 0u); - FormData malformed_form = observed_form_; + FormData malformed_form = submitted_form_; malformed_form.fields.clear(); - EXPECT_TRUE( + EXPECT_FALSE( form_manager_->SetSubmittedFormIfIsManaged(malformed_form, &driver_)); // Destroy the form manager to destroy the UKM recorder it owns. The recorder
diff --git a/components/password_manager/core/browser/password_form_manager_unittest.cc b/components/password_manager/core/browser/password_form_manager_unittest.cc index c9872b0..9cd0d02 100644 --- a/components/password_manager/core/browser/password_form_manager_unittest.cc +++ b/components/password_manager/core/browser/password_form_manager_unittest.cc
@@ -89,6 +89,8 @@ PasswordForm CreateMinimalCrowdsourcableForm( const PasswordForm& observed_form) { PasswordForm form = observed_form; + form.origin = GURL("https://www.foo.com/login"); + form.form_data.origin = form.origin; autofill::FormFieldData field; field.name = ASCIIToUTF16("email"); field.form_control_type = "text"; @@ -4514,6 +4516,9 @@ // User submits credentials for the observed form. PasswordForm submitted_form = *observed_form(); + submitted_form.origin = GURL("https://www.foo.com/login"); + submitted_form.form_data.origin = submitted_form.origin; + autofill::FormFieldData field; field.name = ASCIIToUTF16("password1"); field.form_control_type = "password"; @@ -4603,6 +4608,8 @@ observed_form()->password_element = ASCIIToUTF16("password"); // User submits credentials for the observed form. PasswordForm submitted_form = *observed_form(); + submitted_form.origin = GURL("https://www.foo.com/login"); + submitted_form.form_data.origin = submitted_form.origin; submitted_form.username_value = saved_match()->username_value; submitted_form.password_value = saved_match()->password_value; submitted_form.form_data.fields[0].value = submitted_form.username_value;
diff --git a/components/password_manager/core/browser/password_store.cc b/components/password_manager/core/browser/password_store.cc index d7db1ac..9d359ce2 100644 --- a/components/password_manager/core/browser/password_store.cc +++ b/components/password_manager/core/browser/password_store.cc
@@ -13,6 +13,7 @@ #include "base/debug/dump_without_crashing.h" #include "base/location.h" #include "base/macros.h" +#include "base/metrics/histogram_functions.h" #include "base/metrics/histogram_macros.h" #include "base/stl_util.h" #include "base/task/post_task.h" @@ -506,6 +507,7 @@ void PasswordStore::GetLoginsImpl(const FormDigest& form, std::unique_ptr<GetLoginsRequest> request) { + SCOPED_UMA_HISTOGRAM_TIMER("PasswordManager.StorePerformance.GetLogins"); request->NotifyConsumerWithResults(FillMatchingLogins(form)); } @@ -648,16 +650,19 @@ } void PasswordStore::AddLoginInternal(const PasswordForm& form) { + SCOPED_UMA_HISTOGRAM_TIMER("PasswordManager.StorePerformance.AddLogin"); PasswordStoreChangeList changes = AddLoginImpl(form); NotifyLoginsChanged(changes); } void PasswordStore::UpdateLoginInternal(const PasswordForm& form) { + SCOPED_UMA_HISTOGRAM_TIMER("PasswordManager.StorePerformance.UpdateLogin"); PasswordStoreChangeList changes = UpdateLoginImpl(form); NotifyLoginsChanged(changes); } void PasswordStore::RemoveLoginInternal(const PasswordForm& form) { + SCOPED_UMA_HISTOGRAM_TIMER("PasswordManager.StorePerformance.RemoveLogin"); PasswordStoreChangeList changes = RemoveLoginImpl(form); NotifyLoginsChanged(changes); } @@ -844,6 +849,7 @@ std::unique_ptr<PasswordForm> PasswordStore::GetLoginImpl( const PasswordForm& primary_key) { + SCOPED_UMA_HISTOGRAM_TIMER("PasswordManager.StorePerformance.GetLogin"); DCHECK(background_task_runner_->RunsTasksInCurrentSequence()); std::vector<std::unique_ptr<PasswordForm>> candidates( FillMatchingLogins(FormDigest(primary_key)));
diff --git a/components/policy/resources/policy_templates.json b/components/policy/resources/policy_templates.json index 4963a29..407ca26 100644 --- a/components/policy/resources/policy_templates.json +++ b/components/policy/resources/policy_templates.json
@@ -671,6 +671,7 @@ 'policies': [ 'NetworkFileSharesAllowed', 'NetBiosShareDiscoveryEnabled', + 'NTLMShareAuthenticationEnabled', ], }, { @@ -13445,6 +13446,27 @@ This policy is meant to be used together with the "Always on VPN" feature, that lets the admin decide to establish a VPN connection on boot.''', }, + { + 'id': 489, + 'name': 'NTLMShareAuthenticationEnabled', + 'type': 'main', + 'schema': {'type': 'boolean', }, + 'tags': [], + 'features': { + 'dynamic_refresh': False, + 'per_profile': True, + }, + 'supported_on': ['chrome_os:71-'], + 'caption': '''Controls enabling NTLM as an authentication protocol for SMB mounts''', + 'example_value': True, + 'default_for_enterprise_users': False, + 'desc': '''This policy controls whether the Network File Shares feature for <ph name="PRODUCT_NAME">$2<ex>Google Chrome OS</ex></ph> will use NTLM for authentication. + + When this policy is set to True, NTLM will be used for authentication to SMB shares if necessary. + When this policy is set to False, NTLM authentication to SMB shares will be disabled. + + If the policy is left not set, the default is disabled for enterprise-managed users and enabled for non-managed users.''', + }, ], 'messages': { @@ -13586,5 +13608,5 @@ }, 'placeholders': [], 'deleted_policy_ids': [412], - 'highest_id_currently_used': 488 + 'highest_id_currently_used': 489 }
diff --git a/components/previews/content/previews_content_util.cc b/components/previews/content/previews_content_util.cc index 4bd2a65..31757b7 100644 --- a/components/previews/content/previews_content_util.cc +++ b/components/previews/content/previews_content_util.cc
@@ -23,6 +23,9 @@ previews::PreviewsDecider* previews_decider) { content::PreviewsState previews_state = content::PREVIEWS_UNSPECIFIED; + // Record whether the hint cache has a matching entry for this pre-commit URL. + previews_decider->LogHintCacheMatch(url, false /* is_committed */); + if (!previews::params::ArePreviewsAllowed()) { return previews_state; } @@ -75,6 +78,9 @@ const previews::PreviewsDecider* previews_decider) { bool is_https = url.SchemeIs(url::kHttpsScheme); + // Record whether the hint cache has a matching entry for this committed URL. + previews_decider->LogHintCacheMatch(url, true /* is_committed */); + // Check if an offline preview was actually served. if (previews_data && previews_data->offline_preview_used()) { DCHECK(previews_state & content::OFFLINE_PAGE_ON);
diff --git a/components/previews/content/previews_content_util_unittest.cc b/components/previews/content/previews_content_util_unittest.cc index b6efc2b3..c2a8a82 100644 --- a/components/previews/content/previews_content_util_unittest.cc +++ b/components/previews/content/previews_content_util_unittest.cc
@@ -55,6 +55,8 @@ void LoadResourceHints(const GURL& url) override {} + void LogHintCacheMatch(const GURL& url, bool is_committed) const override {} + private: bool IsEnabled(PreviewsType type) const { switch (type) {
diff --git a/components/previews/content/previews_decider_impl.cc b/components/previews/content/previews_decider_impl.cc index 41826e2c..fc9c3d8e 100644 --- a/components/previews/content/previews_decider_impl.cc +++ b/components/previews/content/previews_decider_impl.cc
@@ -406,6 +406,15 @@ weak_factory_.GetWeakPtr())); } +void PreviewsDeciderImpl::LogHintCacheMatch(const GURL& url, + bool is_committed) const { + if (!previews_opt_guide_) + return; + + previews_opt_guide_->LogHintCacheMatch(url, is_committed, + effective_connection_type_); +} + bool PreviewsDeciderImpl::IsURLAllowedForPreview( PreviewsUserData* previews_data, const GURL& url,
diff --git a/components/previews/content/previews_decider_impl.h b/components/previews/content/previews_decider_impl.h index 16c3f0c..8e2dba02 100644 --- a/components/previews/content/previews_decider_impl.h +++ b/components/previews/content/previews_decider_impl.h
@@ -131,6 +131,8 @@ void LoadResourceHints(const GURL& url) override; + void LogHintCacheMatch(const GURL& url, bool is_committed) const override; + // Generates a page ID that is guaranteed to be unique from any other page ID // generated in this browser session. Also, guaranteed to be non-zero. uint64_t GeneratePageId();
diff --git a/components/previews/content/previews_hints.cc b/components/previews/content/previews_hints.cc index 4cd2ab55..41c353f 100644 --- a/components/previews/content/previews_hints.cc +++ b/components/previews/content/previews_hints.cc
@@ -518,4 +518,35 @@ return hint_cache_->HasHint(url.host()); } +void PreviewsHints::LogHintCacheMatch(const GURL& url, + bool is_committed, + net::EffectiveConnectionType ect) const { + if (!hint_cache_) + return; + + if (hint_cache_->HasHint(url.host())) { + if (!is_committed) { + UMA_HISTOGRAM_ENUMERATION( + "Previews.OptimizationGuide.HintCache.HasHint.BeforeCommit", ect, + net::EffectiveConnectionType::EFFECTIVE_CONNECTION_TYPE_LAST); + } else { + UMA_HISTOGRAM_ENUMERATION( + "Previews.OptimizationGuide.HintCache.HasHint.AtCommit", ect, + net::EffectiveConnectionType::EFFECTIVE_CONNECTION_TYPE_LAST); + if (hint_cache_->IsHintLoaded(url.host())) { + UMA_HISTOGRAM_ENUMERATION( + "Previews.OptimizationGuide.HintCache.HostMatch.AtCommit", ect, + net::EffectiveConnectionType::EFFECTIVE_CONNECTION_TYPE_LAST); + const optimization_guide::proto::Hint* hint = + hint_cache_->GetHint(url.host()); + if (FindPageHint(url, *hint) != nullptr) { + UMA_HISTOGRAM_ENUMERATION( + "Previews.OptimizationGuide.HintCache.PageMatch.AtCommit", ect, + net::EffectiveConnectionType::EFFECTIVE_CONNECTION_TYPE_LAST); + } + } + } + } +} + } // namespace previews
diff --git a/components/previews/content/previews_hints.h b/components/previews/content/previews_hints.h index 9ade6551..92165af 100644 --- a/components/previews/content/previews_hints.h +++ b/components/previews/content/previews_hints.h
@@ -17,6 +17,7 @@ #include "components/previews/content/previews_user_data.h" #include "components/previews/core/host_filter.h" #include "components/url_matcher/url_matcher.h" +#include "net/nqe/effective_connection_type.h" class GURL; @@ -65,6 +66,13 @@ bool MaybeLoadOptimizationHints(const GURL& url, HintLoadedCallback callback) const; + // Logs UMA for whether the HintCache has a matching Hint and also a matching + // PageHint for |url|. Records the client's current |ect| as well. This is + // useful for measuring the effectiveness of the page hints provided by Cacao. + void LogHintCacheMatch(const GURL& url, + bool is_committed, + net::EffectiveConnectionType ect) const; + private: friend class PreviewsHintsTest;
diff --git a/components/previews/content/previews_hints_unittest.cc b/components/previews/content/previews_hints_unittest.cc index f7ca4b2..c86fe7a 100644 --- a/components/previews/content/previews_hints_unittest.cc +++ b/components/previews/content/previews_hints_unittest.cc
@@ -105,6 +105,66 @@ GURL("https://www.foo.org/bar/three.jpg"), hint1)); } +TEST_F(PreviewsHintsTest, LogHintCacheMatch) { + base::test::ScopedFeatureList scoped_list; + scoped_list.InitAndEnableFeature(features::kResourceLoadingHints); + + optimization_guide::proto::Configuration config; + optimization_guide::proto::Hint* hint1 = config.add_hints(); + hint1->set_key("somedomain.org"); + hint1->set_key_representation(optimization_guide::proto::HOST_SUFFIX); + optimization_guide::proto::PageHint* page_hint1 = hint1->add_page_hints(); + page_hint1->set_page_pattern("/news/"); + optimization_guide::proto::Optimization* optimization1 = + page_hint1->add_whitelisted_optimizations(); + optimization1->set_optimization_type( + optimization_guide::proto::RESOURCE_LOADING); + optimization_guide::proto::ResourceLoadingHint* resource_loading_hint1 = + optimization1->add_resource_loading_hints(); + resource_loading_hint1->set_loading_optimization_type( + optimization_guide::proto::LOADING_BLOCK_RESOURCE); + resource_loading_hint1->set_resource_pattern("news_cruft.js"); + ParseConfig(config); + + base::HistogramTester histogram_tester; + + // First verify no histogram counts for non-matching URL host. + previews_hints()->LogHintCacheMatch( + GURL("https://someotherdomain.com/news/story.html"), + false /* is_committed */, net::EFFECTIVE_CONNECTION_TYPE_3G); + previews_hints()->LogHintCacheMatch( + GURL("https://someotherdomain.com/news/story2.html"), + true /* is_committed */, net::EFFECTIVE_CONNECTION_TYPE_4G); + histogram_tester.ExpectTotalCount( + "Previews.OptimizationGuide.HintCache.HasHint.BeforeCommit", 0); + histogram_tester.ExpectTotalCount( + "Previews.OptimizationGuide.HintCache.HasHint.AtCommit", 0); + histogram_tester.ExpectTotalCount( + "Previews.OptimizationGuide.HintCache.HintLoaded.AtCommit", 0); + histogram_tester.ExpectTotalCount( + "Previews.OptimizationGuide.HintCache.PageMatch.AtCommit", 0); + + // Now verify do have histogram counts for matching URL host. + previews_hints()->LogHintCacheMatch( + GURL("https://somedomain.org/news/story.html"), false /* is_committed */, + net::EFFECTIVE_CONNECTION_TYPE_3G); + previews_hints()->LogHintCacheMatch( + GURL("https://somedomain.org/news/story2.html"), true /* is_committed */, + net::EFFECTIVE_CONNECTION_TYPE_4G); + histogram_tester.ExpectBucketCount( + "Previews.OptimizationGuide.HintCache.HasHint.BeforeCommit", + 4 /* EFFECTIVE_CONNECTION_TYPE_3G */, 1); + histogram_tester.ExpectBucketCount( + "Previews.OptimizationGuide.HintCache.HasHint.AtCommit", + 5 /* EFFECTIVE_CONNECTION_TYPE_4G */, 1); + histogram_tester.ExpectBucketCount( + "Previews.OptimizationGuide.HintCache.HostMatch.AtCommit", + 5 /* EFFECTIVE_CONNECTION_TYPE_4G */, 1); + histogram_tester.ExpectBucketCount( + "Previews.OptimizationGuide.HintCache.PageMatch.AtCommit", + 5 /* EFFECTIVE_CONNECTION_TYPE_4G */, 1); +} + TEST_F(PreviewsHintsTest, IsBlacklisted) { std::unique_ptr<PreviewsHints> previews_hints = PreviewsHints::CreateForTesting(
diff --git a/components/previews/content/previews_optimization_guide.cc b/components/previews/content/previews_optimization_guide.cc index ba8e2d9..7fb4810 100644 --- a/components/previews/content/previews_optimization_guide.cc +++ b/components/previews/content/previews_optimization_guide.cc
@@ -104,6 +104,16 @@ std::move(callback), url)); } +void PreviewsOptimizationGuide::LogHintCacheMatch( + const GURL& url, + bool is_committed, + net::EffectiveConnectionType ect) const { + if (!hints_) + return; + + hints_->LogHintCacheMatch(url, is_committed, ect); +} + void PreviewsOptimizationGuide::OnHintsProcessed( const optimization_guide::proto::Configuration& config, const optimization_guide::ComponentInfo& info) {
diff --git a/components/previews/content/previews_optimization_guide.h b/components/previews/content/previews_optimization_guide.h index fe988ef..9603f03d 100644 --- a/components/previews/content/previews_optimization_guide.h +++ b/components/previews/content/previews_optimization_guide.h
@@ -64,6 +64,13 @@ bool MaybeLoadOptimizationHints(const GURL& url, ResourceLoadingHintsCallback callback); + // Logs UMA for whether the OptimizationGuide HintCache has a matching Hint + // guidance for |url|. This is useful for measuring the effectiveness of the + // page hints provided by Cacao. + void LogHintCacheMatch(const GURL& url, + bool is_committed, + net::EffectiveConnectionType ect) const; + // optimization_guide::OptimizationGuideServiceObserver implementation: void OnHintsProcessed( const optimization_guide::proto::Configuration& config,
diff --git a/components/previews/core/previews_decider.h b/components/previews/core/previews_decider.h index 2e89162c..a721654 100644 --- a/components/previews/core/previews_decider.h +++ b/components/previews/core/previews_decider.h
@@ -53,6 +53,11 @@ // Requests that any applicable detailed resource hints be loaded. virtual void LoadResourceHints(const GURL& url) = 0; + // Logs UMA for whether the OptimizationGuide HintCache has a matching Hint + // guidance for |url|. This is useful for measuring the effectiveness of the + // page hints provided by Cacao. + virtual void LogHintCacheMatch(const GURL& url, bool is_committed) const = 0; + protected: PreviewsDecider() {} virtual ~PreviewsDecider() {}
diff --git a/components/previews/core/test_previews_decider.cc b/components/previews/core/test_previews_decider.cc index 09e41b0d..a6f31b328 100644 --- a/components/previews/core/test_previews_decider.cc +++ b/components/previews/core/test_previews_decider.cc
@@ -38,4 +38,7 @@ void TestPreviewsDecider::LoadResourceHints(const GURL& url) {} +void TestPreviewsDecider::LogHintCacheMatch(const GURL& url, + bool is_committed) const {} + } // namespace previews
diff --git a/components/previews/core/test_previews_decider.h b/components/previews/core/test_previews_decider.h index 77dc8fb..577829d8 100644 --- a/components/previews/core/test_previews_decider.h +++ b/components/previews/core/test_previews_decider.h
@@ -32,6 +32,7 @@ const GURL& url, PreviewsType type) const override; void LoadResourceHints(const GURL& url) override; + void LogHintCacheMatch(const GURL& url, bool is_committed) const override; private: bool allow_previews_;
diff --git a/components/safe_browsing/common/safe_browsing_prefs.cc b/components/safe_browsing/common/safe_browsing_prefs.cc index c300dd0..97ffdb9 100644 --- a/components/safe_browsing/common/safe_browsing_prefs.cc +++ b/components/safe_browsing/common/safe_browsing_prefs.cc
@@ -169,28 +169,23 @@ base::FEATURE_ENABLED_BY_DEFAULT}; bool ExtendedReportingPrefExists(const PrefService& prefs) { - return prefs.HasPrefPath(GetExtendedReportingPrefName(prefs)); + return prefs.HasPrefPath(prefs::kSafeBrowsingScoutReportingEnabled); } ExtendedReportingLevel GetExtendedReportingLevel(const PrefService& prefs) { return IsExtendedReportingEnabled(prefs) ? SBER_LEVEL_SCOUT : SBER_LEVEL_OFF; } -const char* GetExtendedReportingPrefName(const PrefService& prefs) { - // TODO(lpz): Remove this method, use the pref directly in calling code. - return prefs::kSafeBrowsingScoutReportingEnabled; -} - bool IsExtendedReportingOptInAllowed(const PrefService& prefs) { return prefs.GetBoolean(prefs::kSafeBrowsingExtendedReportingOptInAllowed); } bool IsExtendedReportingEnabled(const PrefService& prefs) { - return prefs.GetBoolean(GetExtendedReportingPrefName(prefs)); + return prefs.GetBoolean(prefs::kSafeBrowsingScoutReportingEnabled); } bool IsExtendedReportingPolicyManaged(const PrefService& prefs) { - return prefs.IsManagedPreference(GetExtendedReportingPrefName(prefs)); + return prefs.IsManagedPreference(prefs::kSafeBrowsingScoutReportingEnabled); } void RecordExtendedReportingMetrics(const PrefService& prefs) { @@ -262,12 +257,12 @@ PrefService* prefs, bool value, ExtendedReportingOptInLocation location) { - prefs->SetBoolean(GetExtendedReportingPrefName(*prefs), value); + prefs->SetBoolean(prefs::kSafeBrowsingScoutReportingEnabled, value); RecordExtendedReportingPrefChanged(*prefs, location); } void SetExtendedReportingPref(PrefService* prefs, bool value) { - prefs->SetBoolean(GetExtendedReportingPrefName(*prefs), value); + prefs->SetBoolean(prefs::kSafeBrowsingScoutReportingEnabled, value); } void UpdateMetricsAfterSecurityInterstitial(const PrefService& prefs,
diff --git a/components/safe_browsing/common/safe_browsing_prefs.h b/components/safe_browsing/common/safe_browsing_prefs.h index a90d70b6..6d68d3f 100644 --- a/components/safe_browsing/common/safe_browsing_prefs.h +++ b/components/safe_browsing/common/safe_browsing_prefs.h
@@ -149,10 +149,6 @@ // Returns the level of reporting available for the current user. ExtendedReportingLevel GetExtendedReportingLevel(const PrefService& prefs); -// Returns the name of the Safe Browsing Extended Reporting pref that is -// currently in effect. The specific pref in-use may change through experiments. -const char* GetExtendedReportingPrefName(const PrefService& prefs); - // Returns whether the user is able to modify the Safe Browsing Extended // Reporting opt-in. bool IsExtendedReportingOptInAllowed(const PrefService& prefs);
diff --git a/components/safe_browsing/common/safe_browsing_prefs_unittest.cc b/components/safe_browsing/common/safe_browsing_prefs_unittest.cc index cc3cb04..d4a2629 100644 --- a/components/safe_browsing/common/safe_browsing_prefs_unittest.cc +++ b/components/safe_browsing/common/safe_browsing_prefs_unittest.cc
@@ -61,21 +61,6 @@ base::JoinString(disabled_features, ",")); } - std::string GetActivePref() { return GetExtendedReportingPrefName(prefs_); } - - // Convenience method for explicitly setting up all combinations of prefs and - // experiments. - void TestGetPrefName(bool scout_reporting, - bool scout_group, - bool can_show_scout, - const std::string& expected_pref) { - ResetPrefs(scout_reporting, scout_group); - ResetExperiments(can_show_scout); - EXPECT_EQ(expected_pref, GetActivePref()) - << " scout=" << scout_reporting << " scout_group=" << scout_group - << " can_show_scout=" << can_show_scout; - } - bool IsScoutGroupSelected() { return prefs_.GetBoolean(prefs::kSafeBrowsingScoutGroupSelected); } @@ -104,59 +89,6 @@ content::TestBrowserThreadBundle thread_bundle_; }; -// This test ensures that we correctly select Scout as the -// active preference in a number of common scenarios. -// TODO(crbug.com/881476) disabled for flaky crashes. -#if defined(OS_WIN) -#define MAYBE_GetExtendedReportingPrefName_Common \ - DISABLED_GetExtendedReportingPrefName_Common -#else -#define MAYBE_GetExtendedReportingPrefName_Common \ - GetExtendedReportingPrefName_Common -#endif -TEST_F(SafeBrowsingPrefsTest, MAYBE_GetExtendedReportingPrefName_Common) { - const std::string& scout = prefs::kSafeBrowsingScoutReportingEnabled; - - // By default (all prefs and experiment features disabled), Scout pref is - // used. - TestGetPrefName(false, false, false, scout); - - // Changing any prefs (including ScoutGroupSelected) keeps Scout as the active - // pref because the experiment remains in the Control group. - TestGetPrefName(/*scout=*/true, false, false, scout); - TestGetPrefName(false, /*scout_group=*/true, false, scout); - - // Being in the experiment group with ScoutGroup selected makes Scout the - // active pref. - TestGetPrefName(false, /*scout_group=*/true, /*can_show_scout=*/true, scout); - - // When ScoutGroup is not selected then Scout still remains the active pref, - // regardless if the experiment is enabled. - TestGetPrefName(false, false, /*can_show_scout=*/true, scout); -} - -// Here we exhaustively check all combinations of pref and experiment states. -// This should help catch regressions. -// TODO(crbug.com/881476) disabled for flaky crashes. -#if defined(OS_WIN) -#define MAYBE_GetExtendedReportingPrefName_Exhaustive \ - DISABLED_GetExtendedReportingPrefName_Exhaustive -#else -#define MAYBE_GetExtendedReportingPrefName_Exhaustive \ - GetExtendedReportingPrefName_Exhaustive -#endif -TEST_F(SafeBrowsingPrefsTest, MAYBE_GetExtendedReportingPrefName_Exhaustive) { - const std::string& scout = prefs::kSafeBrowsingScoutReportingEnabled; - TestGetPrefName(false, false, false, scout); - TestGetPrefName(false, false, true, scout); - TestGetPrefName(false, true, false, scout); - TestGetPrefName(false, true, true, scout); - TestGetPrefName(true, false, false, scout); - TestGetPrefName(true, false, true, scout); - TestGetPrefName(true, true, false, scout); - TestGetPrefName(true, true, true, scout); -} - // TODO(crbug.com/881476) disabled for flaky crashes. #if defined(OS_WIN) #define MAYBE_GetSafeBrowsingExtendedReportingLevel \ @@ -257,9 +189,10 @@ // Make the SBER pref managed and enable it and ensure that the pref gets // the expected value. Making SBER managed doesn't change the // SBEROptInAllowed setting. - prefs_.SetManagedPref(GetExtendedReportingPrefName(prefs_), + prefs_.SetManagedPref(prefs::kSafeBrowsingScoutReportingEnabled, std::make_unique<base::Value>(true)); - EXPECT_TRUE(prefs_.IsManagedPreference(GetExtendedReportingPrefName(prefs_))); + EXPECT_TRUE( + prefs_.IsManagedPreference(prefs::kSafeBrowsingScoutReportingEnabled)); // The value of the pref comes from the policy. EXPECT_TRUE(IsExtendedReportingEnabled(prefs_)); // SBER being managed doesn't change the SBEROptInAllowed pref.
diff --git a/components/security_interstitials/content/security_interstitial_controller_client.cc b/components/security_interstitials/content/security_interstitial_controller_client.cc index 49eba9c..3a88df42 100644 --- a/components/security_interstitials/content/security_interstitial_controller_client.cc +++ b/components/security_interstitials/content/security_interstitial_controller_client.cc
@@ -99,7 +99,7 @@ const std::string SecurityInterstitialControllerClient::GetExtendedReportingPrefName() const { - return safe_browsing::GetExtendedReportingPrefName(*prefs_); + return prefs::kSafeBrowsingScoutReportingEnabled; } bool SecurityInterstitialControllerClient::CanLaunchDateAndTimeSettings() {
diff --git a/components/signin/core/browser/account_reconcilor.h b/components/signin/core/browser/account_reconcilor.h index dad2ab6..988a954a 100644 --- a/components/signin/core/browser/account_reconcilor.h +++ b/components/signin/core/browser/account_reconcilor.h
@@ -10,6 +10,7 @@ #include "base/callback_forward.h" #include "base/compiler_specific.h" +#include "base/feature_list.h" #include "base/gtest_prod_util.h" #include "base/macros.h" #include "base/memory/weak_ptr.h"
diff --git a/components/signin/core/browser/profile_management_switches.cc b/components/signin/core/browser/profile_management_switches.cc index 9321f3a8..a0246df 100644 --- a/components/signin/core/browser/profile_management_switches.cc +++ b/components/signin/core/browser/profile_management_switches.cc
@@ -4,23 +4,15 @@ #include "components/signin/core/browser/profile_management_switches.h" -#include <string> - -#include "base/command_line.h" #include "base/logging.h" -#include "base/metrics/field_trial_params.h" -#include "build/build_config.h" -#include "components/signin/core/browser/signin_switches.h" namespace signin { namespace { - bool AccountConsistencyMethodGreaterOrEqual(AccountConsistencyMethod a, AccountConsistencyMethod b) { return static_cast<int>(a) >= static_cast<int>(b); } - } // namespace bool DiceMethodGreaterOrEqual(AccountConsistencyMethod a, @@ -30,15 +22,4 @@ return AccountConsistencyMethodGreaterOrEqual(a, b); } -bool IsExtensionsMultiAccount() { -#if defined(OS_ANDROID) || defined(OS_IOS) - NOTREACHED() << "Extensions are not enabled on Android or iOS"; - // Account consistency is enabled on Android and iOS. - return false; -#endif - - return base::CommandLine::ForCurrentProcess()->HasSwitch( - switches::kExtensionsMultiAccount); -} - } // namespace signin
diff --git a/components/signin/core/browser/profile_management_switches.h b/components/signin/core/browser/profile_management_switches.h index 51bc3e6..702972cf 100644 --- a/components/signin/core/browser/profile_management_switches.h +++ b/components/signin/core/browser/profile_management_switches.h
@@ -9,8 +9,6 @@ #ifndef COMPONENTS_SIGNIN_CORE_BROWSER_PROFILE_MANAGEMENT_SWITCHES_H_ #define COMPONENTS_SIGNIN_CORE_BROWSER_PROFILE_MANAGEMENT_SWITCHES_H_ -#include "base/feature_list.h" - namespace signin { // TODO(https://crbug.com/777774): Cleanup this enum and remove related @@ -41,12 +39,6 @@ bool DiceMethodGreaterOrEqual(AccountConsistencyMethod a, AccountConsistencyMethod b); -//////////////////////////////////////////////////////////////////////////////// -// Other functions: - -// Whether the chrome.identity API should be multi-account. -bool IsExtensionsMultiAccount(); - } // namespace signin #endif // COMPONENTS_SIGNIN_CORE_BROWSER_PROFILE_MANAGEMENT_SWITCHES_H_
diff --git a/components/signin/core/browser/signin_switches.cc b/components/signin/core/browser/signin_switches.cc index 1886ccf3..7d99de9b 100644 --- a/components/signin/core/browser/signin_switches.cc +++ b/components/signin/core/browser/signin_switches.cc
@@ -26,7 +26,4 @@ const char kAccountConsistencyDice[] = "dice"; #endif -// Enables multiple account versions of chrome.identity APIs. -const char kExtensionsMultiAccount[] = "extensions-multi-account"; - } // namespace switches
diff --git a/components/signin/core/browser/signin_switches.h b/components/signin/core/browser/signin_switches.h index 71cf2a5..7d7971f 100644 --- a/components/signin/core/browser/signin_switches.h +++ b/components/signin/core/browser/signin_switches.h
@@ -17,7 +17,6 @@ // alongside the definition of their values in the .cc file. extern const char kClearTokenService[]; extern const char kDisableSigninScopedDeviceId[]; -extern const char kExtensionsMultiAccount[]; #if !BUILDFLAG(ENABLE_MIRROR) // Note: Account consistency (Mirror) is already enabled on mobile platforms, so
diff --git a/components/sync/model/sync_data.cc b/components/sync/model/sync_data.cc index eb57484..04a3b385 100644 --- a/components/sync/model/sync_data.cc +++ b/components/sync/model/sync_data.cc
@@ -169,8 +169,7 @@ // cases, where this is the hashed tag value. The original tag is not sent to // the server so we wouldn't be able to set this value anyways. The only way // to recreate an un-hashed tag is for the service to do so with a specifics. - // Should only be used by sessions, see crbug.com/604657. - DCHECK_EQ(SESSIONS, GetDataType()); + DCHECK(!immutable_entity_.Get().client_defined_unique_tag().empty()); return immutable_entity_.Get().client_defined_unique_tag(); }
diff --git a/components/sync/model_impl/syncable_service_based_bridge.cc b/components/sync/model_impl/syncable_service_based_bridge.cc index e604393..5f11020 100644 --- a/components/sync/model_impl/syncable_service_based_bridge.cc +++ b/components/sync/model_impl/syncable_service_based_bridge.cc
@@ -108,20 +108,24 @@ store_->CreateWriteBatch(); for (const SyncChange& change : change_list) { - DCHECK(change.sync_data().IsLocal()) - << " from " << change.location().ToString(); - SyncDataLocal sync_data(change.sync_data()); - DCHECK(sync_data.IsValid()) << " from " << change.location().ToString(); - const std::string storage_key = - GenerateSyncableHash(type_, sync_data.GetTag()); - DCHECK(!storage_key.empty()); - switch (change.change_type()) { case SyncChange::ACTION_INVALID: NOTREACHED() << " from " << change.location().ToString(); break; + case SyncChange::ACTION_ADD: case SyncChange::ACTION_UPDATE: { + DCHECK_EQ(type_, change.sync_data().GetDataType()); + DCHECK(change.sync_data().IsLocal()) + << " from " << change.location().ToString(); + + SyncDataLocal sync_data(change.sync_data()); + DCHECK(sync_data.IsValid()) + << " from " << change.location().ToString(); + const std::string storage_key = + GenerateSyncableHash(type_, sync_data.GetTag()); + DCHECK(!storage_key.empty()); + (*in_memory_store_)[storage_key] = sync_data.GetSpecifics(); std::unique_ptr<sync_pb::PersistedEntityData> persisted_entity = CreatePersistedFromSyncData(sync_data); @@ -133,11 +137,35 @@ batch->GetMetadataChangeList()); break; } - case SyncChange::ACTION_DELETE: + + case SyncChange::ACTION_DELETE: { + std::string storage_key; + // Both SyncDataLocal and SyncDataRemote are allowed for deletions. + if (change.sync_data().IsLocal()) { + SyncDataLocal sync_data(change.sync_data()); + DCHECK(sync_data.IsValid()) + << " from " << change.location().ToString(); + storage_key = GenerateSyncableHash(type_, sync_data.GetTag()); + } else { + SyncDataRemote sync_data(change.sync_data()); + storage_key = sync_data.GetClientTagHash(); + } + + DCHECK(!storage_key.empty()) + << " from " << change.location().ToString(); + in_memory_store_->erase(storage_key); - other_->Delete(storage_key, batch->GetMetadataChangeList()); batch->DeleteData(storage_key); + + if (IsActOnceDataType(type_)) { + batch->GetMetadataChangeList()->ClearMetadata(storage_key); + other_->UntrackEntityForStorageKey(storage_key); + } else { + other_->Delete(storage_key, batch->GetMetadataChangeList()); + } + break; + } } }
diff --git a/components/update_client/ping_manager_unittest.cc b/components/update_client/ping_manager_unittest.cc index a65fdd38..0ac9f80 100644 --- a/components/update_client/ping_manager_unittest.cc +++ b/components/update_client/ping_manager_unittest.cc
@@ -135,10 +135,10 @@ R"(prodchannel="fake_channel_string" )" R"(os="\w+" arch="\w+" nacl_arch="[-\w]+"( wow64="1")?>)" R"(<hw physmemory="\d+"/>)" - R"(<os platform="Fake Operating System" arch="\w+" )" + R"(<os platform="Fake Operating System" arch="[,-.\w]+" )" R"(version="[-.\w]+"( sp="[\s\w]+")?/>)" R"(<app appid="abc"><event eventtype="3" eventresult="1" )" - R"(previousversion="1.0" nextversion="2.0"/></app></request>)"; + R"(previousversion="1\.0" nextversion="2\.0"/></app></request>)"; EXPECT_TRUE(RE2::FullMatch(msg, regex)) << msg; // Check the ping request does not carry the specific extra request headers. @@ -170,7 +170,7 @@ const auto msg = interceptor->GetRequestBody(0); constexpr char regex[] = R"(<app appid="abc"><event eventtype="3" eventresult="0" )" - R"(previousversion="1.0" nextversion="2.0"/></app>)"; + R"(previousversion="1\.0" nextversion="2\.0"/></app>)"; EXPECT_TRUE(RE2::PartialMatch(msg, regex)) << msg; interceptor->Reset(); } @@ -206,7 +206,7 @@ R"(errorcode="2" extracode1="-1" diffresult="0" )" R"(differrorcat="4" differrorcode="20" diffextracode1="-10" )" R"(previousfp="prev fp" nextfp="next fp" )" - R"(previousversion="1.0" nextversion="2.0"/></app>)"; + R"(previousversion="1\.0" nextversion="2\.0"/></app>)"; EXPECT_TRUE(RE2::PartialMatch(msg, regex)) << msg; interceptor->Reset(); @@ -230,7 +230,7 @@ const auto msg = interceptor->GetRequestBody(0); constexpr char regex[] = R"(<app appid="abc"><event eventtype="3" eventresult="0" )" - R"(previousversion="1.0"/></app>)"; + R"(previousversion="1\.0"/></app>)"; EXPECT_TRUE(RE2::PartialMatch(msg, regex)) << msg; interceptor->Reset(); @@ -252,7 +252,7 @@ const auto msg = interceptor->GetRequestBody(0); constexpr char regex[] = R"(<app appid="abc"><event eventtype="4" eventresult="1" )" - R"(previousversion="1.2.3.4" nextversion="0"/></app>)"; + R"(previousversion="1\.2\.3\.4" nextversion="0"/></app>)"; EXPECT_TRUE(RE2::PartialMatch(msg, regex)) << msg; interceptor->Reset(); @@ -296,15 +296,15 @@ constexpr char regex[] = R"(<app appid="abc">)" R"(<event eventtype="3" eventresult="1" )" - R"(previousversion="1.0" nextversion="2.0"/>)" + R"(previousversion="1\.0" nextversion="2\.0"/>)" R"(<event eventtype="14" eventresult="0" downloader="direct" )" R"(errorcode="-1" url="http://host1/path1" downloaded="123" )" - R"(total="456" download_time_ms="987" previousversion="1.0" )" - R"(nextversion="2.0"/>)" + R"(total="456" download_time_ms="987" previousversion="1\.0" )" + R"(nextversion="2\.0"/>)" R"(<event eventtype="14" eventresult="1" downloader="bits" )" R"(url="http://host2/path2" downloaded="1230" total="4560" )" - R"(download_time_ms="9870" previousversion="1.0" )" - R"(nextversion="2.0"/></app>)"; + R"(download_time_ms="9870" previousversion="1\.0" )" + R"(nextversion="2\.0"/></app>)"; EXPECT_TRUE(RE2::PartialMatch(msg, regex)) << msg; interceptor->Reset();
diff --git a/components/variations/synthetic_trial_registry.h b/components/variations/synthetic_trial_registry.h index 646c90d..4be74aff 100644 --- a/components/variations/synthetic_trial_registry.h +++ b/components/variations/synthetic_trial_registry.h
@@ -50,7 +50,7 @@ // is registered for a given trial name will be recorded. The values passed // in must not correspond to any real field trial in the code. // Note: Should not be used to replace trials that were registered with - // RegisterMultiGroupSyntheticFieldTrial(). + // RegisterSyntheticMultiGroupFieldTrial(). void RegisterSyntheticFieldTrial(const SyntheticTrialGroup& trial_group); // Similar to RegisterSyntheticFieldTrial(), but registers a synthetic trial
diff --git a/content/browser/android/java/gin_java_bridge_message_filter.cc b/content/browser/android/java/gin_java_bridge_message_filter.cc index 9c2feb1a..2a38722 100644 --- a/content/browser/android/java/gin_java_bridge_message_filter.cc +++ b/content/browser/android/java/gin_java_bridge_message_filter.cc
@@ -84,6 +84,21 @@ } } +void GinJavaBridgeMessageFilter::RenderProcessExited( + RenderProcessHost* rph, + const ChildProcessTerminationInfo& info) { +#if DCHECK_IS_ON() + { + scoped_refptr<GinJavaBridgeMessageFilter> filter = + base::UserDataAdapter<GinJavaBridgeMessageFilter>::Get( + rph, kGinJavaBridgeMessageFilterKey); + DCHECK_EQ(this, filter.get()); + } +#endif + rph->RemoveObserver(this); + rph->RemoveUserData(kGinJavaBridgeMessageFilterKey); +} + // static scoped_refptr<GinJavaBridgeMessageFilter> GinJavaBridgeMessageFilter::FromHost( GinJavaBridgeDispatcherHost* host, bool create_if_not_exists) { @@ -94,6 +109,8 @@ if (!filter && create_if_not_exists) { filter = new GinJavaBridgeMessageFilter(); rph->AddFilter(filter.get()); + rph->AddObserver(filter.get()); + rph->SetUserData( kGinJavaBridgeMessageFilterKey, std::make_unique<base::UserDataAdapter<GinJavaBridgeMessageFilter>>(
diff --git a/content/browser/android/java/gin_java_bridge_message_filter.h b/content/browser/android/java/gin_java_bridge_message_filter.h index f38f0d032..c15bc707 100644 --- a/content/browser/android/java/gin_java_bridge_message_filter.h +++ b/content/browser/android/java/gin_java_bridge_message_filter.h
@@ -16,6 +16,7 @@ #include "content/browser/android/java/gin_java_bound_object.h" #include "content/common/android/gin_java_bridge_errors.h" #include "content/public/browser/browser_message_filter.h" +#include "content/public/browser/render_process_host_observer.h" namespace base { class ListValue; @@ -30,7 +31,8 @@ class GinJavaBridgeDispatcherHost; class RenderFrameHost; -class GinJavaBridgeMessageFilter : public BrowserMessageFilter { +class GinJavaBridgeMessageFilter : public BrowserMessageFilter, + public RenderProcessHostObserver { public: // BrowserMessageFilter void OnDestruct() const override; @@ -38,6 +40,10 @@ base::TaskRunner* OverrideTaskRunnerForMessage( const IPC::Message& message) override; + // RenderProcessHostObserver + void RenderProcessExited(RenderProcessHost* rph, + const ChildProcessTerminationInfo& info) override; + // Called on the UI thread. void AddRoutingIdForHost(GinJavaBridgeDispatcherHost* host, RenderFrameHost* render_frame_host);
diff --git a/content/browser/background_fetch/background_fetch_context.cc b/content/browser/background_fetch/background_fetch_context.cc index e95ff15..655baf1 100644 --- a/content/browser/background_fetch/background_fetch_context.cc +++ b/content/browser/background_fetch/background_fetch_context.cc
@@ -452,6 +452,7 @@ case FailureReason::CANCELLED_FROM_UI: CleanupRegistration(registration_id, {}, blink::mojom::BackgroundFetchResult::FAILURE); + registration_notifier_->Notify(*registration); event_dispatcher_.DispatchBackgroundFetchAbortEvent( registration_id, std::move(registration), base::DoNothing()); return; @@ -509,6 +510,7 @@ switch (registration->failure_reason) { case FailureReason::NONE: registration->result = blink::mojom::BackgroundFetchResult::SUCCESS; + registration_notifier_->Notify(*registration); event_dispatcher_.DispatchBackgroundFetchSuccessEvent( registration_id, std::move(registration), base::BindOnce( @@ -529,6 +531,7 @@ case FailureReason::QUOTA_EXCEEDED: case FailureReason::TOTAL_DOWNLOAD_SIZE_EXCEEDED: registration->result = blink::mojom::BackgroundFetchResult::FAILURE; + registration_notifier_->Notify(*registration); event_dispatcher_.DispatchBackgroundFetchFailEvent( registration_id, std::move(registration), base::BindOnce(
diff --git a/content/browser/background_fetch/background_fetch_job_controller.cc b/content/browser/background_fetch/background_fetch_job_controller.cc index aae90ba..7561aeb 100644 --- a/content/browser/background_fetch/background_fetch_job_controller.cc +++ b/content/browser/background_fetch/background_fetch_job_controller.cc
@@ -160,9 +160,10 @@ active_request_downloaded_bytes_ = bytes_downloaded; - progress_callback_.Run(registration_id().unique_id(), options_.download_total, - complete_requests_downloaded_bytes_cache_ + - GetInProgressDownloadedBytes()); + auto registration = + NewRegistration(blink::mojom::BackgroundFetchResult::UNSET); + registration->downloaded += GetInProgressDownloadedBytes(); + progress_callback_.Run(*registration); } void BackgroundFetchJobController::DidCompleteRequest(
diff --git a/content/browser/background_fetch/background_fetch_job_controller.h b/content/browser/background_fetch/background_fetch_job_controller.h index 56d0941..b63f389d 100644 --- a/content/browser/background_fetch/background_fetch_job_controller.h +++ b/content/browser/background_fetch/background_fetch_job_controller.h
@@ -43,9 +43,7 @@ base::OnceCallback<void(const BackgroundFetchRegistrationId&, blink::mojom::BackgroundFetchFailureReason)>; using ProgressCallback = - base::RepeatingCallback<void(const std::string& /* unique_id */, - uint64_t /* download_total */, - uint64_t /* downloaded */)>; + base::RepeatingCallback<void(const BackgroundFetchRegistration&)>; BackgroundFetchJobController( BackgroundFetchDelegateProxy* delegate_proxy,
diff --git a/content/browser/background_fetch/background_fetch_job_controller_unittest.cc b/content/browser/background_fetch/background_fetch_job_controller_unittest.cc index 265be30..259b466 100644 --- a/content/browser/background_fetch/background_fetch_job_controller_unittest.cc +++ b/content/browser/background_fetch/background_fetch_job_controller_unittest.cc
@@ -207,10 +207,8 @@ BackgroundFetchDelegate* delegate_; private: - void DidUpdateProgress(const std::string& unique_id, - uint64_t download_total, - uint64_t downloaded) { - last_downloaded_ = downloaded; + void DidUpdateProgress(const BackgroundFetchRegistration& registration) { + last_downloaded_ = registration.downloaded; if (job_progress_closure_) job_progress_closure_.Run();
diff --git a/content/browser/background_fetch/background_fetch_registration_notifier.cc b/content/browser/background_fetch/background_fetch_registration_notifier.cc index 75bba45..e5dfc98 100644 --- a/content/browser/background_fetch/background_fetch_registration_notifier.cc +++ b/content/browser/background_fetch/background_fetch_registration_notifier.cc
@@ -28,14 +28,14 @@ observers_.emplace(unique_id, std::move(observer)); } -void BackgroundFetchRegistrationNotifier::Notify(const std::string& unique_id, - uint64_t download_total, - uint64_t downloaded) { - auto range = observers_.equal_range(unique_id); +void BackgroundFetchRegistrationNotifier::Notify( + const BackgroundFetchRegistration& registration) { + auto range = observers_.equal_range(registration.unique_id); for (auto it = range.first; it != range.second; ++it) { // TODO(crbug.com/774054): Uploads are not yet supported. it->second->OnProgress(0 /* upload_total */, 0 /* uploaded */, - download_total, downloaded); + registration.download_total, registration.downloaded, + registration.result, registration.failure_reason); } }
diff --git a/content/browser/background_fetch/background_fetch_registration_notifier.h b/content/browser/background_fetch/background_fetch_registration_notifier.h index e14df6f5..06324735 100644 --- a/content/browser/background_fetch/background_fetch_registration_notifier.h +++ b/content/browser/background_fetch/background_fetch_registration_notifier.h
@@ -30,12 +30,10 @@ const std::string& unique_id, blink::mojom::BackgroundFetchRegistrationObserverPtr observer); - // Notifies any registered observers for the registration identified by the - // |unique_id| of the progress. This will cause JavaScript events to fire. - // Successful fetches must also call Notify with the final state. - void Notify(const std::string& unique_id, - uint64_t download_total, - uint64_t downloaded); + // Notifies any registered observers for the |registration| of the progress. + // This will cause JavaScript events to fire. + // Completed fetches must also call Notify with the final state. + void Notify(const BackgroundFetchRegistration& registration); // Notifies any registered observers for the registration identifier by // |unique_id| that the records for the fetch are no longer available.
diff --git a/content/browser/background_fetch/background_fetch_registration_notifier_unittest.cc b/content/browser/background_fetch/background_fetch_registration_notifier_unittest.cc index b97eed5..cd9eee1 100644 --- a/content/browser/background_fetch/background_fetch_registration_notifier_unittest.cc +++ b/content/browser/background_fetch/background_fetch_registration_notifier_unittest.cc
@@ -19,6 +19,7 @@ namespace content { namespace { +const char kDeveloperId[] = "my-fetch"; const char kPrimaryUniqueId[] = "7e57ab1e-c0de-a150-ca75-1e75f005ba11"; const char kSecondaryUniqueId[] = "bb48a9fb-c21f-4c2d-a9ae-58bd48a9fb53"; @@ -32,16 +33,24 @@ ProgressUpdate(uint64_t upload_total, uint64_t uploaded, uint64_t download_total, - uint64_t downloaded) + uint64_t downloaded, + blink::mojom::BackgroundFetchResult result, + blink::mojom::BackgroundFetchFailureReason failure_reason) : upload_total(upload_total), uploaded(uploaded), download_total(download_total), - downloaded(downloaded) {} + downloaded(downloaded), + result(result), + failure_reason(failure_reason) {} uint64_t upload_total = 0; uint64_t uploaded = 0; uint64_t download_total = 0; uint64_t downloaded = 0; + blink::mojom::BackgroundFetchResult result = + blink::mojom::BackgroundFetchResult::UNSET; + blink::mojom::BackgroundFetchFailureReason failure_reason = + blink::mojom::BackgroundFetchFailureReason::NONE; }; TestRegistrationObserver() : binding_(this) {} @@ -65,12 +74,15 @@ bool records_available() const { return records_available_; } // blink::mojom::BackgroundFetchRegistrationObserver implementation. - void OnProgress(uint64_t upload_total, - uint64_t uploaded, - uint64_t download_total, - uint64_t downloaded) override { + void OnProgress( + uint64_t upload_total, + uint64_t uploaded, + uint64_t download_total, + uint64_t downloaded, + blink::mojom::BackgroundFetchResult result, + blink::mojom::BackgroundFetchFailureReason failure_reason) override { progress_updates_.emplace_back(upload_total, uploaded, download_total, - downloaded); + downloaded, result, failure_reason); } void OnRecordsUnavailable() override { records_available_ = false; } @@ -94,10 +106,8 @@ // Notifies all observers for the |unique_id| of the made progress, and waits // until the task runner managing the Mojo connection has finished. - void Notify(const std::string& unique_id, - uint64_t download_total, - uint64_t downloaded) { - notifier_->Notify(unique_id, download_total, downloaded); + void Notify(const BackgroundFetchRegistration& registration) { + notifier_->Notify(registration); task_runner_->RunUntilIdle(); } @@ -122,7 +132,11 @@ notifier_->AddObserver(kPrimaryUniqueId, observer->GetPtr()); ASSERT_EQ(observer->progress_updates().size(), 0u); - Notify(kPrimaryUniqueId, kDownloadTotal, kDownloaded); + Notify(BackgroundFetchRegistration( + kDeveloperId, kPrimaryUniqueId, + /* upload_total*/ 0, /* uploaded*/ 0, kDownloadTotal, kDownloaded, + blink::mojom::BackgroundFetchResult::UNSET, + blink::mojom::BackgroundFetchFailureReason::NONE)); ASSERT_EQ(observer->progress_updates().size(), 1u); @@ -132,6 +146,9 @@ EXPECT_EQ(update.uploaded, 0u); EXPECT_EQ(update.download_total, kDownloadTotal); EXPECT_EQ(update.downloaded, kDownloaded); + EXPECT_EQ(update.result, blink::mojom::BackgroundFetchResult::UNSET); + EXPECT_EQ(update.failure_reason, + blink::mojom::BackgroundFetchFailureReason::NONE); } TEST_F(BackgroundFetchRegistrationNotifierTest, NotifyMultipleObservers) { @@ -151,7 +168,11 @@ ASSERT_EQ(secondary_observer->progress_updates().size(), 0u); // Notify the |kPrimaryUniqueId|. - Notify(kPrimaryUniqueId, kDownloadTotal, kDownloaded); + Notify(BackgroundFetchRegistration( + kDeveloperId, kPrimaryUniqueId, + /* upload_total*/ 0, /* uploaded*/ 0, kDownloadTotal, kDownloaded, + blink::mojom::BackgroundFetchResult::UNSET, + blink::mojom::BackgroundFetchFailureReason::NONE)); for (auto& observer : primary_observers) { ASSERT_EQ(observer->progress_updates().size(), 1u); @@ -162,6 +183,9 @@ EXPECT_EQ(update.uploaded, 0u); EXPECT_EQ(update.download_total, kDownloadTotal); EXPECT_EQ(update.downloaded, kDownloaded); + EXPECT_EQ(update.result, blink::mojom::BackgroundFetchResult::UNSET); + EXPECT_EQ(update.failure_reason, + blink::mojom::BackgroundFetchFailureReason::NONE); } // The observer for |kSecondaryUniqueId| should not have been notified. @@ -175,14 +199,22 @@ notifier_->AddObserver(kPrimaryUniqueId, observer->GetPtr()); ASSERT_EQ(observer->progress_updates().size(), 0u); - Notify(kPrimaryUniqueId, kDownloadTotal, kDownloaded); + Notify(BackgroundFetchRegistration( + kDeveloperId, kPrimaryUniqueId, + /* upload_total*/ 0, /* uploaded*/ 0, kDownloadTotal, kDownloaded, + blink::mojom::BackgroundFetchResult::UNSET, + blink::mojom::BackgroundFetchFailureReason::NONE)); ASSERT_EQ(observer->progress_updates().size(), 1u); // Closes the binding as would be done from the renderer process. observer->Close(); - Notify(kPrimaryUniqueId, kDownloadTotal, kDownloaded); + Notify(BackgroundFetchRegistration( + kDeveloperId, kPrimaryUniqueId, + /* upload_total*/ 0, /* uploaded*/ 0, kDownloadTotal, kDownloaded, + blink::mojom::BackgroundFetchResult::UNSET, + blink::mojom::BackgroundFetchFailureReason::NONE)); // The observers for |kPrimaryUniqueId| were removed, so no second update // should have been received by the |observer|. @@ -195,7 +227,11 @@ notifier_->AddObserver(kPrimaryUniqueId, observer->GetPtr()); ASSERT_EQ(observer->progress_updates().size(), 0u); - Notify(kSecondaryUniqueId, kDownloadTotal, kDownloaded); + Notify(BackgroundFetchRegistration( + kDeveloperId, kSecondaryUniqueId, + /* upload_total*/ 0, /* uploaded*/ 0, kDownloadTotal, kDownloaded, + blink::mojom::BackgroundFetchResult::UNSET, + blink::mojom::BackgroundFetchFailureReason::NONE)); // Because the notification was for |kSecondaryUniqueId|, no progress updates // should be received by the |observer|.
diff --git a/content/browser/child_process_launcher_helper_mac.cc b/content/browser/child_process_launcher_helper_mac.cc index c1b02ef..60a5a64 100644 --- a/content/browser/child_process_launcher_helper_mac.cc +++ b/content/browser/child_process_launcher_helper_mac.cc
@@ -73,34 +73,8 @@ command_line_->HasSwitch(service_manager::switches::kNoSandbox) || service_manager::IsUnsandboxedSandboxType(sandbox_type); - // TODO(kerrnel): Delete this switch once the V2 sandbox is always enabled. - bool use_v2 = base::FeatureList::IsEnabled(features::kMacV2Sandbox); - - switch (sandbox_type) { - case service_manager::SANDBOX_TYPE_NO_SANDBOX: - break; - case service_manager::SANDBOX_TYPE_CDM: - case service_manager::SANDBOX_TYPE_PPAPI: - case service_manager::SANDBOX_TYPE_RENDERER: - case service_manager::SANDBOX_TYPE_UTILITY: - case service_manager::SANDBOX_TYPE_NACL_LOADER: - case service_manager::SANDBOX_TYPE_PDF_COMPOSITOR: - case service_manager::SANDBOX_TYPE_PROFILING: - // If the feature experiment is enabled and this process type supports - // the v2 sandbox, use it. - use_v2 &= true; - break; - case service_manager::SANDBOX_TYPE_AUDIO: - // The audio service only exists with the v2 sandbox. - use_v2 |= true; - break; - default: - // This is a 'break' because the V2 sandbox is not enabled for all - // processes yet, and so there are sandbox types like NETWORK that - // should not be run under the V2 sandbox. - use_v2 = false; - break; - } + bool use_v2 = + !no_sandbox && (sandbox_type != service_manager::SANDBOX_TYPE_GPU); if (use_v2 && !no_sandbox) { // Generate the profile string. @@ -133,8 +107,16 @@ case service_manager::SANDBOX_TYPE_PROFILING: profile += service_manager::kSeatbeltPolicyString_utility; break; - default: + case service_manager::SANDBOX_TYPE_NETWORK: + // Put a separate CHECK() for the network sandbox so that crash reports + // will show which invalid case was hit. CHECK(false); + break; + case service_manager::SANDBOX_TYPE_INVALID: + case service_manager::SANDBOX_TYPE_FIRST_TYPE: + case service_manager::SANDBOX_TYPE_AFTER_LAST_TYPE: + CHECK(false); + break; } // Disable os logging to com.apple.diagnosticd which is a performance
diff --git a/content/browser/font_unique_name_lookup/font_unique_name_browsertest.cc b/content/browser/font_unique_name_lookup/font_unique_name_browsertest.cc index 269e705..8e370e5 100644 --- a/content/browser/font_unique_name_lookup/font_unique_name_browsertest.cc +++ b/content/browser/font_unique_name_lookup/font_unique_name_browsertest.cc
@@ -87,6 +87,17 @@ "Tinos", "Mukti Narrow", "Tinos"}; +#elif defined(OS_MACOSX) +const char* kExpectedFontFamilyNames[] = {"American Typewriter", + "Arial Narrow", + "Baskerville", + "Devanagari MT", + "DIN Alternate", + "Gill Sans", + "Iowan Old Style", + "Malayalam Sangam MN", + "Hiragino Maru Gothic Pro", + "Hiragino Kaku Gothic StdN"}; #endif } // namespace @@ -110,7 +121,7 @@ }; // TODO(drott): Enable this on all platforms. -#if defined(OS_ANDROID) || defined(OS_LINUX) +#if defined(OS_ANDROID) || defined(OS_LINUX) || defined(OS_MACOSX) IN_PROC_BROWSER_TEST_F(FontUniqueNameBrowserTest, ContentLocalFontsMatching) { LoadAndWait("/font_src_local_matching.html"); Attach();
diff --git a/content/browser/frame_host/render_frame_host_impl.cc b/content/browser/frame_host/render_frame_host_impl.cc index df0aa51..a17ae7c 100644 --- a/content/browser/frame_host/render_frame_host_impl.cc +++ b/content/browser/frame_host/render_frame_host_impl.cc
@@ -5207,10 +5207,9 @@ BrowserMainLoop* browser_main_loop = BrowserMainLoop::GetInstance(); DCHECK(browser_main_loop); if (base::FeatureList::IsEnabled(features::kAudioServiceAudioStreams)) { - scoped_refptr<AudioInputDeviceManager> aidm = - browser_main_loop->media_stream_manager()->audio_input_device_manager(); - audio_service_audio_input_stream_factory_.emplace(std::move(request), - std::move(aidm), this); + MediaStreamManager* msm = browser_main_loop->media_stream_manager(); + audio_service_audio_input_stream_factory_.emplace(std::move(request), msm, + this); } else { in_content_audio_input_stream_factory_ = RenderFrameAudioInputStreamFactoryHandle::CreateFactory(
diff --git a/content/browser/media/audio_input_stream_broker.cc b/content/browser/media/audio_input_stream_broker.cc index b5e91e560..0fc989d 100644 --- a/content/browser/media/audio_input_stream_broker.cc +++ b/content/browser/media/audio_input_stream_broker.cc
@@ -6,23 +6,24 @@ #include <utility> +#include "base/bind.h" #include "base/command_line.h" +#include "base/location.h" #include "base/logging.h" #include "base/memory/read_only_shared_memory_region.h" #include "base/metrics/histogram_macros.h" +#include "base/optional.h" #include "base/task/post_task.h" #include "base/trace_event/trace_event.h" +#include "build/build_config.h" #include "content/browser/browser_main_loop.h" #include "content/browser/media/media_internals.h" #include "content/public/browser/browser_task_traits.h" #include "content/public/browser/browser_thread.h" -#include "content/public/browser/content_browser_client.h" -#include "content/public/browser/media_observer.h" -#include "content/public/browser/render_process_host.h" -#include "content/public/common/content_client.h" #include "media/audio/audio_logging.h" #include "media/base/media_switches.h" #include "media/base/user_input_monitor.h" +#include "mojo/public/cpp/bindings/interface_request.h" #include "mojo/public/cpp/system/platform_handle.h" #if defined(OS_CHROMEOS) @@ -82,7 +83,7 @@ renderer_factory_client_(std::move(renderer_factory_client)), observer_binding_(this), weak_ptr_factory_(this) { - DCHECK_CURRENTLY_ON(BrowserThread::UI); + DCHECK_CURRENTLY_ON(BrowserThread::IO); DCHECK(renderer_factory_client_); DCHECK(deleter_); TRACE_EVENT_NESTABLE_ASYNC_BEGIN0("audio", "AudioInputStreamBroker", this); @@ -91,11 +92,7 @@ renderer_factory_client_.set_connection_error_handler(base::BindOnce( &AudioInputStreamBroker::ClientBindingLost, base::Unretained(this))); - // Notify RenderProcessHost about input stream so the renderer is not - // background. - auto* process_host = RenderProcessHost::FromID(render_process_id); - if (process_host) - process_host->OnMediaStreamAdded(); + NotifyProcessHostOfStartedStream(render_process_id); if (base::CommandLine::ForCurrentProcess()->HasSwitch( switches::kUseFakeDeviceForMediaStream)) { @@ -111,7 +108,7 @@ } AudioInputStreamBroker::~AudioInputStreamBroker() { - DCHECK_CURRENTLY_ON(BrowserThread::UI); + DCHECK_CURRENTLY_ON(BrowserThread::IO); #if defined(OS_CHROMEOS) if (params_.channel_layout() == @@ -125,9 +122,7 @@ if (user_input_monitor_) user_input_monitor_->DisableKeyPressMonitoring(); - auto* process_host = RenderProcessHost::FromID(render_process_id()); - if (process_host) - process_host->OnMediaStreamRemoved(); + NotifyProcessHostOfStoppedStream(render_process_id()); // TODO(https://crbug.com/829317) update tab recording indicator. @@ -145,7 +140,7 @@ void AudioInputStreamBroker::CreateStream( audio::mojom::StreamFactory* factory) { - DCHECK_CURRENTLY_ON(BrowserThread::UI); + DCHECK_CURRENTLY_ON(BrowserThread::IO); DCHECK(!observer_binding_.is_bound()); DCHECK(!client_request_); TRACE_EVENT_NESTABLE_ASYNC_BEGIN1("audio", "CreateStream", this, "device id", @@ -175,8 +170,6 @@ // Note that the component id for AudioLog is used to differentiate between // several users of the same audio log. Since this audio log is for a single // stream, the component id used doesn't matter. - // TODO(https://crbug.com/836226) pass valid user input monitor handle when - // switching to audio service input streams. constexpr int log_component_id = 0; factory->CreateInputStream( std::move(stream_request), std::move(client), std::move(observer_ptr), @@ -191,7 +184,7 @@ } void AudioInputStreamBroker::DidStartRecording() { - DCHECK_CURRENTLY_ON(BrowserThread::UI); + DCHECK_CURRENTLY_ON(BrowserThread::IO); // TODO(https://crbug.com/829317) update tab recording indicator. } @@ -200,7 +193,7 @@ media::mojom::ReadOnlyAudioDataPipePtr data_pipe, bool initially_muted, const base::Optional<base::UnguessableToken>& stream_id) { - DCHECK_CURRENTLY_ON(BrowserThread::UI); + DCHECK_CURRENTLY_ON(BrowserThread::IO); awaiting_created_ = false; TRACE_EVENT_NESTABLE_ASYNC_END1("audio", "CreateStream", this, "success", !!data_pipe); @@ -221,7 +214,7 @@ void AudioInputStreamBroker::ObserverBindingLost( uint32_t reason, const std::string& description) { - DCHECK_CURRENTLY_ON(BrowserThread::UI); + DCHECK_CURRENTLY_ON(BrowserThread::IO); const uint32_t maxValidReason = static_cast<uint32_t>( media::mojom::AudioInputStreamObserver::DisconnectReason::kMaxValue); @@ -238,13 +231,14 @@ } void AudioInputStreamBroker::ClientBindingLost() { + DCHECK_CURRENTLY_ON(BrowserThread::IO); disconnect_reason_ = media::mojom::AudioInputStreamObserver:: DisconnectReason::kTerminatedByClient; Cleanup(); } void AudioInputStreamBroker::Cleanup() { - DCHECK_CURRENTLY_ON(BrowserThread::UI); + DCHECK_CURRENTLY_ON(BrowserThread::IO); std::move(deleter_).Run(this); }
diff --git a/content/browser/media/audio_input_stream_broker.h b/content/browser/media/audio_input_stream_broker.h index bc1ea80..397cb49 100644 --- a/content/browser/media/audio_input_stream_broker.h +++ b/content/browser/media/audio_input_stream_broker.h
@@ -7,12 +7,13 @@ #include <string> +#include "base/macros.h" #include "base/memory/weak_ptr.h" -#include "base/sequence_checker.h" #include "content/browser/media/audio_stream_broker.h" #include "content/common/content_export.h" #include "content/common/media/renderer_audio_input_stream_factory.mojom.h" #include "media/base/audio_parameters.h" +#include "media/mojo/interfaces/audio_data_pipe.mojom.h" #include "media/mojo/interfaces/audio_input_stream.mojom.h" #include "mojo/public/cpp/bindings/binding.h" #include "services/audio/public/mojom/audio_processing.mojom.h"
diff --git a/content/browser/media/audio_loopback_stream_broker.cc b/content/browser/media/audio_loopback_stream_broker.cc index 5ce0ed678..1b83498 100644 --- a/content/browser/media/audio_loopback_stream_broker.cc +++ b/content/browser/media/audio_loopback_stream_broker.cc
@@ -6,9 +6,14 @@ #include <utility> +#include "base/bind.h" +#include "base/location.h" +#include "base/logging.h" +#include "base/task/post_task.h" #include "base/unguessable_token.h" +#include "content/public/browser/browser_task_traits.h" #include "content/public/browser/browser_thread.h" -#include "content/public/browser/render_process_host.h" +#include "services/audio/public/mojom/stream_factory.mojom.h" namespace content { @@ -29,7 +34,7 @@ renderer_factory_client_(std::move(renderer_factory_client)), observer_binding_(this), weak_ptr_factory_(this) { - DCHECK_CURRENTLY_ON(BrowserThread::UI); + DCHECK_CURRENTLY_ON(BrowserThread::IO); DCHECK(source_); DCHECK(renderer_factory_client_); DCHECK(deleter_); @@ -45,25 +50,21 @@ // Notify the source that we are capturing from it. source_->AddLoopbackSink(this); - // Notify RenderProcessHost about the input stream, so that the destination - // renderer does not get background. - if (auto* process_host = RenderProcessHost::FromID(render_process_id)) - process_host->OnMediaStreamAdded(); + NotifyProcessHostOfStartedStream(render_process_id); } AudioLoopbackStreamBroker::~AudioLoopbackStreamBroker() { - DCHECK_CURRENTLY_ON(BrowserThread::UI); + DCHECK_CURRENTLY_ON(BrowserThread::IO); if (source_) source_->RemoveLoopbackSink(this); - if (auto* process_host = RenderProcessHost::FromID(render_process_id())) - process_host->OnMediaStreamRemoved(); + NotifyProcessHostOfStoppedStream(render_process_id()); } void AudioLoopbackStreamBroker::CreateStream( audio::mojom::StreamFactory* factory) { - DCHECK_CURRENTLY_ON(BrowserThread::UI); + DCHECK_CURRENTLY_ON(BrowserThread::IO); DCHECK(!observer_binding_.is_bound()); DCHECK(!client_request_); DCHECK(source_); @@ -93,20 +94,20 @@ } void AudioLoopbackStreamBroker::OnSourceGone() { - DCHECK_CURRENTLY_ON(BrowserThread::UI); + DCHECK_CURRENTLY_ON(BrowserThread::IO); // No further access to |source_| is allowed. source_ = nullptr; Cleanup(); } void AudioLoopbackStreamBroker::DidStartRecording() { - DCHECK_CURRENTLY_ON(BrowserThread::UI); + DCHECK_CURRENTLY_ON(BrowserThread::IO); } void AudioLoopbackStreamBroker::StreamCreated( media::mojom::AudioInputStreamPtr stream, media::mojom::ReadOnlyAudioDataPipePtr data_pipe) { - DCHECK_CURRENTLY_ON(BrowserThread::UI); + DCHECK_CURRENTLY_ON(BrowserThread::IO); if (!data_pipe) { Cleanup(); @@ -121,7 +122,7 @@ } void AudioLoopbackStreamBroker::Cleanup() { - DCHECK_CURRENTLY_ON(BrowserThread::UI); + DCHECK_CURRENTLY_ON(BrowserThread::IO); std::move(deleter_).Run(this); }
diff --git a/content/browser/media/audio_loopback_stream_broker.h b/content/browser/media/audio_loopback_stream_broker.h index e7425363..aa1f6f6 100644 --- a/content/browser/media/audio_loopback_stream_broker.h +++ b/content/browser/media/audio_loopback_stream_broker.h
@@ -5,18 +5,25 @@ #ifndef CONTENT_BROWSER_MEDIA_AUDIO_LOOPBACK_STREAM_BROKER_H_ #define CONTENT_BROWSER_MEDIA_AUDIO_LOOPBACK_STREAM_BROKER_H_ +#include <cstdint> #include <string> +#include "base/macros.h" #include "base/memory/weak_ptr.h" #include "base/optional.h" -#include "base/sequence_checker.h" #include "content/browser/media/audio_muting_session.h" #include "content/browser/media/audio_stream_broker.h" #include "content/common/content_export.h" #include "media/base/audio_parameters.h" +#include "media/mojo/interfaces/audio_data_pipe.mojom.h" #include "media/mojo/interfaces/audio_input_stream.mojom.h" #include "mojo/public/cpp/bindings/binding.h" -#include "services/audio/public/mojom/stream_factory.mojom.h" + +namespace audio { +namespace mojom { +class StreamFactory; +} +} // namespace audio namespace content { @@ -46,7 +53,7 @@ void DidStartRecording() final; // AudioStreamBroker::LoopbackSink - void OnSourceGone() override; + void OnSourceGone() final; private: void StreamCreated(media::mojom::AudioInputStreamPtr stream,
diff --git a/content/browser/media/audio_stream_broker.cc b/content/browser/media/audio_stream_broker.cc index 5f58941e..875d810e 100644 --- a/content/browser/media/audio_stream_broker.cc +++ b/content/browser/media/audio_stream_broker.cc
@@ -6,9 +6,15 @@ #include <utility> +#include "base/bind.h" +#include "base/location.h" +#include "base/task/post_task.h" #include "content/browser/media/audio_input_stream_broker.h" #include "content/browser/media/audio_loopback_stream_broker.h" #include "content/browser/media/audio_output_stream_broker.h" +#include "content/public/browser/browser_task_traits.h" +#include "content/public/browser/browser_thread.h" +#include "content/public/browser/render_process_host.h" namespace content { @@ -82,6 +88,28 @@ render_frame_id_(render_frame_id) {} AudioStreamBroker::~AudioStreamBroker() {} +// static +void AudioStreamBroker::NotifyProcessHostOfStartedStream( + int render_process_id) { + auto impl = [](int id) { + if (auto* process_host = RenderProcessHost::FromID(id)) + process_host->OnMediaStreamAdded(); + }; + base::PostTaskWithTraits(FROM_HERE, {BrowserThread::UI}, + base::BindOnce(impl, render_process_id)); +} + +// static +void AudioStreamBroker::NotifyProcessHostOfStoppedStream( + int render_process_id) { + auto impl = [](int id) { + if (auto* process_host = RenderProcessHost::FromID(id)) + process_host->OnMediaStreamRemoved(); + }; + base::PostTaskWithTraits(FROM_HERE, {BrowserThread::UI}, + base::BindOnce(impl, render_process_id)); +} + AudioStreamBrokerFactory::AudioStreamBrokerFactory() {} AudioStreamBrokerFactory::~AudioStreamBrokerFactory() {}
diff --git a/content/browser/media/audio_stream_broker.h b/content/browser/media/audio_stream_broker.h index a5f0880..24d8928f 100644 --- a/content/browser/media/audio_stream_broker.h +++ b/content/browser/media/audio_stream_broker.h
@@ -5,12 +5,13 @@ #ifndef CONTENT_BROWSER_MEDIA_AUDIO_STREAM_BROKER_H_ #define CONTENT_BROWSER_MEDIA_AUDIO_STREAM_BROKER_H_ +#include <cstdint> #include <memory> #include <string> -#include <utility> #include "base/callback.h" #include "base/macros.h" +#include "base/optional.h" #include "content/common/content_export.h" #include "content/common/media/renderer_audio_input_stream_factory.mojom.h" #include "media/mojo/interfaces/audio_input_stream.mojom.h" @@ -36,7 +37,8 @@ // An AudioStreamBroker is used to broker a connection between a client // (typically renderer) and the audio service. It also sets up all objects -// used for monitoring the stream. +// used for monitoring the stream. All AudioStreamBrokers are used on the IO +// thread. class CONTENT_EXPORT AudioStreamBroker { public: class CONTENT_EXPORT LoopbackSink { @@ -68,6 +70,13 @@ virtual void CreateStream(audio::mojom::StreamFactory* factory) = 0; + // Thread-safe utility that notifies the process host identified by + // |render_process_id| of a started stream to ensure that the renderer is not + // backgrounded. Must be paired with a later call to + // NotifyRenderProcessOfStoppedStream() + static void NotifyProcessHostOfStartedStream(int render_process_id); + static void NotifyProcessHostOfStoppedStream(int render_process_id); + int render_process_id() const { return render_process_id_; } int render_frame_id() const { return render_frame_id_; } @@ -79,7 +88,8 @@ DISALLOW_COPY_AND_ASSIGN(AudioStreamBroker); }; -// Used for dependency injection into ForwardingAudioStreamFactory. +// Used for dependency injection into ForwardingAudioStreamFactory. Used on the +// IO thread. class CONTENT_EXPORT AudioStreamBrokerFactory { public: static std::unique_ptr<AudioStreamBrokerFactory> CreateImpl();
diff --git a/content/browser/media/forwarding_audio_stream_factory.cc b/content/browser/media/forwarding_audio_stream_factory.cc index a76d573..bcdea97 100644 --- a/content/browser/media/forwarding_audio_stream_factory.cc +++ b/content/browser/media/forwarding_audio_stream_factory.cc
@@ -6,39 +6,174 @@ #include <utility> +#include "base/bind.h" +#include "base/location.h" +#include "base/logging.h" +#include "base/stl_util.h" +#include "base/task/post_task.h" #include "base/trace_event/trace_event.h" #include "content/browser/web_contents/web_contents_impl.h" +#include "content/public/browser/browser_task_traits.h" #include "content/public/browser/browser_thread.h" -#include "content/public/browser/navigation_handle.h" #include "content/public/browser/render_frame_host.h" #include "content/public/browser/render_process_host.h" #include "content/public/browser/web_contents.h" +#include "media/base/audio_parameters.h" #include "media/base/user_input_monitor.h" #include "services/audio/public/mojom/constants.mojom.h" #include "services/service_manager/public/cpp/connector.h" +#include "ui/gfx/geometry/size.h" namespace content { -ForwardingAudioStreamFactory::ForwardingAudioStreamFactory( - WebContents* web_contents, +ForwardingAudioStreamFactory::Core::Core( + base::WeakPtr<ForwardingAudioStreamFactory> owner, media::UserInputMonitorBase* user_input_monitor, std::unique_ptr<service_manager::Connector> connector, std::unique_ptr<AudioStreamBrokerFactory> broker_factory) - : WebContentsObserver(web_contents), - user_input_monitor_(user_input_monitor), - connector_(std::move(connector)), + : user_input_monitor_(user_input_monitor), + owner_(std::move(owner)), broker_factory_(std::move(broker_factory)), - group_id_(base::UnguessableToken::Create()) { + group_id_(base::UnguessableToken::Create()), + connector_(std::move(connector)) { DCHECK_CURRENTLY_ON(BrowserThread::UI); + DCHECK(owner_); DCHECK(broker_factory_); + DCHECK(connector_); } -ForwardingAudioStreamFactory::~ForwardingAudioStreamFactory() { - DCHECK_CURRENTLY_ON(BrowserThread::UI); +ForwardingAudioStreamFactory::Core::~Core() { + DCHECK_CURRENTLY_ON(BrowserThread::IO); for (AudioStreamBroker::LoopbackSink* sink : loopback_sinks_) sink->OnSourceGone(); } +void ForwardingAudioStreamFactory::Core::CreateInputStream( + int render_process_id, + int render_frame_id, + const std::string& device_id, + const media::AudioParameters& params, + uint32_t shared_memory_count, + bool enable_agc, + audio::mojom::AudioProcessingConfigPtr processing_config, + mojom::RendererAudioInputStreamFactoryClientPtr renderer_factory_client) { + DCHECK_CURRENTLY_ON(BrowserThread::IO); + + // |this| owns |inputs_|, so Unretained is safe. + inputs_ + .insert(broker_factory_->CreateAudioInputStreamBroker( + render_process_id, render_frame_id, device_id, params, + shared_memory_count, user_input_monitor_, enable_agc, + std::move(processing_config), + base::BindOnce(&ForwardingAudioStreamFactory::Core::RemoveInput, + base::Unretained(this)), + std::move(renderer_factory_client))) + .first->get() + ->CreateStream(GetFactory()); +} + +void ForwardingAudioStreamFactory::Core::AssociateInputAndOutputForAec( + const base::UnguessableToken& input_stream_id, + const std::string& raw_output_device_id) { + DCHECK_CURRENTLY_ON(BrowserThread::IO); + // Avoid spawning a factory if this for some reason gets called with an + // invalid |input_stream_id| before any streams are created. + if (!inputs_.empty()) { + GetFactory()->AssociateInputAndOutputForAec(input_stream_id, + raw_output_device_id); + } +} + +void ForwardingAudioStreamFactory::Core::CreateOutputStream( + int render_process_id, + int render_frame_id, + const std::string& device_id, + const media::AudioParameters& params, + const base::Optional<base::UnguessableToken>& processing_id, + media::mojom::AudioOutputStreamProviderClientPtr client) { + DCHECK_CURRENTLY_ON(BrowserThread::IO); + + // |this| owns |outputs_|, so Unretained is safe. + outputs_ + .insert(broker_factory_->CreateAudioOutputStreamBroker( + render_process_id, render_frame_id, ++stream_id_counter_, device_id, + params, group_id_, processing_id, + base::BindOnce(&ForwardingAudioStreamFactory::Core::RemoveOutput, + base::Unretained(this)), + std::move(client))) + .first->get() + ->CreateStream(GetFactory()); +} + +void ForwardingAudioStreamFactory::Core::CreateLoopbackStream( + int render_process_id, + int render_frame_id, + AudioStreamBroker::LoopbackSource* loopback_source, + const media::AudioParameters& params, + uint32_t shared_memory_count, + bool mute_source, + mojom::RendererAudioInputStreamFactoryClientPtr renderer_factory_client) { + DCHECK_CURRENTLY_ON(BrowserThread::IO); + DCHECK(loopback_source); + + TRACE_EVENT_BEGIN1("audio", "CreateLoopbackStream", "group", + group_id_.GetLowForSerialization()); + + // |this| owns |inputs_|, so Unretained is safe. + inputs_ + .insert(broker_factory_->CreateAudioLoopbackStreamBroker( + render_process_id, render_frame_id, loopback_source, params, + shared_memory_count, mute_source, + base::BindOnce(&ForwardingAudioStreamFactory::Core::RemoveInput, + base::Unretained(this)), + std::move(renderer_factory_client))) + .first->get() + ->CreateStream(GetFactory()); + TRACE_EVENT_END1("audio", "CreateLoopbackStream", "source", + loopback_source->GetGroupID().GetLowForSerialization()); +} + +void ForwardingAudioStreamFactory::Core::SetMuted(bool muted) { + DCHECK_CURRENTLY_ON(BrowserThread::IO); + DCHECK_NE(muted, !!muter_); + TRACE_EVENT_INSTANT2("audio", "SetMuted", TRACE_EVENT_SCOPE_THREAD, "group", + group_id_.GetLowForSerialization(), "muted", muted); + + if (!muted) { + muter_.reset(); + return; + } + + muter_.emplace(group_id_); + if (remote_factory_) + muter_->Connect(remote_factory_.get()); +} + +void ForwardingAudioStreamFactory::Core::AddLoopbackSink( + AudioStreamBroker::LoopbackSink* sink) { + DCHECK_CURRENTLY_ON(BrowserThread::IO); + loopback_sinks_.insert(sink); + base::PostTaskWithTraits( + FROM_HERE, {BrowserThread::UI}, + base::BindOnce(&ForwardingAudioStreamFactory::LoopbackStreamStarted, + owner_)); +} + +void ForwardingAudioStreamFactory::Core::RemoveLoopbackSink( + AudioStreamBroker::LoopbackSink* sink) { + DCHECK_CURRENTLY_ON(BrowserThread::IO); + loopback_sinks_.erase(sink); + base::PostTaskWithTraits( + FROM_HERE, {BrowserThread::UI}, + base::BindOnce(&ForwardingAudioStreamFactory::LoopbackStreamStopped, + owner_)); +} + +const base::UnguessableToken& ForwardingAudioStreamFactory::Core::GetGroupID() { + DCHECK_CURRENTLY_ON(BrowserThread::IO); + return group_id(); +} + // static ForwardingAudioStreamFactory* ForwardingAudioStreamFactory::ForFrame( RenderFrameHost* frame) { @@ -52,154 +187,95 @@ return contents->GetAudioStreamFactory(); } -void ForwardingAudioStreamFactory::CreateInputStream( - RenderFrameHost* frame, - const std::string& device_id, - const media::AudioParameters& params, - uint32_t shared_memory_count, - bool enable_agc, - audio::mojom::AudioProcessingConfigPtr processing_config, - mojom::RendererAudioInputStreamFactoryClientPtr renderer_factory_client) { +// static +ForwardingAudioStreamFactory::Core* ForwardingAudioStreamFactory::CoreForFrame( + RenderFrameHost* frame) { DCHECK_CURRENTLY_ON(BrowserThread::UI); - - const int process_id = frame ? frame->GetProcess()->GetID() : -1; - const int frame_id = frame ? frame->GetRoutingID() : -1; - inputs_ - .insert(broker_factory_->CreateAudioInputStreamBroker( - process_id, frame_id, device_id, params, shared_memory_count, - user_input_monitor_, enable_agc, std::move(processing_config), - base::BindOnce(&ForwardingAudioStreamFactory::RemoveInput, - base::Unretained(this)), - std::move(renderer_factory_client))) - .first->get() - ->CreateStream(GetFactory()); + ForwardingAudioStreamFactory* forwarding_factory = + ForwardingAudioStreamFactory::ForFrame(frame); + return forwarding_factory ? forwarding_factory->core() : nullptr; } -void ForwardingAudioStreamFactory::AssociateInputAndOutputForAec( - const base::UnguessableToken& input_stream_id, - const std::string& raw_output_device_id) { +ForwardingAudioStreamFactory::ForwardingAudioStreamFactory( + WebContents* web_contents, + media::UserInputMonitorBase* user_input_monitor, + std::unique_ptr<service_manager::Connector> connector, + std::unique_ptr<AudioStreamBrokerFactory> broker_factory) + : WebContentsObserver(web_contents), core_(), weak_ptr_factory_(this) { DCHECK_CURRENTLY_ON(BrowserThread::UI); - // Avoid spawning a factory if this for some reason gets called with an - // invalid |input_stream_id| before any streams are created. - if (!inputs_.empty()) { - GetFactory()->AssociateInputAndOutputForAec(input_stream_id, - raw_output_device_id); - } + core_ = + std::make_unique<Core>(weak_ptr_factory_.GetWeakPtr(), user_input_monitor, + std::move(connector), std::move(broker_factory)); } -void ForwardingAudioStreamFactory::CreateOutputStream( - RenderFrameHost* frame, - const std::string& device_id, - const media::AudioParameters& params, - const base::Optional<base::UnguessableToken>& processing_id, - media::mojom::AudioOutputStreamProviderClientPtr client) { +ForwardingAudioStreamFactory::~ForwardingAudioStreamFactory() { DCHECK_CURRENTLY_ON(BrowserThread::UI); - - const int process_id = frame->GetProcess()->GetID(); - const int frame_id = frame->GetRoutingID(); - - outputs_ - .insert(broker_factory_->CreateAudioOutputStreamBroker( - process_id, frame_id, ++stream_id_counter_, device_id, params, - group_id_, processing_id, - base::BindOnce(&ForwardingAudioStreamFactory::RemoveOutput, - base::Unretained(this)), - std::move(client))) - .first->get() - ->CreateStream(GetFactory()); + // Ensure |core_| is deleted on the right thread. DeleteOnIOThread isn't used + // as it doesn't post in case it is already executed on the right thread. That + // causes issues in unit tests where the UI thread and the IO thread are the + // same. + base::PostTaskWithTraits( + FROM_HERE, {BrowserThread::IO}, + base::BindOnce([](std::unique_ptr<Core>) {}, std::move(core_))); } -void ForwardingAudioStreamFactory::CreateLoopbackStream( - RenderFrameHost* frame, - ForwardingAudioStreamFactory* loopback_source, - const media::AudioParameters& params, - uint32_t shared_memory_count, - bool mute_source, - mojom::RendererAudioInputStreamFactoryClientPtr renderer_factory_client) { +void ForwardingAudioStreamFactory::LoopbackStreamStarted() { DCHECK_CURRENTLY_ON(BrowserThread::UI); - DCHECK(loopback_source); + web_contents()->IncrementCapturerCount(gfx::Size()); +} - TRACE_EVENT_BEGIN1("audio", "CreateLoopbackStream", "group", - group_id_.GetLowForSerialization()); - - const int process_id = frame ? frame->GetProcess()->GetID() : -1; - const int frame_id = frame ? frame->GetRoutingID() : -1; - inputs_ - .insert(broker_factory_->CreateAudioLoopbackStreamBroker( - process_id, frame_id, loopback_source, params, shared_memory_count, - mute_source, - base::BindOnce(&ForwardingAudioStreamFactory::RemoveInput, - base::Unretained(this)), - std::move(renderer_factory_client))) - .first->get() - ->CreateStream(GetFactory()); - TRACE_EVENT_END1("audio", "CreateLoopbackStream", "source", - loopback_source->group_id().GetLowForSerialization()); +void ForwardingAudioStreamFactory::LoopbackStreamStopped() { + DCHECK_CURRENTLY_ON(BrowserThread::UI); + web_contents()->DecrementCapturerCount(); } void ForwardingAudioStreamFactory::SetMuted(bool muted) { DCHECK_CURRENTLY_ON(BrowserThread::UI); - DCHECK_NE(muted, IsMuted()); - TRACE_EVENT_INSTANT2("audio", "SetMuted", TRACE_EVENT_SCOPE_THREAD, "group", - group_id_.GetLowForSerialization(), "muted", muted); + if (is_muted_ != muted) { + is_muted_ = muted; - if (!muted) { - muter_.reset(); - return; + // Unretained is safe since the destruction of |core_| will be posted to the + // IO thread later. + base::PostTaskWithTraits( + FROM_HERE, {BrowserThread::IO}, + base::BindOnce(&Core::SetMuted, base::Unretained(core_.get()), muted)); } - - muter_.emplace(group_id_); - if (remote_factory_) - muter_->Connect(remote_factory_.get()); } bool ForwardingAudioStreamFactory::IsMuted() const { DCHECK_CURRENTLY_ON(BrowserThread::UI); - return !!muter_; -} - -void ForwardingAudioStreamFactory::AddLoopbackSink( - AudioStreamBroker::LoopbackSink* sink) { - DCHECK_CURRENTLY_ON(BrowserThread::UI); - loopback_sinks_.insert(sink); - web_contents()->IncrementCapturerCount(gfx::Size()); -} - -void ForwardingAudioStreamFactory::RemoveLoopbackSink( - AudioStreamBroker::LoopbackSink* sink) { - DCHECK_CURRENTLY_ON(BrowserThread::UI); - loopback_sinks_.erase(sink); - web_contents()->DecrementCapturerCount(); -} - -const base::UnguessableToken& ForwardingAudioStreamFactory::GetGroupID() { - return group_id_; + return is_muted_; } void ForwardingAudioStreamFactory::FrameDeleted( RenderFrameHost* render_frame_host) { DCHECK_CURRENTLY_ON(BrowserThread::UI); DCHECK(render_frame_host); - CleanupStreamsBelongingTo(render_frame_host); + + // Unretained is safe since the destruction of |core_| will be posted to the + // IO thread later. + base::PostTaskWithTraits( + FROM_HERE, {BrowserThread::IO}, + base::BindOnce(&Core::CleanupStreamsBelongingTo, + base::Unretained(core_.get()), + render_frame_host->GetProcess()->GetID(), + render_frame_host->GetRoutingID())); } -void ForwardingAudioStreamFactory::CleanupStreamsBelongingTo( - RenderFrameHost* render_frame_host) { - DCHECK_CURRENTLY_ON(BrowserThread::UI); - DCHECK(render_frame_host); - - const int process_id = render_frame_host->GetProcess()->GetID(); - const int frame_id = render_frame_host->GetRoutingID(); +void ForwardingAudioStreamFactory::Core::CleanupStreamsBelongingTo( + int render_process_id, + int render_frame_id) { + DCHECK_CURRENTLY_ON(BrowserThread::IO); TRACE_EVENT_BEGIN2("audio", "CleanupStreamsBelongingTo", "group", group_id_.GetLowForSerialization(), "process id", - process_id); + render_process_id); auto match_rfh = - [process_id, - frame_id](const std::unique_ptr<AudioStreamBroker>& broker) -> bool { - return broker->render_process_id() == process_id && - broker->render_frame_id() == frame_id; + [render_process_id, render_frame_id]( + const std::unique_ptr<AudioStreamBroker>& broker) -> bool { + return broker->render_process_id() == render_process_id && + broker->render_frame_id() == render_frame_id; }; base::EraseIf(outputs_, match_rfh); @@ -207,27 +283,30 @@ ResetRemoteFactoryPtrIfIdle(); - TRACE_EVENT_END1("audio", "CleanupStreamsBelongingTo", "frame_id", frame_id); + TRACE_EVENT_END1("audio", "CleanupStreamsBelongingTo", "frame_id", + render_frame_id); } -void ForwardingAudioStreamFactory::RemoveInput(AudioStreamBroker* broker) { - DCHECK_CURRENTLY_ON(BrowserThread::UI); +void ForwardingAudioStreamFactory::Core::RemoveInput( + AudioStreamBroker* broker) { + DCHECK_CURRENTLY_ON(BrowserThread::IO); size_t removed = inputs_.erase(broker); DCHECK_EQ(1u, removed); ResetRemoteFactoryPtrIfIdle(); } -void ForwardingAudioStreamFactory::RemoveOutput(AudioStreamBroker* broker) { - DCHECK_CURRENTLY_ON(BrowserThread::UI); +void ForwardingAudioStreamFactory::Core::RemoveOutput( + AudioStreamBroker* broker) { + DCHECK_CURRENTLY_ON(BrowserThread::IO); size_t removed = outputs_.erase(broker); DCHECK_EQ(1u, removed); ResetRemoteFactoryPtrIfIdle(); } -audio::mojom::StreamFactory* ForwardingAudioStreamFactory::GetFactory() { - DCHECK_CURRENTLY_ON(BrowserThread::UI); +audio::mojom::StreamFactory* ForwardingAudioStreamFactory::Core::GetFactory() { + DCHECK_CURRENTLY_ON(BrowserThread::IO); if (!remote_factory_) { TRACE_EVENT_INSTANT1( "audio", "ForwardingAudioStreamFactory: Binding new factory", @@ -235,9 +314,9 @@ connector_->BindInterface(audio::mojom::kServiceName, mojo::MakeRequest(&remote_factory_)); // Unretained is safe because |this| owns |remote_factory_|. - remote_factory_.set_connection_error_handler( - base::BindOnce(&ForwardingAudioStreamFactory::ResetRemoteFactoryPtr, - base::Unretained(this))); + remote_factory_.set_connection_error_handler(base::BindOnce( + &ForwardingAudioStreamFactory::Core::ResetRemoteFactoryPtr, + base::Unretained(this))); // Restore the muting session on reconnect. if (muter_) @@ -247,14 +326,14 @@ return remote_factory_.get(); } -void ForwardingAudioStreamFactory::ResetRemoteFactoryPtrIfIdle() { - DCHECK_CURRENTLY_ON(BrowserThread::UI); +void ForwardingAudioStreamFactory::Core::ResetRemoteFactoryPtrIfIdle() { + DCHECK_CURRENTLY_ON(BrowserThread::IO); if (inputs_.empty() && outputs_.empty()) ResetRemoteFactoryPtr(); } -void ForwardingAudioStreamFactory::ResetRemoteFactoryPtr() { - DCHECK_CURRENTLY_ON(BrowserThread::UI); +void ForwardingAudioStreamFactory::Core::ResetRemoteFactoryPtr() { + DCHECK_CURRENTLY_ON(BrowserThread::IO); if (remote_factory_) { TRACE_EVENT_INSTANT1( "audio", "ForwardingAudioStreamFactory: Resetting factory",
diff --git a/content/browser/media/forwarding_audio_stream_factory.h b/content/browser/media/forwarding_audio_stream_factory.h index e7b518f..f0c9e20 100644 --- a/content/browser/media/forwarding_audio_stream_factory.h +++ b/content/browser/media/forwarding_audio_stream_factory.h
@@ -5,12 +5,14 @@ #ifndef CONTENT_BROWSER_MEDIA_FORWARDING_AUDIO_STREAM_FACTORY_H_ #define CONTENT_BROWSER_MEDIA_FORWARDING_AUDIO_STREAM_FACTORY_H_ +#include <cstdint> #include <memory> #include <string> #include "base/containers/flat_set.h" #include "base/containers/unique_ptr_adapters.h" #include "base/macros.h" +#include "base/memory/weak_ptr.h" #include "base/optional.h" #include "base/unguessable_token.h" #include "content/browser/media/audio_muting_session.h" @@ -18,6 +20,8 @@ #include "content/common/content_export.h" #include "content/common/media/renderer_audio_input_stream_factory.mojom.h" #include "content/public/browser/web_contents_observer.h" +#include "media/mojo/interfaces/audio_output_stream.mojom.h" +#include "services/audio/public/mojom/audio_processing.mojom.h" #include "services/audio/public/mojom/stream_factory.mojom.h" namespace service_manager { @@ -26,22 +30,150 @@ namespace media { class AudioParameters; +class UserInputMonitorBase; } namespace content { -class AudioStreamBroker; class RenderFrameHost; class WebContents; // This class handles stream creation operations for a WebContents. // This class is operated on the UI thread. class CONTENT_EXPORT ForwardingAudioStreamFactory final - : public WebContentsObserver, - public AudioStreamBroker::LoopbackSource { + : public WebContentsObserver { public: + // Note: all methods of Core may only be called on the IO thread except for + // the constructor. The destruction of Core is posted to the IO thread when + // the owning ForwardingAudioStreamFactory is destructed, so any task posted + // to the IO thread while the ForwardingAudioStreamFactory is alive may post + // |core()| using base::Unretained. + class CONTENT_EXPORT Core final : public AudioStreamBroker::LoopbackSource { + public: + Core(base::WeakPtr<ForwardingAudioStreamFactory> owner, + media::UserInputMonitorBase* user_input_monitor, + std::unique_ptr<service_manager::Connector> connector, + std::unique_ptr<AudioStreamBrokerFactory> factory); + ~Core() final; + + const base::UnguessableToken& group_id() const { return group_id_; } + + // E.g. to override binder. + service_manager::Connector* get_connector_for_testing() { + return connector_.get(); + } + + // TODO(https://crbug.com/787806): Automatically restore streams on audio + // service restart. + void CreateInputStream( + int render_process_id, + int render_frame_id, + const std::string& device_id, + const media::AudioParameters& params, + uint32_t shared_memory_count, + bool enable_agc, + audio::mojom::AudioProcessingConfigPtr processing_config, + mojom::RendererAudioInputStreamFactoryClientPtr + renderer_factory_client); + + void AssociateInputAndOutputForAec( + const base::UnguessableToken& input_stream_id, + const std::string& raw_output_device_id); + + void CreateOutputStream( + int render_process_id, + int render_frame_id, + const std::string& device_id, + const media::AudioParameters& params, + const base::Optional<base::UnguessableToken>& processing_id, + media::mojom::AudioOutputStreamProviderClientPtr client); + + void CreateLoopbackStream( + int render_process_id, + int render_frame_id, + AudioStreamBroker::LoopbackSource* loopback_source, + const media::AudioParameters& params, + uint32_t shared_memory_count, + bool mute_source, + mojom::RendererAudioInputStreamFactoryClientPtr + renderer_factory_client); + + // Sets the muting state for all output streams created through this + // factory. + void SetMuted(bool muted); + + // AudioStreamLoopback::Source implementation + void AddLoopbackSink(AudioStreamBroker::LoopbackSink* sink) final; + void RemoveLoopbackSink(AudioStreamBroker::LoopbackSink* sink) final; + const base::UnguessableToken& GetGroupID() final; // Actually const. + + private: + // For CleanupStreamsBelongingTo. + friend class ForwardingAudioStreamFactory; + + using StreamBrokerSet = base::flat_set<std::unique_ptr<AudioStreamBroker>, + base::UniquePtrComparator>; + + void CleanupStreamsBelongingTo(int render_process_id, int render_frame_id); + + void RemoveInput(AudioStreamBroker* handle); + void RemoveOutput(AudioStreamBroker* handle); + + audio::mojom::StreamFactory* GetFactory(); + void ResetRemoteFactoryPtrIfIdle(); + void ResetRemoteFactoryPtr(); + + media::UserInputMonitorBase* const user_input_monitor_; + + // Used for posting tasks the UI thread to communicate when a loopback + // stream is started/stopped. Weak since |this| on the IO thread outlives + // |owner| on the UI thread. + const base::WeakPtr<ForwardingAudioStreamFactory> owner_; + + const std::unique_ptr<AudioStreamBrokerFactory> broker_factory_; + + // Unique id identifying all streams belonging to the WebContents owning + // |this|. + const base::UnguessableToken group_id_; + + const std::unique_ptr<service_manager::Connector> connector_; + + // Lazily acquired. Reset on connection error and when we no longer have any + // streams. Note: we don't want muting to force the connection to be open, + // since we want to clean up the service when not in use. If we have active + // muting but nothing else, we should stop it and start it again when we + // need to reacquire the factory for some other reason. + audio::mojom::StreamFactoryPtr remote_factory_; + + // Running id used for tracking audible streams. We keep count here to avoid + // collisions. + // TODO(https://crbug.com/830494): Refactor to make this unnecessary and + // remove it. + int stream_id_counter_ = 0; + + // Instantiated when |outputs_| should be muted, empty otherwise. + base::Optional<AudioMutingSession> muter_; + + StreamBrokerSet inputs_; + StreamBrokerSet outputs_; + base::flat_set<AudioStreamBroker::LoopbackSink*> loopback_sinks_; + DISALLOW_COPY_AND_ASSIGN(Core); + }; + + // Returns the ForwardingAudioStreamFactory which takes care of stream + // creation for |frame|. Returns null if |frame| is null or if the frame + // doesn't belong to a WebContents. + static ForwardingAudioStreamFactory* ForFrame(RenderFrameHost* frame); + + // Returns the ForwardingAudioStreamFactory::Core which takes care of stream + // creation for |frame|. Returns null if |frame| is null or if the frame + // doesn't belong to a WebContents. + static ForwardingAudioStreamFactory::Core* CoreForFrame( + RenderFrameHost* frame); + // |web_contents| is null in the browser-privileged access case, i.e., when // the streams created with this factory will not be consumed by a renderer. + // |connector| will be used on the IO thread. ForwardingAudioStreamFactory( WebContents* web_contents, media::UserInputMonitorBase* user_input_monitor, @@ -50,42 +182,14 @@ ~ForwardingAudioStreamFactory() final; - // Returns the ForwardingAudioStreamFactory which takes care of stream - // creation for |frame|. Returns null if |frame| is null or if the frame - // doesn't belong to a WebContents. - static ForwardingAudioStreamFactory* ForFrame(RenderFrameHost* frame); + const base::UnguessableToken& group_id() const { + // Thread-safe since Core::group_id is thread-safe and |core_| outlives + // |this|. + return core_->group_id(); + } - const base::UnguessableToken& group_id() { return group_id_; } - - // TODO(https://crbug.com/787806): Automatically restore streams on audio - // service restart. - void CreateInputStream( - RenderFrameHost* frame, - const std::string& device_id, - const media::AudioParameters& params, - uint32_t shared_memory_count, - bool enable_agc, - audio::mojom::AudioProcessingConfigPtr processing_config, - mojom::RendererAudioInputStreamFactoryClientPtr renderer_factory_client); - - void AssociateInputAndOutputForAec( - const base::UnguessableToken& input_stream_id, - const std::string& raw_output_device_id); - - void CreateOutputStream( - RenderFrameHost* frame, - const std::string& device_id, - const media::AudioParameters& params, - const base::Optional<base::UnguessableToken>& processing_id, - media::mojom::AudioOutputStreamProviderClientPtr client); - - void CreateLoopbackStream( - RenderFrameHost* frame, - ForwardingAudioStreamFactory* loopback_source, - const media::AudioParameters& params, - uint32_t shared_memory_count, - bool mute_source, - mojom::RendererAudioInputStreamFactoryClientPtr renderer_factory_client); + void LoopbackStreamStarted(); + void LoopbackStreamStopped(); // Sets the muting state for all output streams created through this factory. void SetMuted(bool muted); @@ -93,62 +197,17 @@ // Returns the current muting state. bool IsMuted() const; - // AudioStreamLoopback::Source implementation - void AddLoopbackSink(AudioStreamBroker::LoopbackSink* sink) final; - void RemoveLoopbackSink(AudioStreamBroker::LoopbackSink* sink) final; - const base::UnguessableToken& GetGroupID() final; - // WebContentsObserver implementation. We observe these events so that we can // clean up streams belonging to a frame when that frame is destroyed. void FrameDeleted(RenderFrameHost* render_frame_host) final; - // E.g. to override binder. - service_manager::Connector* get_connector_for_testing() { - return connector_.get(); - } + Core* core() { return core_.get(); } private: - using StreamBrokerSet = base::flat_set<std::unique_ptr<AudioStreamBroker>, - base::UniquePtrComparator>; + std::unique_ptr<Core> core_; + bool is_muted_ = false; - void CleanupStreamsBelongingTo(RenderFrameHost* render_frame_host); - - void RemoveInput(AudioStreamBroker* handle); - void RemoveOutput(AudioStreamBroker* handle); - - audio::mojom::StreamFactory* GetFactory(); - void ResetRemoteFactoryPtrIfIdle(); - void ResetRemoteFactoryPtr(); - - media::UserInputMonitorBase* const user_input_monitor_; - - const std::unique_ptr<service_manager::Connector> connector_; - const std::unique_ptr<AudioStreamBrokerFactory> broker_factory_; - - // Unique id indentifying all streams belonging to the WebContents owning - // |this|. - // TODO(https://crbug.com/824019): Use this for loopback. - const base::UnguessableToken group_id_; - - // Lazily acquired. Reset on connection error and when we no longer have any - // streams. Note: we don't want muting to force the connection to be open, - // since we want to clean up the service when not in use. If we have active - // muting but nothing else, we should stop it and start it again when we need - // to reacquire the factory for some other reason. - audio::mojom::StreamFactoryPtr remote_factory_; - - // Running id used for tracking audible streams. We keep count here to avoid - // collisions. - // TODO(https://crbug.com/830494): Refactor to make this unnecessary and - // remove it. - int stream_id_counter_ = 0; - - // Instantiated when |outputs_| should be muted, empty otherwise. - base::Optional<AudioMutingSession> muter_; - - StreamBrokerSet inputs_; - StreamBrokerSet outputs_; - base::flat_set<AudioStreamBroker::LoopbackSink*> loopback_sinks_; + base::WeakPtrFactory<ForwardingAudioStreamFactory> weak_ptr_factory_; DISALLOW_COPY_AND_ASSIGN(ForwardingAudioStreamFactory); };
diff --git a/content/browser/media/forwarding_audio_stream_factory_unittest.cc b/content/browser/media/forwarding_audio_stream_factory_unittest.cc index 0fcc2ce6..d390f5817 100644 --- a/content/browser/media/forwarding_audio_stream_factory_unittest.cc +++ b/content/browser/media/forwarding_audio_stream_factory_unittest.cc
@@ -272,9 +272,10 @@ EXPECT_CALL(*broker, CreateStream(NotNull())); mojo::MakeRequest(&client); - factory.CreateInputStream(main_rfh(), kInputDeviceId, kParams, - kSharedMemoryCount, kEnableAgc, nullptr, - std::move(client)); + factory.core()->CreateInputStream(main_rfh()->GetProcess()->GetID(), + main_rfh()->GetRoutingID(), kInputDeviceId, + kParams, kSharedMemoryCount, kEnableAgc, + nullptr, std::move(client)); } TEST_F(ForwardingAudioStreamFactoryTest, @@ -284,19 +285,23 @@ base::WeakPtr<MockBroker> broker = ExpectLoopbackBrokerConstruction(main_rfh()); + std::unique_ptr<service_manager::Connector> other_connector = + connector_->Clone(); + ForwardingAudioStreamFactory factory( web_contents(), nullptr /*user_input_monitor*/, std::move(connector_), std::move(broker_factory_)); ForwardingAudioStreamFactory source_factory( source_contents.get(), nullptr /*user_input_monitor*/, - std::move(connector_), std::make_unique<MockBrokerFactory>()); + std::move(other_connector), std::make_unique<MockBrokerFactory>()); EXPECT_CALL(*broker, CreateStream(NotNull())); mojo::MakeRequest(&client); - factory.CreateLoopbackStream(main_rfh(), &source_factory, kParams, - kSharedMemoryCount, kMuteSource, - std::move(client)); + factory.core()->CreateLoopbackStream( + main_rfh()->GetProcess()->GetID(), main_rfh()->GetRoutingID(), + source_factory.core(), kParams, kSharedMemoryCount, kMuteSource, + std::move(client)); } TEST_F(ForwardingAudioStreamFactoryTest, @@ -310,8 +315,9 @@ EXPECT_CALL(*broker, CreateStream(NotNull())); mojo::MakeRequest(&client); - factory.CreateOutputStream(main_rfh(), kOutputDeviceId, kParams, - base::nullopt, std::move(client)); + factory.core()->CreateOutputStream( + main_rfh()->GetProcess()->GetID(), main_rfh()->GetRoutingID(), + kOutputDeviceId, kParams, base::nullopt, std::move(client)); } TEST_F(ForwardingAudioStreamFactoryTest, @@ -329,17 +335,19 @@ { EXPECT_CALL(*main_rfh_broker, CreateStream(NotNull())); mojo::MakeRequest(&client); - factory.CreateInputStream(main_rfh(), kInputDeviceId, kParams, - kSharedMemoryCount, kEnableAgc, nullptr, - std::move(client)); + factory.core()->CreateInputStream( + main_rfh()->GetProcess()->GetID(), main_rfh()->GetRoutingID(), + kInputDeviceId, kParams, kSharedMemoryCount, kEnableAgc, nullptr, + std::move(client)); testing::Mock::VerifyAndClear(&*main_rfh_broker); } { EXPECT_CALL(*other_rfh_broker, CreateStream(NotNull())); mojo::MakeRequest(&client); - factory.CreateInputStream(other_rfh(), kInputDeviceId, kParams, - kSharedMemoryCount, kEnableAgc, nullptr, - std::move(client)); + factory.core()->CreateInputStream( + other_rfh()->GetProcess()->GetID(), other_rfh()->GetRoutingID(), + kInputDeviceId, kParams, kSharedMemoryCount, kEnableAgc, nullptr, + std::move(client)); testing::Mock::VerifyAndClear(&*other_rfh_broker); } @@ -358,28 +366,33 @@ base::WeakPtr<MockBroker> other_rfh_broker = ExpectLoopbackBrokerConstruction(other_rfh()); + std::unique_ptr<service_manager::Connector> other_connector = + connector_->Clone(); + ForwardingAudioStreamFactory factory( web_contents(), nullptr /*user_input_monitor*/, std::move(connector_), std::move(broker_factory_)); ForwardingAudioStreamFactory source_factory( source_contents.get(), nullptr /*user_input_monitor*/, - std::move(connector_), std::make_unique<MockBrokerFactory>()); + std::move(other_connector), std::make_unique<MockBrokerFactory>()); { EXPECT_CALL(*main_rfh_broker, CreateStream(NotNull())); mojo::MakeRequest(&client); - factory.CreateLoopbackStream(main_rfh(), &source_factory, kParams, - kSharedMemoryCount, kMuteSource, - std::move(client)); + factory.core()->CreateLoopbackStream( + main_rfh()->GetProcess()->GetID(), main_rfh()->GetRoutingID(), + source_factory.core(), kParams, kSharedMemoryCount, kMuteSource, + std::move(client)); testing::Mock::VerifyAndClear(&*main_rfh_broker); } { EXPECT_CALL(*other_rfh_broker, CreateStream(NotNull())); mojo::MakeRequest(&client); - factory.CreateLoopbackStream(other_rfh(), &source_factory, kParams, - kSharedMemoryCount, kMuteSource, - std::move(client)); + factory.core()->CreateLoopbackStream( + other_rfh()->GetProcess()->GetID(), other_rfh()->GetRoutingID(), + source_factory.core(), kParams, kSharedMemoryCount, kMuteSource, + std::move(client)); testing::Mock::VerifyAndClear(&*other_rfh_broker); } @@ -404,15 +417,17 @@ { EXPECT_CALL(*main_rfh_broker, CreateStream(NotNull())); mojo::MakeRequest(&client); - factory.CreateOutputStream(main_rfh(), kOutputDeviceId, kParams, - base::nullopt, std::move(client)); + factory.core()->CreateOutputStream( + main_rfh()->GetProcess()->GetID(), main_rfh()->GetRoutingID(), + kOutputDeviceId, kParams, base::nullopt, std::move(client)); testing::Mock::VerifyAndClear(&*main_rfh_broker); } { EXPECT_CALL(*other_rfh_broker, CreateStream(NotNull())); mojo::MakeRequest(&client); - factory.CreateOutputStream(other_rfh(), kOutputDeviceId, kParams, - base::nullopt, std::move(client)); + factory.core()->CreateOutputStream( + other_rfh()->GetProcess()->GetID(), other_rfh()->GetRoutingID(), + kOutputDeviceId, kParams, base::nullopt, std::move(client)); testing::Mock::VerifyAndClear(&*other_rfh_broker); } @@ -442,60 +457,69 @@ base::WeakPtr<MockBroker> other_rfh_output_broker = ExpectOutputBrokerConstruction(other_rfh()); + std::unique_ptr<service_manager::Connector> other_connector = + connector_->Clone(); + ForwardingAudioStreamFactory factory( web_contents(), nullptr /*user_input_monitor*/, std::move(connector_), std::move(broker_factory_)); ForwardingAudioStreamFactory source_factory( source_contents.get(), nullptr /*user_input_monitor*/, - std::move(connector_), std::make_unique<MockBrokerFactory>()); + std::move(other_connector), std::make_unique<MockBrokerFactory>()); { EXPECT_CALL(*main_rfh_input_broker, CreateStream(NotNull())); mojo::MakeRequest(&input_client); - factory.CreateInputStream(main_rfh(), kInputDeviceId, kParams, - kSharedMemoryCount, kEnableAgc, nullptr, - std::move(input_client)); + factory.core()->CreateInputStream( + main_rfh()->GetProcess()->GetID(), main_rfh()->GetRoutingID(), + kInputDeviceId, kParams, kSharedMemoryCount, kEnableAgc, nullptr, + std::move(input_client)); testing::Mock::VerifyAndClear(&*main_rfh_input_broker); } { EXPECT_CALL(*other_rfh_input_broker, CreateStream(NotNull())); mojo::MakeRequest(&input_client); - factory.CreateInputStream(other_rfh(), kInputDeviceId, kParams, - kSharedMemoryCount, kEnableAgc, nullptr, - std::move(input_client)); + factory.core()->CreateInputStream( + other_rfh()->GetProcess()->GetID(), other_rfh()->GetRoutingID(), + kInputDeviceId, kParams, kSharedMemoryCount, kEnableAgc, nullptr, + std::move(input_client)); testing::Mock::VerifyAndClear(&*other_rfh_input_broker); } { EXPECT_CALL(*main_rfh_loopback_broker, CreateStream(NotNull())); mojo::MakeRequest(&input_client); - factory.CreateLoopbackStream(main_rfh(), &source_factory, kParams, - kSharedMemoryCount, kMuteSource, - std::move(input_client)); + factory.core()->CreateLoopbackStream( + main_rfh()->GetProcess()->GetID(), main_rfh()->GetRoutingID(), + source_factory.core(), kParams, kSharedMemoryCount, kMuteSource, + std::move(input_client)); testing::Mock::VerifyAndClear(&*main_rfh_loopback_broker); } { EXPECT_CALL(*other_rfh_loopback_broker, CreateStream(NotNull())); mojo::MakeRequest(&input_client); - factory.CreateLoopbackStream(other_rfh(), &source_factory, kParams, - kSharedMemoryCount, kMuteSource, - std::move(input_client)); + factory.core()->CreateLoopbackStream( + other_rfh()->GetProcess()->GetID(), other_rfh()->GetRoutingID(), + source_factory.core(), kParams, kSharedMemoryCount, kMuteSource, + std::move(input_client)); testing::Mock::VerifyAndClear(&*other_rfh_loopback_broker); } { EXPECT_CALL(*main_rfh_output_broker, CreateStream(NotNull())); mojo::MakeRequest(&output_client); - factory.CreateOutputStream(main_rfh(), kOutputDeviceId, kParams, - base::nullopt, std::move(output_client)); + factory.core()->CreateOutputStream( + main_rfh()->GetProcess()->GetID(), main_rfh()->GetRoutingID(), + kOutputDeviceId, kParams, base::nullopt, std::move(output_client)); testing::Mock::VerifyAndClear(&*main_rfh_output_broker); } { EXPECT_CALL(*other_rfh_output_broker, CreateStream(NotNull())); mojo::MakeRequest(&output_client); - factory.CreateOutputStream(other_rfh(), kOutputDeviceId, kParams, - base::nullopt, std::move(output_client)); + factory.core()->CreateOutputStream( + other_rfh()->GetProcess()->GetID(), other_rfh()->GetRoutingID(), + kOutputDeviceId, kParams, base::nullopt, std::move(output_client)); testing::Mock::VerifyAndClear(&*other_rfh_output_broker); } @@ -528,14 +552,16 @@ EXPECT_CALL(*input_broker, CreateStream(NotNull())); mojo::MakeRequest(&input_client); - factory.CreateInputStream(main_rfh(), kInputDeviceId, kParams, - kSharedMemoryCount, kEnableAgc, nullptr, - std::move(input_client)); + factory.core()->CreateInputStream(main_rfh()->GetProcess()->GetID(), + main_rfh()->GetRoutingID(), kInputDeviceId, + kParams, kSharedMemoryCount, kEnableAgc, + nullptr, std::move(input_client)); EXPECT_CALL(*output_broker, CreateStream(NotNull())); mojo::MakeRequest(&output_client); - factory.CreateOutputStream(main_rfh(), kOutputDeviceId, kParams, - base::nullopt, std::move(output_client)); + factory.core()->CreateOutputStream( + main_rfh()->GetProcess()->GetID(), main_rfh()->GetRoutingID(), + kOutputDeviceId, kParams, base::nullopt, std::move(output_client)); DeleteContents(); base::RunLoop().RunUntilIdle(); @@ -566,32 +592,36 @@ { EXPECT_CALL(*main_rfh_input_broker, CreateStream(NotNull())); mojo::MakeRequest(&input_client); - factory.CreateInputStream(main_rfh(), kInputDeviceId, kParams, - kSharedMemoryCount, kEnableAgc, nullptr, - std::move(input_client)); + factory.core()->CreateInputStream( + main_rfh()->GetProcess()->GetID(), main_rfh()->GetRoutingID(), + kInputDeviceId, kParams, kSharedMemoryCount, kEnableAgc, nullptr, + std::move(input_client)); testing::Mock::VerifyAndClear(&*main_rfh_input_broker); } { EXPECT_CALL(*other_rfh_input_broker, CreateStream(NotNull())); mojo::MakeRequest(&input_client); - factory.CreateInputStream(other_rfh(), kInputDeviceId, kParams, - kSharedMemoryCount, kEnableAgc, nullptr, - std::move(input_client)); + factory.core()->CreateInputStream( + other_rfh()->GetProcess()->GetID(), other_rfh()->GetRoutingID(), + kInputDeviceId, kParams, kSharedMemoryCount, kEnableAgc, nullptr, + std::move(input_client)); testing::Mock::VerifyAndClear(&*other_rfh_input_broker); } { EXPECT_CALL(*main_rfh_output_broker, CreateStream(NotNull())); mojo::MakeRequest(&output_client); - factory.CreateOutputStream(main_rfh(), kOutputDeviceId, kParams, - base::nullopt, std::move(output_client)); + factory.core()->CreateOutputStream( + main_rfh()->GetProcess()->GetID(), main_rfh()->GetRoutingID(), + kOutputDeviceId, kParams, base::nullopt, std::move(output_client)); testing::Mock::VerifyAndClear(&*main_rfh_output_broker); } { EXPECT_CALL(*other_rfh_output_broker, CreateStream(NotNull())); mojo::MakeRequest(&output_client); - factory.CreateOutputStream(other_rfh(), kOutputDeviceId, kParams, - base::nullopt, std::move(output_client)); + factory.core()->CreateOutputStream( + other_rfh()->GetProcess()->GetID(), other_rfh()->GetRoutingID(), + kOutputDeviceId, kParams, base::nullopt, std::move(output_client)); testing::Mock::VerifyAndClear(&*other_rfh_output_broker); } @@ -644,8 +674,9 @@ EXPECT_CALL(*broker, CreateStream(NotNull())); mojo::MakeRequest(&client); - factory.CreateOutputStream(main_rfh(), kOutputDeviceId, kParams, - base::nullopt, std::move(client)); + factory.core()->CreateOutputStream( + main_rfh()->GetProcess()->GetID(), main_rfh()->GetRoutingID(), + kOutputDeviceId, kParams, base::nullopt, std::move(client)); base::RunLoop().RunUntilIdle(); testing::Mock::VerifyAndClear(&*broker); @@ -684,8 +715,9 @@ EXPECT_CALL(*broker, CreateStream(NotNull())); mojo::MakeRequest(&client); - factory.CreateOutputStream(main_rfh(), kOutputDeviceId, kParams, - base::nullopt, std::move(client)); + factory.core()->CreateOutputStream( + main_rfh()->GetProcess()->GetID(), main_rfh()->GetRoutingID(), + kOutputDeviceId, kParams, base::nullopt, std::move(client)); base::RunLoop().RunUntilIdle(); EXPECT_TRUE(factory.IsMuted()); EXPECT_TRUE(stream_factory_.IsConnected()); @@ -713,8 +745,9 @@ { EXPECT_CALL(*broker, CreateStream(NotNull())); mojo::MakeRequest(&client); - factory.CreateOutputStream(main_rfh(), kOutputDeviceId, kParams, - base::nullopt, std::move(client)); + factory.core()->CreateOutputStream( + main_rfh()->GetProcess()->GetID(), main_rfh()->GetRoutingID(), + kOutputDeviceId, kParams, base::nullopt, std::move(client)); base::RunLoop().RunUntilIdle(); testing::Mock::VerifyAndClear(&*broker); } @@ -730,8 +763,9 @@ { EXPECT_CALL(*another_broker, CreateStream(NotNull())); mojo::MakeRequest(&client); - factory.CreateOutputStream(main_rfh(), kOutputDeviceId, kParams, - base::nullopt, std::move(client)); + factory.core()->CreateOutputStream( + main_rfh()->GetProcess()->GetID(), main_rfh()->GetRoutingID(), + kOutputDeviceId, kParams, base::nullopt, std::move(client)); base::RunLoop().RunUntilIdle(); testing::Mock::VerifyAndClear(&*another_broker); } @@ -762,10 +796,11 @@ web_contents(), nullptr /*user_input_monitor*/, std::move(connector_), std::move(broker_factory_)); - factory.AddLoopbackSink(&sink1); - factory.AddLoopbackSink(&sink2); - factory.RemoveLoopbackSink(&sink1); + factory.core()->AddLoopbackSink(&sink1); + factory.core()->AddLoopbackSink(&sink2); + factory.core()->RemoveLoopbackSink(&sink1); } + base::RunLoop().RunUntilIdle(); } } // namespace content
diff --git a/content/browser/media/in_process_audio_loopback_stream_creator.cc b/content/browser/media/in_process_audio_loopback_stream_creator.cc index ad26dac..12b51f3 100644 --- a/content/browser/media/in_process_audio_loopback_stream_creator.cc +++ b/content/browser/media/in_process_audio_loopback_stream_creator.cc
@@ -7,8 +7,14 @@ #include <memory> #include <utility> +#include "base/bind.h" +#include "base/location.h" +#include "base/logging.h" +#include "base/task/post_task.h" #include "content/browser/browser_main_loop.h" #include "content/browser/web_contents/web_contents_impl.h" +#include "content/common/media/renderer_audio_input_stream_factory.mojom.h" +#include "content/public/browser/browser_task_traits.h" #include "content/public/browser/browser_thread.h" #include "content/public/browser/render_frame_host.h" #include "content/public/common/service_manager_connection.h" @@ -53,6 +59,39 @@ DISALLOW_COPY_AND_ASSIGN(StreamCreatedCallbackAdapter); }; +void CreateLoopbackStreamHelper( + ForwardingAudioStreamFactory::Core* factory, + AudioStreamBroker::LoopbackSource* loopback_source, + const media::AudioParameters& params, + uint32_t total_segments, + mojom::RendererAudioInputStreamFactoryClientPtrInfo client_ptr_info) { + DCHECK_CURRENTLY_ON(BrowserThread::IO); + + const bool mute_source = true; + mojom::RendererAudioInputStreamFactoryClientPtr client; + client.Bind(std::move(client_ptr_info)); + + factory->CreateLoopbackStream(-1, -1, loopback_source, params, total_segments, + mute_source, std::move(client)); +} + +void CreateSystemWideLoopbackStreamHelper( + ForwardingAudioStreamFactory::Core* factory, + const media::AudioParameters& params, + uint32_t total_segments, + mojom::RendererAudioInputStreamFactoryClientPtrInfo client_ptr_info) { + DCHECK_CURRENTLY_ON(BrowserThread::IO); + + const bool enable_agc = false; + mojom::RendererAudioInputStreamFactoryClientPtr client; + client.Bind(std::move(client_ptr_info)); + + factory->CreateInputStream( + -1, -1, media::AudioDeviceDescription::kLoopbackWithMuteDeviceId, params, + total_segments, enable_agc, nullptr /* processing_config */, + std::move(client)); +} + } // namespace InProcessAudioLoopbackStreamCreator::InProcessAudioLoopbackStreamCreator() @@ -78,22 +117,27 @@ uint32_t total_segments, const StreamCreatedCallback& callback) { DCHECK_CURRENTLY_ON(BrowserThread::UI); - mojom::RendererAudioInputStreamFactoryClientPtr client; + mojom::RendererAudioInputStreamFactoryClientPtrInfo client; mojo::MakeStrongBinding( std::make_unique<StreamCreatedCallbackAdapter>(callback), mojo::MakeRequest(&client)); + // Deletion of factory_.core() is posted to the IO thread when |factory_| is + // destroyed, so Unretained is safe below. if (loopback_source) { - factory_.CreateLoopbackStream( - nullptr, - static_cast<WebContentsImpl*>(loopback_source)->GetAudioStreamFactory(), - params, total_segments, true /* mute_source */, std::move(client)); - } else { - // A null |frame_of_source_web_contents| requests system-wide loopback. - factory_.CreateInputStream( - nullptr, media::AudioDeviceDescription::kLoopbackWithMuteDeviceId, - params, total_segments, false /* enable_agc */, - nullptr /* processing_config */, std::move(client)); + base::PostTaskWithTraits( + FROM_HERE, {BrowserThread::IO}, + base::BindOnce(&CreateLoopbackStreamHelper, factory_.core(), + static_cast<WebContentsImpl*>(loopback_source) + ->GetAudioStreamFactory() + ->core(), + params, total_segments, std::move(client))); + return; } + // A null |frame_of_source_web_contents| requests system-wide loopback. + base::PostTaskWithTraits( + FROM_HERE, {BrowserThread::IO}, + base::BindOnce(&CreateSystemWideLoopbackStreamHelper, factory_.core(), + params, total_segments, std::move(client))); } } // namespace content
diff --git a/content/browser/renderer_host/media/render_frame_audio_input_stream_factory.cc b/content/browser/renderer_host/media/render_frame_audio_input_stream_factory.cc index e92b04b6..e7e8b7a 100644 --- a/content/browser/renderer_host/media/render_frame_audio_input_stream_factory.cc +++ b/content/browser/renderer_host/media/render_frame_audio_input_stream_factory.cc
@@ -4,15 +4,25 @@ #include "content/browser/renderer_host/media/render_frame_audio_input_stream_factory.h" +#include <cstdint> #include <string> #include <utility> +#include "base/bind.h" +#include "base/callback.h" +#include "base/location.h" +#include "base/logging.h" +#include "base/memory/weak_ptr.h" #include "base/task/post_task.h" #include "base/trace_event/trace_event.h" -#include "content/browser/browser_main_loop.h" +#include "base/unguessable_token.h" +#include "content/browser/media/audio_stream_broker.h" #include "content/browser/media/capture/desktop_capture_device_uma_types.h" #include "content/browser/media/forwarding_audio_stream_factory.h" #include "content/browser/media/media_devices_permission_checker.h" +#include "content/browser/media/media_devices_util.h" +#include "content/browser/renderer_host/media/audio_input_device_manager.h" +#include "content/browser/renderer_host/media/media_devices_manager.h" #include "content/browser/renderer_host/media/media_stream_manager.h" #include "content/public/browser/browser_task_traits.h" #include "content/public/browser/browser_thread.h" @@ -22,25 +32,29 @@ #include "content/public/browser/web_contents_media_capture_id.h" #include "content/public/common/media_stream_request.h" #include "media/audio/audio_device_description.h" -#include "media/audio/audio_input_device.h" #include "media/base/audio_parameters.h" +#include "mojo/public/cpp/bindings/binding.h" +#include "services/audio/public/mojom/audio_processing.mojom.h" +#include "url/origin.h" namespace content { namespace { -void LookUpDeviceAndRespondIfFound( - scoped_refptr<AudioInputDeviceManager> audio_input_device_manager, - int32_t session_id, - base::OnceCallback<void(const MediaStreamDevice&)> response) { - DCHECK_CURRENTLY_ON(BrowserThread::IO); - const MediaStreamDevice* device = - audio_input_device_manager->GetOpenedDeviceById(session_id); - if (device) { - // Copies device. - base::PostTaskWithTraits(FROM_HERE, {BrowserThread::UI}, - base::BindOnce(std::move(response), *device)); +AudioStreamBroker::LoopbackSource* GetLoopbackSourceOnUIThread( + int render_process_id, + int render_frame_id) { + DCHECK_CURRENTLY_ON(BrowserThread::UI); + auto* source = ForwardingAudioStreamFactory::CoreForFrame( + (RenderFrameHost::FromID(render_process_id, render_frame_id))); + if (!source) { + // The source of the capture has already been destroyed, so fail early. + return nullptr; } + // Note: this pointer is sent over to the IO thread. This is safe since the + // destruction of |source| is posted to the IO thread and it hasn't been + // posted yet. + return source; } void EnumerateOutputDevices(MediaStreamManager* media_stream_manager, @@ -61,75 +75,164 @@ if (MediaStreamManager::DoesMediaDeviceIDMatchHMAC( salt_and_origin.device_id_salt, salt_and_origin.origin, device_id, device_info.device_id)) { - base::PostTaskWithTraits( - FROM_HERE, {BrowserThread::UI}, - base::BindOnce(std::move(cb), device_info.device_id)); + cb.Run(device_info.device_id); break; } } // If we're unable to translate the device id, |cb| will not be run. } +void GetSaltOriginAndPermissionsOnUIThread( + int process_id, + int frame_id, + base::OnceCallback<void(MediaDeviceSaltAndOrigin salt_and_origin, + bool has_access)> cb) { + auto salt_and_origin = GetMediaDeviceSaltAndOrigin(process_id, frame_id); + bool access = MediaDevicesPermissionChecker().CheckPermissionOnUIThread( + MEDIA_DEVICE_TYPE_AUDIO_OUTPUT, process_id, frame_id); + base::PostTaskWithTraits( + FROM_HERE, {BrowserThread::IO}, + base::BindOnce(std::move(cb), std::move(salt_and_origin), access)); +} + } // namespace +class RenderFrameAudioInputStreamFactory::Core final + : public mojom::RendererAudioInputStreamFactory { + public: + Core(mojom::RendererAudioInputStreamFactoryRequest request, + MediaStreamManager* media_stream_manager, + RenderFrameHost* render_frame_host); + + ~Core() final; + + void Init(mojom::RendererAudioInputStreamFactoryRequest request); + + // mojom::RendererAudioInputStreamFactory implementation. + void CreateStream( + mojom::RendererAudioInputStreamFactoryClientPtr client, + int32_t session_id, + const media::AudioParameters& audio_params, + bool automatic_gain_control, + uint32_t shared_memory_count, + audio::mojom::AudioProcessingConfigPtr processing_config) final; + + void AssociateInputAndOutputForAec( + const base::UnguessableToken& input_stream_id, + const std::string& output_device_id) final; + + void CreateLoopbackStream( + mojom::RendererAudioInputStreamFactoryClientPtr client, + const media::AudioParameters& audio_params, + uint32_t shared_memory_count, + bool disable_local_echo, + AudioStreamBroker::LoopbackSource* loopback_source); + + void AssociateInputAndOutputForAecAfterCheckingAccess( + const base::UnguessableToken& input_stream_id, + const std::string& output_device_id, + MediaDeviceSaltAndOrigin salt_and_origin, + bool access_granted); + + void AssociateTranslatedOutputDeviceForAec( + const base::UnguessableToken& input_stream_id, + const std::string& raw_output_device_id); + + MediaStreamManager* const media_stream_manager_; + const int process_id_; + const int frame_id_; + const url::Origin origin_; + + mojo::Binding<RendererAudioInputStreamFactory> binding_; + ForwardingAudioStreamFactory::Core* forwarding_factory_; + + base::WeakPtrFactory<Core> weak_ptr_factory_; + + DISALLOW_COPY_AND_ASSIGN(Core); +}; + RenderFrameAudioInputStreamFactory::RenderFrameAudioInputStreamFactory( mojom::RendererAudioInputStreamFactoryRequest request, - scoped_refptr<AudioInputDeviceManager> audio_input_device_manager, + MediaStreamManager* media_stream_manager, RenderFrameHost* render_frame_host) - : binding_(this, std::move(request)), - audio_input_device_manager_(std::move(audio_input_device_manager)), - render_frame_host_(render_frame_host), - weak_ptr_factory_(this) { + : core_(new Core(std::move(request), + media_stream_manager, + render_frame_host)) { DCHECK_CURRENTLY_ON(BrowserThread::UI); } RenderFrameAudioInputStreamFactory::~RenderFrameAudioInputStreamFactory() { DCHECK_CURRENTLY_ON(BrowserThread::UI); + // Ensure |core_| is deleted on the right thread. DeleteOnIOThread isn't used + // as it doesn't post in case it is already executed on the right thread. That + // causes issues in unit tests where the UI thread and the IO thread are the + // same. + base::PostTaskWithTraits( + FROM_HERE, {BrowserThread::IO}, + base::BindOnce([](std::unique_ptr<Core>) {}, std::move(core_))); } -void RenderFrameAudioInputStreamFactory::CreateStream( +RenderFrameAudioInputStreamFactory::Core::Core( + mojom::RendererAudioInputStreamFactoryRequest request, + MediaStreamManager* media_stream_manager, + RenderFrameHost* render_frame_host) + : media_stream_manager_(media_stream_manager), + process_id_(render_frame_host->GetProcess()->GetID()), + frame_id_(render_frame_host->GetRoutingID()), + origin_(render_frame_host->GetLastCommittedOrigin()), + binding_(this), + forwarding_factory_( + ForwardingAudioStreamFactory::CoreForFrame(render_frame_host)), + weak_ptr_factory_(this) { + DCHECK_CURRENTLY_ON(BrowserThread::UI); + + if (!forwarding_factory_) { + // The only case when we not have a forwarding factory is when the + // frame belongs to an interstitial. Interstitials don't need audio, so it's + // fine to drop the request. + return; + } + + // Unretained is safe since the destruction of |this| is posted to the IO + // thread. + base::PostTaskWithTraits( + FROM_HERE, {BrowserThread::IO}, + base::BindOnce(&Core::Init, base::Unretained(this), std::move(request))); +} + +RenderFrameAudioInputStreamFactory::Core::~Core() { + DCHECK_CURRENTLY_ON(BrowserThread::IO); +} + +void RenderFrameAudioInputStreamFactory::Core::Init( + mojom::RendererAudioInputStreamFactoryRequest request) { + DCHECK_CURRENTLY_ON(BrowserThread::IO); + binding_.Bind(std::move(request)); +} + +void RenderFrameAudioInputStreamFactory::Core::CreateStream( mojom::RendererAudioInputStreamFactoryClientPtr client, int32_t session_id, const media::AudioParameters& audio_params, bool automatic_gain_control, uint32_t shared_memory_count, audio::mojom::AudioProcessingConfigPtr processing_config) { - DCHECK_CURRENTLY_ON(BrowserThread::UI); - TRACE_EVENT_INSTANT1("audio", - "RenderFrameAudioInputStreamFactory::CreateStream", - TRACE_EVENT_SCOPE_THREAD, "session id", session_id); + DCHECK_CURRENTLY_ON(BrowserThread::IO); + DCHECK(forwarding_factory_); + TRACE_EVENT1("audio", "RenderFrameAudioInputStreamFactory::CreateStream", + "session id", session_id); - base::PostTaskWithTraits( - FROM_HERE, {BrowserThread::IO}, - base::BindOnce( - &LookUpDeviceAndRespondIfFound, audio_input_device_manager_, - session_id, - base::BindOnce(&RenderFrameAudioInputStreamFactory:: - CreateStreamAfterLookingUpDevice, - weak_ptr_factory_.GetWeakPtr(), std::move(client), - audio_params, automatic_gain_control, - shared_memory_count, std::move(processing_config)))); -} + const MediaStreamDevice* device = + media_stream_manager_->audio_input_device_manager()->GetOpenedDeviceById( + session_id); -void RenderFrameAudioInputStreamFactory::CreateStreamAfterLookingUpDevice( - mojom::RendererAudioInputStreamFactoryClientPtr client, - const media::AudioParameters& audio_params, - bool automatic_gain_control, - uint32_t shared_memory_count, - audio::mojom::AudioProcessingConfigPtr processing_config, - const MediaStreamDevice& device) { - TRACE_EVENT1( - "audio", - "RenderFrameAudioInputStreamFactory::CreateStreamAfterLookingUpDevice", - "device id", device.id); - DCHECK_CURRENTLY_ON(BrowserThread::UI); - ForwardingAudioStreamFactory* factory = - ForwardingAudioStreamFactory::ForFrame(render_frame_host_); - if (!factory) + if (!device) { + TRACE_EVENT_INSTANT0("audio", "device not found", TRACE_EVENT_SCOPE_THREAD); return; + } WebContentsMediaCaptureId capture_id; - if (WebContentsMediaCaptureId::Parse(device.id, &capture_id)) { + if (WebContentsMediaCaptureId::Parse(device->id, &capture_id)) { // For MEDIA_GUM_DESKTOP_AUDIO_CAPTURE, the source is selected from // picker window, we do not mute the source audio. For // MEDIA_GUM_TAB_AUDIO_CAPTURE, the probable use case is Cast, we mute @@ -137,85 +240,102 @@ // TODO(qiangchen): Analyze audio constraints to make a duplicating or // diverting decision. It would give web developer more flexibility. - ForwardingAudioStreamFactory* loopback_source = - ForwardingAudioStreamFactory::ForFrame((RenderFrameHost::FromID( - capture_id.render_process_id, capture_id.main_render_frame_id))); - if (!loopback_source) { - // The source of the capture has already been destroyed, so fail early. - return; - } + base::PostTaskWithTraitsAndReplyWithResult( + FROM_HERE, {BrowserThread::UI}, + base::BindOnce(&GetLoopbackSourceOnUIThread, + capture_id.render_process_id, + capture_id.main_render_frame_id), + base::BindOnce( + &RenderFrameAudioInputStreamFactory::Core::CreateLoopbackStream, + weak_ptr_factory_.GetWeakPtr(), std::move(client), audio_params, + shared_memory_count, capture_id.disable_local_echo)); - factory->CreateLoopbackStream( - render_frame_host_, loopback_source, audio_params, shared_memory_count, - capture_id.disable_local_echo, std::move(client)); - - if (device.type == MEDIA_GUM_DESKTOP_AUDIO_CAPTURE) + if (device->type == MEDIA_GUM_DESKTOP_AUDIO_CAPTURE) IncrementDesktopCaptureCounter(SYSTEM_LOOPBACK_AUDIO_CAPTURER_CREATED); + return; } else { - factory->CreateInputStream(render_frame_host_, device.id, audio_params, - shared_memory_count, automatic_gain_control, - std::move(processing_config), std::move(client)); + forwarding_factory_->CreateInputStream( + process_id_, frame_id_, device->id, audio_params, shared_memory_count, + automatic_gain_control, std::move(processing_config), + std::move(client)); // Only count for captures from desktop media picker dialog and system loop // back audio. - if (device.type == MEDIA_GUM_DESKTOP_AUDIO_CAPTURE && - (media::AudioDeviceDescription::IsLoopbackDevice(device.id))) { + if (device->type == MEDIA_GUM_DESKTOP_AUDIO_CAPTURE && + (media::AudioDeviceDescription::IsLoopbackDevice(device->id))) { IncrementDesktopCaptureCounter(SYSTEM_LOOPBACK_AUDIO_CAPTURER_CREATED); } } } -void RenderFrameAudioInputStreamFactory::AssociateInputAndOutputForAec( +void RenderFrameAudioInputStreamFactory::Core::CreateLoopbackStream( + mojom::RendererAudioInputStreamFactoryClientPtr client, + const media::AudioParameters& audio_params, + uint32_t shared_memory_count, + bool disable_local_echo, + AudioStreamBroker::LoopbackSource* loopback_source) { + if (!loopback_source) + return; + + forwarding_factory_->CreateLoopbackStream( + process_id_, frame_id_, loopback_source, audio_params, + shared_memory_count, disable_local_echo, std::move(client)); +} + +void RenderFrameAudioInputStreamFactory::Core::AssociateInputAndOutputForAec( const base::UnguessableToken& input_stream_id, const std::string& output_device_id) { - DCHECK_CURRENTLY_ON(BrowserThread::UI); + DCHECK_CURRENTLY_ON(BrowserThread::IO); + DCHECK(forwarding_factory_); if (!IsValidDeviceId(output_device_id)) return; - ForwardingAudioStreamFactory* factory = - ForwardingAudioStreamFactory::ForFrame(render_frame_host_); - if (!factory) - return; + base::PostTaskWithTraits( + FROM_HERE, {BrowserThread::UI}, + base::BindOnce( + &GetSaltOriginAndPermissionsOnUIThread, process_id_, frame_id_, + base::BindOnce( + &Core::AssociateInputAndOutputForAecAfterCheckingAccess, + weak_ptr_factory_.GetWeakPtr(), input_stream_id, + output_device_id))); +} - const int process_id = render_frame_host_->GetProcess()->GetID(); - const int frame_id = render_frame_host_->GetRoutingID(); - auto salt_and_origin = GetMediaDeviceSaltAndOrigin(process_id, frame_id); +void RenderFrameAudioInputStreamFactory::Core:: + AssociateInputAndOutputForAecAfterCheckingAccess( + const base::UnguessableToken& input_stream_id, + const std::string& output_device_id, + MediaDeviceSaltAndOrigin salt_and_origin, + bool access_granted) { + DCHECK_CURRENTLY_ON(BrowserThread::IO); + DCHECK(forwarding_factory_); - // Check permissions for everything but the default device - if (!media::AudioDeviceDescription::IsDefaultDevice(output_device_id) && - !MediaDevicesPermissionChecker().CheckPermissionOnUIThread( - MEDIA_DEVICE_TYPE_AUDIO_OUTPUT, process_id, frame_id)) { + if (!access_granted) return; - } if (media::AudioDeviceDescription::IsDefaultDevice(output_device_id) || media::AudioDeviceDescription::IsCommunicationsDevice(output_device_id)) { - factory->AssociateInputAndOutputForAec(input_stream_id, output_device_id); + forwarding_factory_->AssociateInputAndOutputForAec(input_stream_id, + output_device_id); } else { - auto* media_stream_manager = - BrowserMainLoop::GetInstance()->media_stream_manager(); - base::PostTaskWithTraits( - FROM_HERE, {BrowserThread::IO}, - base::BindOnce( - EnumerateOutputDevices, media_stream_manager, - base::BindRepeating( - &TranslateDeviceId, output_device_id, salt_and_origin, - base::BindRepeating(&RenderFrameAudioInputStreamFactory:: - AssociateTranslatedOutputDeviceForAec, - weak_ptr_factory_.GetWeakPtr(), - input_stream_id)))); + EnumerateOutputDevices( + media_stream_manager_, + base::BindRepeating( + &TranslateDeviceId, output_device_id, salt_and_origin, + base::BindRepeating(&RenderFrameAudioInputStreamFactory::Core:: + AssociateTranslatedOutputDeviceForAec, + weak_ptr_factory_.GetWeakPtr(), + input_stream_id))); } } -void RenderFrameAudioInputStreamFactory::AssociateTranslatedOutputDeviceForAec( - const base::UnguessableToken& input_stream_id, - const std::string& raw_output_device_id) { - DCHECK_CURRENTLY_ON(BrowserThread::UI); - ForwardingAudioStreamFactory* factory = - ForwardingAudioStreamFactory::ForFrame(render_frame_host_); - if (factory) - factory->AssociateInputAndOutputForAec(input_stream_id, - raw_output_device_id); +void RenderFrameAudioInputStreamFactory::Core:: + AssociateTranslatedOutputDeviceForAec( + const base::UnguessableToken& input_stream_id, + const std::string& raw_output_device_id) { + DCHECK_CURRENTLY_ON(BrowserThread::IO); + DCHECK(forwarding_factory_); + forwarding_factory_->AssociateInputAndOutputForAec(input_stream_id, + raw_output_device_id); } } // namespace content
diff --git a/content/browser/renderer_host/media/render_frame_audio_input_stream_factory.h b/content/browser/renderer_host/media/render_frame_audio_input_stream_factory.h index 49ec117..ceafa6a 100644 --- a/content/browser/renderer_host/media/render_frame_audio_input_stream_factory.h +++ b/content/browser/renderer_host/media/render_frame_audio_input_stream_factory.h
@@ -5,72 +5,34 @@ #ifndef CONTENT_BROWSER_RENDERER_HOST_MEDIA_RENDER_FRAME_AUDIO_INPUT_STREAM_FACTORY_H_ #define CONTENT_BROWSER_RENDERER_HOST_MEDIA_RENDER_FRAME_AUDIO_INPUT_STREAM_FACTORY_H_ -#include <cstdint> -#include <string> +#include <memory> #include "base/macros.h" -#include "base/memory/scoped_refptr.h" -#include "content/browser/renderer_host/media/audio_input_device_manager.h" #include "content/common/content_export.h" #include "content/common/media/renderer_audio_input_stream_factory.mojom.h" -#include "content/public/browser/render_frame_host.h" -#include "content/public/common/media_stream_request.h" -#include "mojo/public/cpp/bindings/binding.h" - -namespace media { -class AudioParameters; -} // namespace media namespace content { -class AudioInputDeviceManager; +class MediaStreamManager; class RenderFrameHost; -// Handles a RendererAudioInputStreamFactory request for a render frame host, -// using the provided RendererAudioInputStreamFactoryContext. This class may -// be constructed on any thread, but must be used on the IO thread after that, -// and also destructed on the IO thread. -class CONTENT_EXPORT RenderFrameAudioInputStreamFactory - : public mojom::RendererAudioInputStreamFactory { +// Handles a RendererAudioInputStreamFactory request for a render frame host. +// Should be constructed and destructed on the UI thread, but will process mojo +// messages on the IO thread. This class relates to ForwardingAudioStreamFactory +// the same way as RenderFrameAudioOutputStreamFactory, and a class diagram can +// be found in render_frame_audio_output_stream_factory.h +class CONTENT_EXPORT RenderFrameAudioInputStreamFactory final { public: RenderFrameAudioInputStreamFactory( mojom::RendererAudioInputStreamFactoryRequest request, - scoped_refptr<AudioInputDeviceManager> audio_input_device_manager, + MediaStreamManager* media_stream_manager, RenderFrameHost* render_frame_host); - ~RenderFrameAudioInputStreamFactory() override; + ~RenderFrameAudioInputStreamFactory(); private: - // mojom::RendererAudioInputStreamFactory implementation. - void CreateStream( - mojom::RendererAudioInputStreamFactoryClientPtr client, - int32_t session_id, - const media::AudioParameters& audio_params, - bool automatic_gain_control, - uint32_t shared_memory_count, - audio::mojom::AudioProcessingConfigPtr processing_config) override; - - void CreateStreamAfterLookingUpDevice( - mojom::RendererAudioInputStreamFactoryClientPtr client, - const media::AudioParameters& audio_params, - bool automatic_gain_control, - uint32_t shared_memory_count, - audio::mojom::AudioProcessingConfigPtr processing_config, - const MediaStreamDevice& device); - - void AssociateInputAndOutputForAec( - const base::UnguessableToken& input_stream_id, - const std::string& output_device_id) override; - - void AssociateTranslatedOutputDeviceForAec( - const base::UnguessableToken& input_stream_id, - const std::string& raw_output_device_id); - - const mojo::Binding<RendererAudioInputStreamFactory> binding_; - const scoped_refptr<AudioInputDeviceManager> audio_input_device_manager_; - RenderFrameHost* const render_frame_host_; - - base::WeakPtrFactory<RenderFrameAudioInputStreamFactory> weak_ptr_factory_; + class Core; + std::unique_ptr<Core> core_; DISALLOW_COPY_AND_ASSIGN(RenderFrameAudioInputStreamFactory); };
diff --git a/content/browser/renderer_host/media/render_frame_audio_input_stream_factory_unittest.cc b/content/browser/renderer_host/media/render_frame_audio_input_stream_factory_unittest.cc index 654ec5a..f2cb24b 100644 --- a/content/browser/renderer_host/media/render_frame_audio_input_stream_factory_unittest.cc +++ b/content/browser/renderer_host/media/render_frame_audio_input_stream_factory_unittest.cc
@@ -4,7 +4,6 @@ #include "content/browser/renderer_host/media/render_frame_audio_input_stream_factory.h" -#include <memory> #include <string> #include <utility> @@ -14,6 +13,7 @@ #include "base/run_loop.h" #include "base/task/post_task.h" #include "content/browser/media/forwarding_audio_stream_factory.h" +#include "content/browser/renderer_host/media/audio_input_device_manager.h" #include "content/browser/renderer_host/media/media_stream_manager.h" #include "content/public/browser/browser_task_traits.h" #include "content/public/browser/browser_thread.h" @@ -66,6 +66,7 @@ // Set up the ForwardingAudioStreamFactory. service_manager::Connector::TestApi connector_test_api( ForwardingAudioStreamFactory::ForFrame(main_rfh()) + ->core() ->get_connector_for_testing()); connector_test_api.OverrideBinderForTesting( service_manager::Identity(audio::mojom::kServiceName), @@ -183,17 +184,15 @@ TEST_F(RenderFrameAudioInputStreamFactoryTest, ConstructDestruct) { mojom::RendererAudioInputStreamFactoryPtr factory_ptr; - RenderFrameAudioInputStreamFactory factory(mojo::MakeRequest(&factory_ptr), - audio_input_device_manager(), - main_rfh()); + RenderFrameAudioInputStreamFactory factory( + mojo::MakeRequest(&factory_ptr), media_stream_manager_.get(), main_rfh()); } TEST_F(RenderFrameAudioInputStreamFactoryTest, CreateOpenedStream_ForwardsCall) { mojom::RendererAudioInputStreamFactoryPtr factory_ptr; - RenderFrameAudioInputStreamFactory factory(mojo::MakeRequest(&factory_ptr), - audio_input_device_manager(), - main_rfh()); + RenderFrameAudioInputStreamFactory factory( + mojo::MakeRequest(&factory_ptr), media_stream_manager_.get(), main_rfh()); int session_id = audio_input_device_manager()->Open( MediaStreamDevice(MEDIA_DEVICE_AUDIO_CAPTURE, kDeviceId, kDeviceName)); @@ -213,9 +212,8 @@ CreateWebContentsCapture_ForwardsCall) { std::unique_ptr<WebContents> source_contents = CreateTestWebContents(); mojom::RendererAudioInputStreamFactoryPtr factory_ptr; - RenderFrameAudioInputStreamFactory factory(mojo::MakeRequest(&factory_ptr), - audio_input_device_manager(), - main_rfh()); + RenderFrameAudioInputStreamFactory factory( + mojo::MakeRequest(&factory_ptr), media_stream_manager_.get(), main_rfh()); RenderFrameHost* main_frame = source_contents->GetMainFrame(); WebContentsMediaCaptureId capture_id(main_frame->GetProcess()->GetID(), @@ -238,9 +236,8 @@ CreateWebContentsCaptureAfterCaptureSourceDestructed_Fails) { std::unique_ptr<WebContents> source_contents = CreateTestWebContents(); mojom::RendererAudioInputStreamFactoryPtr factory_ptr; - RenderFrameAudioInputStreamFactory factory(mojo::MakeRequest(&factory_ptr), - audio_input_device_manager(), - main_rfh()); + RenderFrameAudioInputStreamFactory factory( + mojo::MakeRequest(&factory_ptr), media_stream_manager_.get(), main_rfh()); RenderFrameHost* main_frame = source_contents->GetMainFrame(); WebContentsMediaCaptureId capture_id(main_frame->GetProcess()->GetID(), @@ -263,9 +260,8 @@ TEST_F(RenderFrameAudioInputStreamFactoryTest, CreateStreamWithoutValidSessionId_Fails) { mojom::RendererAudioInputStreamFactoryPtr factory_ptr; - RenderFrameAudioInputStreamFactory factory(mojo::MakeRequest(&factory_ptr), - audio_input_device_manager(), - main_rfh()); + RenderFrameAudioInputStreamFactory factory( + mojo::MakeRequest(&factory_ptr), media_stream_manager_.get(), main_rfh()); int session_id = 123; mojom::RendererAudioInputStreamFactoryClientPtr client;
diff --git a/content/browser/renderer_host/media/render_frame_audio_output_stream_factory.cc b/content/browser/renderer_host/media/render_frame_audio_output_stream_factory.cc index d9454f8..5d03441b 100644 --- a/content/browser/renderer_host/media/render_frame_audio_output_stream_factory.cc +++ b/content/browser/renderer_host/media/render_frame_audio_output_stream_factory.cc
@@ -4,73 +4,141 @@ #include "content/browser/renderer_host/media/render_frame_audio_output_stream_factory.h" +#include <cstdint> +#include <string> #include <utility> +#include "base/bind.h" +#include "base/callback.h" +#include "base/containers/flat_set.h" +#include "base/containers/unique_ptr_adapters.h" +#include "base/location.h" +#include "base/logging.h" +#include "base/memory/weak_ptr.h" +#include "base/optional.h" #include "base/task/post_task.h" +#include "base/time/time.h" #include "base/trace_event/trace_event.h" +#include "base/unguessable_token.h" #include "content/browser/media/forwarding_audio_stream_factory.h" #include "content/browser/renderer_host/media/audio_output_authorization_handler.h" #include "content/public/browser/browser_task_traits.h" +#include "content/public/browser/browser_thread.h" #include "content/public/browser/render_frame_host.h" #include "content/public/browser/render_process_host.h" -#include "media/base/bind_to_current_loop.h" +#include "media/base/output_device_info.h" +#include "media/mojo/interfaces/audio_output_stream.mojom.h" +#include "mojo/public/cpp/bindings/binding.h" namespace content { -// This class implements media::mojom::AudioOutputStreamProvider for a single -// streams and cleans itself up (using the |owner| pointer) when done. -class RenderFrameAudioOutputStreamFactory::ProviderImpl final - : public media::mojom::AudioOutputStreamProvider { +class RenderFrameAudioOutputStreamFactory::Core final + : public mojom::RendererAudioOutputStreamFactory { public: - ProviderImpl(media::mojom::AudioOutputStreamProviderRequest request, - RenderFrameAudioOutputStreamFactory* owner, - const std::string& device_id) - : owner_(owner), - device_id_(device_id), - binding_(this, std::move(request)) { - DCHECK(owner_); - DCHECK_CURRENTLY_ON(BrowserThread::UI); - // Unretained is safe since |this| owns |binding_|. - binding_.set_connection_error_handler( - base::BindOnce(&ProviderImpl::Done, base::Unretained(this))); + Core(RenderFrameHost* frame, + media::AudioSystem* audio_system, + MediaStreamManager* media_stream_manager, + mojom::RendererAudioOutputStreamFactoryRequest request); + + ~Core() final = default; + + void Init(mojom::RendererAudioOutputStreamFactoryRequest request); + + size_t current_number_of_providers_for_testing() { + return stream_providers_.size(); } - ~ProviderImpl() final { DCHECK_CURRENTLY_ON(BrowserThread::UI); } - - void Acquire( - const media::AudioParameters& params, - media::mojom::AudioOutputStreamProviderClientPtr provider_client, - const base::Optional<base::UnguessableToken>& processing_id) final { - DCHECK_CURRENTLY_ON(BrowserThread::UI); - TRACE_EVENT1("audio", - "RenderFrameAudioOutputStreamFactory::ProviderImpl::Acquire", - "raw device id", device_id_); - - RenderFrameHost* frame = owner_->frame_; - ForwardingAudioStreamFactory* factory = - ForwardingAudioStreamFactory::ForFrame(frame); - if (factory) { - // It's possible that |frame| has already been destroyed, in which case we - // don't need to create a stream. In this case, the renderer will get a - // connection error since |provider_client| is dropped. - factory->CreateOutputStream(frame, device_id_, params, processing_id, - std::move(provider_client)); - } - - // Since the stream creation has been propagated, |this| is no longer - // needed. - Done(); - } - - void Done() { owner_->DeleteProvider(this); } - private: - RenderFrameAudioOutputStreamFactory* const owner_; - const std::string device_id_; + // This class implements media::mojom::AudioOutputStreamProvider for a single + // streams and cleans itself up (using the |owner| pointer) when done. + class ProviderImpl final : public media::mojom::AudioOutputStreamProvider { + public: + ProviderImpl(media::mojom::AudioOutputStreamProviderRequest request, + RenderFrameAudioOutputStreamFactory::Core* owner, + const std::string& device_id) + : owner_(owner), + device_id_(device_id), + binding_(this, std::move(request)) { + DCHECK_CURRENTLY_ON(BrowserThread::IO); + // Unretained is safe since |this| owns |binding_|. + binding_.set_connection_error_handler( + base::BindOnce(&ProviderImpl::Done, base::Unretained(this))); + } - mojo::Binding<media::mojom::AudioOutputStreamProvider> binding_; + ~ProviderImpl() final { DCHECK_CURRENTLY_ON(BrowserThread::IO); } - DISALLOW_COPY_AND_ASSIGN(ProviderImpl); + void Acquire( + const media::AudioParameters& params, + media::mojom::AudioOutputStreamProviderClientPtr provider_client, + const base::Optional<base::UnguessableToken>& processing_id) final { + DCHECK_CURRENTLY_ON(BrowserThread::IO); + TRACE_EVENT1("audio", + "RenderFrameAudioOutputStreamFactory::ProviderImpl::Acquire", + "raw device id", device_id_); + + owner_->forwarding_factory_->CreateOutputStream( + owner_->process_id_, owner_->frame_id_, device_id_, params, + processing_id, std::move(provider_client)); + + // Since the stream creation has been propagated, |this| is no longer + // needed. + Done(); + } + + void Done() { owner_->DeleteProvider(this); } + + private: + RenderFrameAudioOutputStreamFactory::Core* const owner_; + const std::string device_id_; + + mojo::Binding<media::mojom::AudioOutputStreamProvider> binding_; + + DISALLOW_COPY_AND_ASSIGN(ProviderImpl); + }; + + using OutputStreamProviderSet = + base::flat_set<std::unique_ptr<media::mojom::AudioOutputStreamProvider>, + base::UniquePtrComparator>; + + // mojom::RendererAudioOutputStreamFactory implementation. + void RequestDeviceAuthorization( + media::mojom::AudioOutputStreamProviderRequest provider_request, + int32_t session_id, + const std::string& device_id, + RequestDeviceAuthorizationCallback callback) final; + + // Here, the |raw_device_id| is used to create the stream, and + // |device_id_for_renderer| is nonempty in the case when the renderer + // requested a device using a |session_id|, to let it know which device was + // chosen. This id is hashed. + void AuthorizationCompleted( + base::TimeTicks auth_start_time, + media::mojom::AudioOutputStreamProviderRequest request, + RequestDeviceAuthorizationCallback callback, + media::OutputDeviceStatus status, + const media::AudioParameters& params, + const std::string& raw_device_id, + const std::string& device_id_for_renderer); + + void DeleteProvider(media::mojom::AudioOutputStreamProvider* stream_provider); + + const int process_id_; + const int frame_id_; + AudioOutputAuthorizationHandler authorization_handler_; + + mojo::Binding<mojom::RendererAudioOutputStreamFactory> binding_; + ForwardingAudioStreamFactory::Core* forwarding_factory_; + + // The OutputStreamProviders for authorized streams are kept here while + // waiting for the renderer to finish creating the stream, and destructed + // afterwards. + OutputStreamProviderSet stream_providers_; + + // Weak pointers are used to cancel device authorizations that are in flight + // while |this| is destructed. + base::WeakPtrFactory<Core> weak_ptr_factory_; + + DISALLOW_COPY_AND_ASSIGN(Core); }; RenderFrameAudioOutputStreamFactory::RenderFrameAudioOutputStreamFactory( @@ -78,53 +146,90 @@ media::AudioSystem* audio_system, MediaStreamManager* media_stream_manager, mojom::RendererAudioOutputStreamFactoryRequest request) - : binding_(this, std::move(request)), - frame_(frame), - authorization_handler_( - new AudioOutputAuthorizationHandler(audio_system, - media_stream_manager, - frame_->GetProcess()->GetID())), - weak_ptr_factory_(this) { + : core_(new Core(frame, + audio_system, + media_stream_manager, + std::move(request))) { DCHECK_CURRENTLY_ON(BrowserThread::UI); } RenderFrameAudioOutputStreamFactory::~RenderFrameAudioOutputStreamFactory() { DCHECK_CURRENTLY_ON(BrowserThread::UI); + + // Ensure |core_| is deleted on the right thread. DeleteOnIOThread isn't used + // as it doesn't post in case it is already executed on the right thread. That + // causes issues in unit tests where the UI thread and the IO thread are the + // same. + base::PostTaskWithTraits( + FROM_HERE, {BrowserThread::IO}, + base::BindOnce([](std::unique_ptr<Core>) {}, std::move(core_))); } -void RenderFrameAudioOutputStreamFactory::RequestDeviceAuthorization( +size_t +RenderFrameAudioOutputStreamFactory::CurrentNumberOfProvidersForTesting() { + return core_->current_number_of_providers_for_testing(); +} + +RenderFrameAudioOutputStreamFactory::Core::Core( + RenderFrameHost* frame, + media::AudioSystem* audio_system, + MediaStreamManager* media_stream_manager, + mojom::RendererAudioOutputStreamFactoryRequest request) + : process_id_(frame->GetProcess()->GetID()), + frame_id_(frame->GetRoutingID()), + authorization_handler_(audio_system, media_stream_manager, process_id_), + binding_(this), + forwarding_factory_(ForwardingAudioStreamFactory::CoreForFrame(frame)), + weak_ptr_factory_(this) { + DCHECK_CURRENTLY_ON(BrowserThread::UI); + + if (!forwarding_factory_) { + // The only case when we not have a forwarding factory is when the + // frame belongs to an interstitial. Interstitials don't need audio, so it's + // fine to drop the request. + return; + } + + // Unretained is safe since the destruction of |this| is posted to the IO + // thread. + base::PostTaskWithTraits( + FROM_HERE, {BrowserThread::IO}, + base::BindOnce(&Core::Init, base::Unretained(this), std::move(request))); +} + +void RenderFrameAudioOutputStreamFactory::Core::Init( + mojom::RendererAudioOutputStreamFactoryRequest request) { + DCHECK_CURRENTLY_ON(BrowserThread::IO); + DCHECK(forwarding_factory_); + + binding_.Bind(std::move(request)); +} + +void RenderFrameAudioOutputStreamFactory::Core::RequestDeviceAuthorization( media::mojom::AudioOutputStreamProviderRequest provider_request, int32_t session_id, const std::string& device_id, RequestDeviceAuthorizationCallback callback) { - DCHECK_CURRENTLY_ON(BrowserThread::UI); + DCHECK_CURRENTLY_ON(BrowserThread::IO); + DCHECK(forwarding_factory_); TRACE_EVENT2( "audio", "RenderFrameAudioOutputStreamFactory::RequestDeviceAuthorization", "device id", device_id, "session_id", session_id); const base::TimeTicks auth_start_time = base::TimeTicks::Now(); - // TODO(https://crbug.com/837625): This thread hopping is suboptimal since - // AudioOutputAuthorizationHandler was made to be used on the IO thread. - // Make AudioOutputAuthorizationHandler work on the UI thread instead. - AudioOutputAuthorizationHandler::AuthorizationCompletedCallback - completed_callback = media::BindToCurrentLoop(base::BindOnce( - &RenderFrameAudioOutputStreamFactory::AuthorizationCompleted, - weak_ptr_factory_.GetWeakPtr(), auth_start_time, - std::move(provider_request), std::move(callback))); - // Unretained is safe since |authorization_handler_| is deleted on the IO - // thread. - base::PostTaskWithTraits( - FROM_HERE, {BrowserThread::IO}, - base::BindOnce( - &AudioOutputAuthorizationHandler::RequestDeviceAuthorization, - base::Unretained(authorization_handler_.get()), - frame_->GetRoutingID(), session_id, device_id, - std::move(completed_callback))); + AudioOutputAuthorizationHandler::AuthorizationCompletedCallback + completed_callback = base::BindOnce( + &RenderFrameAudioOutputStreamFactory::Core::AuthorizationCompleted, + weak_ptr_factory_.GetWeakPtr(), auth_start_time, + std::move(provider_request), std::move(callback)); + + authorization_handler_.RequestDeviceAuthorization( + frame_id_, session_id, device_id, std::move(completed_callback)); } -void RenderFrameAudioOutputStreamFactory::AuthorizationCompleted( +void RenderFrameAudioOutputStreamFactory::Core::AuthorizationCompleted( base::TimeTicks auth_start_time, media::mojom::AudioOutputStreamProviderRequest request, RequestDeviceAuthorizationCallback callback, @@ -132,7 +237,7 @@ const media::AudioParameters& params, const std::string& raw_device_id, const std::string& device_id_for_renderer) { - DCHECK_CURRENTLY_ON(BrowserThread::UI); + DCHECK_CURRENTLY_ON(BrowserThread::IO); TRACE_EVENT2("audio", "RenderFrameAudioOutputStreamFactory::AuthorizationCompleted", "raw device id", raw_device_id, "status", status); @@ -150,9 +255,9 @@ } } -void RenderFrameAudioOutputStreamFactory::DeleteProvider( +void RenderFrameAudioOutputStreamFactory::Core::DeleteProvider( media::mojom::AudioOutputStreamProvider* stream_provider) { - DCHECK_CURRENTLY_ON(BrowserThread::UI); + DCHECK_CURRENTLY_ON(BrowserThread::IO); size_t deleted = stream_providers_.erase(stream_provider); DCHECK_EQ(1u, deleted); }
diff --git a/content/browser/renderer_host/media/render_frame_audio_output_stream_factory.h b/content/browser/renderer_host/media/render_frame_audio_output_stream_factory.h index fbc229b..92c5eb29 100644 --- a/content/browser/renderer_host/media/render_frame_audio_output_stream_factory.h +++ b/content/browser/renderer_host/media/render_frame_audio_output_stream_factory.h
@@ -5,36 +5,46 @@ #ifndef CONTENT_BROWSER_RENDERER_HOST_MEDIA_RENDER_FRAME_AUDIO_OUTPUT_STREAM_FACTORY_H_ #define CONTENT_BROWSER_RENDERER_HOST_MEDIA_RENDER_FRAME_AUDIO_OUTPUT_STREAM_FACTORY_H_ +#include <cstddef> #include <memory> -#include <string> -#include "base/containers/flat_set.h" -#include "base/containers/unique_ptr_adapters.h" #include "base/macros.h" -#include "base/memory/weak_ptr.h" -#include "base/time/time.h" #include "content/common/content_export.h" #include "content/common/media/renderer_audio_output_stream_factory.mojom.h" -#include "content/public/browser/browser_thread.h" -#include "media/base/output_device_info.h" -#include "mojo/public/cpp/bindings/binding.h" namespace media { class AudioSystem; -class AudioParameters; } // namespace media namespace content { -class AudioOutputAuthorizationHandler; class MediaStreamManager; class RenderFrameHost; -// This class, which lives on the UI thread, takes care of stream requests from -// a render frame. It verifies that the stream creation is allowed and then -// forwards the request to the appropriate ForwardingAudioStreamFactory. -class CONTENT_EXPORT RenderFrameAudioOutputStreamFactory - : public mojom::RendererAudioOutputStreamFactory { +// This class is related to ForwardingAudioStreamFactory as follows: +// +// WebContentsImpl <-- RenderFrameHostImpl +// ^ ^ +// | | +// ForwardingAudioStreamFactory RenderFrameAudioOutputStreamFactory +// ^ ^ +// | | +// FASF::Core <-- RFAOSF::Core +// +// Both FASF::Core and RFAOSF::Core live on (and are destructed on) the IO +// thread. ForwardingAudioStreamFactory exists until destruction of its owning +// WebContentsImpl. Since WebContentsImpl outlives all of its +// RenderFrameHostImpls, ForwardingAudioStreamFactory will outlive +// RenderFrameAudioOutputStreamFactory. As a consequence, the destruction of +// FASF::Core will be posted to the IO thread after the destruction of +// RFAOSF::Core has been posted, so RFAOSF::Core can safely have a raw pointer +// to FASF::Core + +// This class takes care of stream requests from a render frame. It verifies +// that the stream creation is allowed and then forwards the request to the +// appropriate ForwardingAudioStreamFactory. It should be constructed and +// destructed on the UI thread, but will process mojo messages on the IO thread. +class CONTENT_EXPORT RenderFrameAudioOutputStreamFactory final { public: RenderFrameAudioOutputStreamFactory( RenderFrameHost* frame, @@ -42,56 +52,13 @@ MediaStreamManager* media_stream_manager, mojom::RendererAudioOutputStreamFactoryRequest request); - ~RenderFrameAudioOutputStreamFactory() override; + ~RenderFrameAudioOutputStreamFactory(); - size_t current_number_of_providers_for_testing() { - return stream_providers_.size(); - } + size_t CurrentNumberOfProvidersForTesting(); private: - class ProviderImpl; - friend class ProviderImpl; // For DeleteProvider. - - using OutputStreamProviderSet = - base::flat_set<std::unique_ptr<media::mojom::AudioOutputStreamProvider>, - base::UniquePtrComparator>; - - // mojom::RendererAudioOutputStreamFactory implementation. - void RequestDeviceAuthorization( - media::mojom::AudioOutputStreamProviderRequest provider_request, - int32_t session_id, - const std::string& device_id, - RequestDeviceAuthorizationCallback callback) override; - - // Here, the |raw_device_id| is used to create the stream, and - // |device_id_for_renderer| is nonempty in the case when the renderer - // requested a device using a |session_id|, to let it know which device was - // chosen. This id is hashed. - void AuthorizationCompleted( - base::TimeTicks auth_start_time, - media::mojom::AudioOutputStreamProviderRequest request, - RequestDeviceAuthorizationCallback callback, - media::OutputDeviceStatus status, - const media::AudioParameters& params, - const std::string& raw_device_id, - const std::string& device_id_for_renderer); - - void DeleteProvider(media::mojom::AudioOutputStreamProvider* stream_provider); - - const mojo::Binding<mojom::RendererAudioOutputStreamFactory> binding_; - RenderFrameHost* const frame_; - const std::unique_ptr<AudioOutputAuthorizationHandler, - BrowserThread::DeleteOnIOThread> - authorization_handler_; - - // The OutputStreamProviders for authorized streams are kept here while - // waiting for the renderer to finish creating the stream, and destructed - // afterwards. - OutputStreamProviderSet stream_providers_; - - // Weak pointers are used to cancel device authorizations that are in flight - // while |this| is destructed. - base::WeakPtrFactory<RenderFrameAudioOutputStreamFactory> weak_ptr_factory_; + class Core; + std::unique_ptr<Core> core_; DISALLOW_COPY_AND_ASSIGN(RenderFrameAudioOutputStreamFactory); };
diff --git a/content/browser/renderer_host/media/render_frame_audio_output_stream_factory_unittest.cc b/content/browser/renderer_host/media/render_frame_audio_output_stream_factory_unittest.cc index b8e8850..f7f4fc6 100644 --- a/content/browser/renderer_host/media/render_frame_audio_output_stream_factory_unittest.cc +++ b/content/browser/renderer_host/media/render_frame_audio_output_stream_factory_unittest.cc
@@ -5,6 +5,7 @@ #include "content/browser/renderer_host/media/render_frame_audio_output_stream_factory.h" #include <memory> +#include <string> #include <utility> #include "base/bind.h" @@ -69,6 +70,7 @@ // Set up the ForwardingAudioStreamFactory. service_manager::Connector::TestApi connector_test_api( ForwardingAudioStreamFactory::ForFrame(main_rfh()) + ->core() ->get_connector_for_testing()); connector_test_api.OverrideBinderForTesting( service_manager::Identity(audio::mojom::kServiceName), @@ -155,7 +157,7 @@ base::RunLoop().RunUntilIdle(); - EXPECT_EQ(1u, factory.current_number_of_providers_for_testing()); + EXPECT_EQ(1u, factory.CurrentNumberOfProvidersForTesting()); } TEST_F( @@ -178,7 +180,7 @@ base::RunLoop().RunUntilIdle(); - EXPECT_EQ(0u, factory.current_number_of_providers_for_testing()); + EXPECT_EQ(0u, factory.CurrentNumberOfProvidersForTesting()); } TEST_F( @@ -200,7 +202,7 @@ base::RunLoop().RunUntilIdle(); - EXPECT_EQ(0u, factory.current_number_of_providers_for_testing()); + EXPECT_EQ(0u, factory.CurrentNumberOfProvidersForTesting()); } TEST_F(RenderFrameAudioOutputStreamFactoryTest, @@ -228,7 +230,7 @@ base::RunLoop().RunUntilIdle(); EXPECT_TRUE(!!audio_service_stream_factory_.last_created_callback); - EXPECT_EQ(0u, factory.current_number_of_providers_for_testing()); + EXPECT_EQ(0u, factory.CurrentNumberOfProvidersForTesting()); } TEST_F(RenderFrameAudioOutputStreamFactoryTest,
diff --git a/content/browser/storage_partition_impl_unittest.cc b/content/browser/storage_partition_impl_unittest.cc index 091fa3c..d0942e10 100644 --- a/content/browser/storage_partition_impl_unittest.cc +++ b/content/browser/storage_partition_impl_unittest.cc
@@ -27,6 +27,7 @@ #include "content/public/test/test_browser_context.h" #include "content/public/test/test_browser_thread.h" #include "content/public/test/test_browser_thread_bundle.h" +#include "content/public/test/test_utils.h" #include "content/test/fake_leveldb_database.h" #include "net/base/features.h" #include "net/base/test_completion_callback.h" @@ -306,6 +307,9 @@ std::vector<uint8_t> data_vector(data.begin(), data.end()); GetCache(cache)->WriteData(url, origin, base::Time::Now(), data_vector); base::RunLoop().RunUntilIdle(); + // TODO(crbug.com/886892): Remove this once we update GeneratedCodeCache + // to serialize operations corresponding to each entry. + content::RunAllTasksUntilIdle(); } std::string received_data() { return received_data_; } @@ -1335,14 +1339,15 @@ } TEST_F(StoragePartitionImplTest, ClearCodeCache) { - // Run this test only when the IsolatedCodeCache feature is enabled - if (!base::FeatureList::IsEnabled(net::features::kIsolatedCodeCache)) - return; + base::test::ScopedFeatureList feature_list; + feature_list.InitAndEnableFeature(net::features::kIsolatedCodeCache); + ASSERT_TRUE(base::FeatureList::IsEnabled(net::features::kIsolatedCodeCache)); StoragePartitionImpl* partition = static_cast<StoragePartitionImpl*>( BrowserContext::GetDefaultStoragePartition(browser_context())); // Ensure code cache is initialized. base::RunLoop().RunUntilIdle(); + EXPECT_TRUE(partition->GetGeneratedCodeCacheContext() != nullptr); RemoveCodeCacheTester tester(partition->GetGeneratedCodeCacheContext());
diff --git a/content/public/android/java/src/org/chromium/content/browser/input/SuggestionsPopupWindow.java b/content/public/android/java/src/org/chromium/content/browser/input/SuggestionsPopupWindow.java index 7b1fc0c..400f18c 100644 --- a/content/public/android/java/src/org/chromium/content/browser/input/SuggestionsPopupWindow.java +++ b/content/public/android/java/src/org/chromium/content/browser/input/SuggestionsPopupWindow.java
@@ -150,7 +150,7 @@ // Set this on the content view instead of on the PopupWindow so we can retrieve the // padding later. mContentView.setBackground(ApiCompatibilityUtils.getDrawable( - mContext.getResources(), R.drawable.dropdown_popup_background)); + mContext.getResources(), R.drawable.popup_bg)); } // mPopupVerticalMargin is the minimum amount of space we want to have between the popup
diff --git a/content/public/common/content_features.cc b/content/public/common/content_features.cc index 2301015..9620a913 100644 --- a/content/public/common/content_features.cc +++ b/content/public/common/content_features.cc
@@ -656,11 +656,6 @@ // Enable IOSurface based screen capturer. const base::Feature kIOSurfaceCapturer{"IOSurfaceCapturer", base::FEATURE_ENABLED_BY_DEFAULT}; - -// The V2 sandbox on MacOS removes the unsandboed warmup phase and sandboxes the -// entire life of the process. -const base::Feature kMacV2Sandbox{"MacV2Sandbox", - base::FEATURE_ENABLED_BY_DEFAULT}; #endif // defined(OS_MACOSX) enum class VideoCaptureServiceConfiguration {
diff --git a/content/public/common/content_features.h b/content/public/common/content_features.h index 92b0561..9305262 100644 --- a/content/public/common/content_features.h +++ b/content/public/common/content_features.h
@@ -159,7 +159,6 @@ #if defined(OS_MACOSX) CONTENT_EXPORT extern const base::Feature kDeviceMonitorMac; CONTENT_EXPORT extern const base::Feature kIOSurfaceCapturer; -CONTENT_EXPORT extern const base::Feature kMacV2Sandbox; #endif // defined(OS_MACOSX) // DON'T ADD RANDOM STUFF HERE. Put it in the main section above in
diff --git a/content/public/renderer/content_renderer_client.cc b/content/public/renderer/content_renderer_client.cc index a18e1a92..668f54b 100644 --- a/content/public/renderer/content_renderer_client.cc +++ b/content/public/renderer/content_renderer_client.cc
@@ -236,6 +236,11 @@ return true; } +base::Optional<std::string> +ContentRendererClient::WebRTCPlatformSpecificAudioProcessingConfiguration() { + return base::Optional<std::string>(); +} + GURL ContentRendererClient::OverrideFlashEmbedWithHTML(const GURL& url) { return GURL(); }
diff --git a/content/public/renderer/content_renderer_client.h b/content/public/renderer/content_renderer_client.h index 794ef35..3166cbe2 100644 --- a/content/public/renderer/content_renderer_client.h +++ b/content/public/renderer/content_renderer_client.h
@@ -15,6 +15,7 @@ #include "base/callback_forward.h" #include "base/files/file_path.h" #include "base/memory/ref_counted.h" +#include "base/optional.h" #include "base/strings/string16.h" #include "base/task/task_scheduler/task_scheduler.h" #include "build/build_config.h" @@ -378,6 +379,14 @@ // routing logic, i.e. allowing multiple routes and non-proxied UDP. virtual bool ShouldEnforceWebRTCRoutingPreferences(); + // Provides a default configuration of WebRTC audio processing, in JSON format + // with fields corresponding to webrtc::AudioProcessing::Config. Allows for a + // more functional tuning on platforms with known implementation and hardware + // limitations. + // This is currently not supported when running the Chrome audio service. + virtual base::Optional<std::string> + WebRTCPlatformSpecificAudioProcessingConfiguration(); + // Notifies that a worker context has been created. This function is called // from the worker thread. virtual void DidInitializeWorkerContextOnWorkerThread(
diff --git a/content/renderer/BUILD.gn b/content/renderer/BUILD.gn index 5c6fae65..883df3b1 100644 --- a/content/renderer/BUILD.gn +++ b/content/renderer/BUILD.gn
@@ -711,6 +711,8 @@ "//third_party/webrtc/api:libjingle_logging_api", "//third_party/webrtc/api:libjingle_peerconnection_api", "//third_party/webrtc/api:rtc_stats_api", + "//third_party/webrtc/api/audio:aec3_config", + "//third_party/webrtc/api/audio:aec3_config_json", "//third_party/webrtc/api/audio:aec3_factory", "//third_party/webrtc/api/audio_codecs:audio_codecs_api", "//third_party/webrtc/api/audio_codecs/L16:audio_decoder_L16",
diff --git a/content/renderer/loader/resource_dispatcher.cc b/content/renderer/loader/resource_dispatcher.cc index 4fc82f3..dd7f440d 100644 --- a/content/renderer/loader/resource_dispatcher.cc +++ b/content/renderer/loader/resource_dispatcher.cc
@@ -515,6 +515,7 @@ } network::URLLoaderCompletionStatus renderer_status(status); + // TODO(toyoshim): Consider to convert status.cors_preflight_timing_info here. if (status.completion_time.is_null()) { // No completion timestamp is provided, leave it as is. } else if (request_info->remote_request_start.is_null() ||
diff --git a/content/renderer/loader/web_url_loader_impl.cc b/content/renderer/loader/web_url_loader_impl.cc index 797316a..3479b62 100644 --- a/content/renderer/loader/web_url_loader_impl.cc +++ b/content/renderer/loader/web_url_loader_impl.cc
@@ -978,7 +978,8 @@ } else { client_->DidFinishLoading(status.completion_time, total_transfer_size, encoded_body_size, status.decoded_body_length, - status.should_report_corb_blocking); + status.should_report_corb_blocking, + status.cors_preflight_timing_info); } } }
diff --git a/content/renderer/loader/web_url_loader_impl_unittest.cc b/content/renderer/loader/web_url_loader_impl_unittest.cc index 1a1c1286..d9a336e 100644 --- a/content/renderer/loader/web_url_loader_impl_unittest.cc +++ b/content/renderer/loader/web_url_loader_impl_unittest.cc
@@ -240,11 +240,13 @@ loader_.reset(); } - void DidFinishLoading(base::TimeTicks finishTime, - int64_t totalEncodedDataLength, - int64_t totalEncodedBodyLength, - int64_t totalDecodedBodyLength, - bool should_report_corb_blocking) override { + void DidFinishLoading( + base::TimeTicks finishTime, + int64_t totalEncodedDataLength, + int64_t totalEncodedBodyLength, + int64_t totalDecodedBodyLength, + bool should_report_corb_blocking, + const std::vector<network::cors::PreflightTimingInfo>&) override { EXPECT_TRUE(loader_); EXPECT_TRUE(did_receive_response_); EXPECT_FALSE(did_finish_);
diff --git a/content/renderer/media/stream/media_stream_audio_processor.cc b/content/renderer/media/stream/media_stream_audio_processor.cc index b3989eb..444d282 100644 --- a/content/renderer/media/stream/media_stream_audio_processor.cc +++ b/content/renderer/media/stream/media_stream_audio_processor.cc
@@ -22,7 +22,9 @@ #include "base/threading/thread_task_runner_handle.h" #include "base/trace_event/trace_event.h" #include "build/build_config.h" +#include "content/public/common/content_client.h" #include "content/public/common/content_features.h" +#include "content/public/renderer/content_renderer_client.h" #include "content/renderer/media/webrtc/webrtc_audio_device_impl.h" #include "media/base/audio_converter.h" #include "media/base/audio_fifo.h" @@ -30,6 +32,8 @@ #include "media/base/channel_layout.h" #include "media/webrtc/echo_information.h" #include "media/webrtc/webrtc_switches.h" +#include "third_party/webrtc/api/audio/echo_canceller3_config.h" +#include "third_party/webrtc/api/audio/echo_canceller3_config_json.h" #include "third_party/webrtc/api/audio/echo_canceller3_factory.h" #include "third_party/webrtc/api/mediaconstraintsinterface.h" #include "third_party/webrtc/modules/audio_processing/include/audio_processing_statistics.h" @@ -598,11 +602,22 @@ if (properties.echo_cancellation_type == EchoCancellationType::kEchoCancellationAec3) { webrtc::EchoCanceller3Config aec3_config; - aec3_config.ep_strength.bounded_erl = + base::Optional<std::string> audio_processing_platform_config_json = + GetContentClient() + ->renderer() + ->WebRTCPlatformSpecificAudioProcessingConfiguration(); + if (audio_processing_platform_config_json) { + aec3_config = webrtc::Aec3ConfigFromJsonString( + *audio_processing_platform_config_json); + bool config_parameters_already_valid = + webrtc::EchoCanceller3Config::Validate(&aec3_config); + RTC_DCHECK(config_parameters_already_valid); + } + aec3_config.ep_strength.bounded_erl |= base::FeatureList::IsEnabled(features::kWebRtcAecBoundedErlSetup); - aec3_config.echo_removal_control.has_clock_drift = + aec3_config.echo_removal_control.has_clock_drift |= base::FeatureList::IsEnabled(features::kWebRtcAecClockDriftSetup); - aec3_config.echo_audibility.use_stationary_properties = + aec3_config.echo_audibility.use_stationary_properties |= base::FeatureList::IsEnabled(features::kWebRtcAecNoiseTransparency); ap_builder.SetEchoControlFactory(
diff --git a/content/test/data/font_src_local_matching.html b/content/test/data/font_src_local_matching.html index 163d4f46..e12fc4c 100644 --- a/content/test/data/font_src_local_matching.html +++ b/content/test/data/font_src_local_matching.html
@@ -84,12 +84,25 @@ ["muktinarrow", "0"], ["Tinos-Regular", "0"] ]; - } + } else if (navigator.userAgent.indexOf("Macintosh") !== -1) { + return [ + [ "AmericanTypewriter-CondensedLight", "0" ], + [ "ArialNarrow-BoldItalic", "0" ], + [ "Baskerville-SemiBoldItalic", "0" ], + [ "DevanagariMT", "0" ], + [ "DINAlternate-Bold", "0" ], + [ "GillSans-LightItalic", "0" ], + [ "IowanOldStyle-Titling", "0" ], + [ "MalayalamSangamMN", "0" ], + [ "HiraMaruPro-W4", "0" ], + [ "HiraKakuStdN-W8", "0" ], + ] + }; return []; } function stripSpaces(fontName) { - return fontName.replace(/\s+/g, ''); + return fontName.replace(/\s+/g, ''); } function addTestNodes() {
diff --git a/gpu/command_buffer/service/gl_context_virtual.cc b/gpu/command_buffer/service/gl_context_virtual.cc index 7d83352..3d19ed8e 100644 --- a/gpu/command_buffer/service/gl_context_virtual.cc +++ b/gpu/command_buffer/service/gl_context_virtual.cc
@@ -121,6 +121,10 @@ void GLContextVirtual::BackpressureFenceWait(uint64_t fence) { shared_context_->BackpressureFenceWait(fence); } + +void GLContextVirtual::FlushForDriverCrashWorkaround() { + shared_context_->FlushForDriverCrashWorkaround(); +} #endif GLContextVirtual::~GLContextVirtual() {
diff --git a/gpu/command_buffer/service/gl_context_virtual.h b/gpu/command_buffer/service/gl_context_virtual.h index f0156ead..5ed61a9 100644 --- a/gpu/command_buffer/service/gl_context_virtual.h +++ b/gpu/command_buffer/service/gl_context_virtual.h
@@ -50,6 +50,7 @@ #if defined(OS_MACOSX) uint64_t BackpressureFenceCreate() override; void BackpressureFenceWait(uint64_t fence) override; + void FlushForDriverCrashWorkaround() override; #endif protected:
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder.cc b/gpu/command_buffer/service/gles2_cmd_decoder.cc index 151500b..08706db0 100644 --- a/gpu/command_buffer/service/gles2_cmd_decoder.cc +++ b/gpu/command_buffer/service/gles2_cmd_decoder.cc
@@ -5692,6 +5692,15 @@ } } +#if defined(OS_MACOSX) + // Aggressively call glFlush on macOS. This is the only fix that has been + // found so far to avoid crashes on Intel drivers. The workaround + // isn't needed for WebGL contexts, though. + // https://crbug.com/863817 + if (!feature_info_->IsWebGLContext()) + context_->FlushForDriverCrashWorkaround(); +#endif + *entries_processed = process_pos; if (error::IsError(result)) {
diff --git a/ios/chrome/app/BUILD.gn b/ios/chrome/app/BUILD.gn index d4fe5e5d..de2ae81 100644 --- a/ios/chrome/app/BUILD.gn +++ b/ios/chrome/app/BUILD.gn
@@ -61,8 +61,10 @@ "//ios/chrome/common/app_group", "//ios/chrome/test:test_support", "//ios/chrome/test/base", - "//ios/public/provider/chrome/browser", + "//ios/public/provider/chrome/browser:browser", + "//ios/public/provider/chrome/browser:test_support", "//ios/public/provider/chrome/browser/distribution", + "//ios/public/provider/chrome/browser/distribution:test_support", "//ios/web/public/test:test", "//testing/gtest", "//third_party/ocmock",
diff --git a/ios/chrome/app/firebase_utils.h b/ios/chrome/app/firebase_utils.h index cdbef3cb..cce0e54 100644 --- a/ios/chrome/app/firebase_utils.h +++ b/ios/chrome/app/firebase_utils.h
@@ -27,8 +27,12 @@ // Firebase Analytics is for installation reporting only. Once a user has // passed the conversion attribution window, there is nothing to report. kDisabledConversionWindow, + // Users who installed Chrome prior to incorporating Firebase into Chrome + // should not initialize Firebase because these users could not have been + // the result of any promption campaigns that use Firebase Analytics. + kDisabledLegacyInstallation, // Count of enum values. Must be equal to the last value above. - kMaxValue = kDisabledConversionWindow, + kMaxValue = kDisabledLegacyInstallation, }; // Initializes Firebase SDK if configured and necessary.
diff --git a/ios/chrome/app/firebase_utils.mm b/ios/chrome/app/firebase_utils.mm index f9d04a8..72c98ba 100644 --- a/ios/chrome/app/firebase_utils.mm +++ b/ios/chrome/app/firebase_utils.mm
@@ -13,6 +13,8 @@ #include "components/prefs/pref_service.h" #import "ios/chrome/app/firebase_buildflags.h" #include "ios/chrome/browser/application_context.h" +#import "ios/public/provider/chrome/browser/chrome_browser_provider.h" +#import "ios/public/provider/chrome/browser/distribution/app_distribution_provider.h" #if BUILDFLAG(FIREBASE_ENABLED) #import "ios/third_party/firebase/Analytics/FirebaseCore.framework/Headers/FIRApp.h" #endif // BUILDFLAG(FIREBASE_ENABLED) @@ -32,10 +34,25 @@ const int64_t install_date = prefs->GetInt64(metrics::prefs::kInstallDate); base::TimeDelta installed_delta = base::TimeDelta::FromSeconds(base::Time::Now().ToTimeT() - install_date); - // Initialize Firebase SDK to allow first_open event to be uploaded until - // Attribution Window has passed. + // Initialize Firebase SDK only if there is a possibility that user + // installed Chrome as a result of some marketing campaigns. + // 1. If user installed Chrome prior to the first version of Chrome that + // supports Firebase SDK, this is a legacy user who would not be + // attributable to any marketing event. Firebase SDK should not be + // initialized in this case. + // 2. Installation Attribution is the association of a Chrome installation + // to some marketing event. This attribution is valid only if it happens + // within a reasonable timeframe. If installation date is older than + // the acceptable Attribution Window, there is no need to initialize + // Firebase SDK since the first_open event would not be considered for + // attribution to this installation to a marketing event. FirebaseConfiguredState enabled_state; - if (installed_delta.InDaysFloored() >= kConversionAttributionWindowInDays) { + auto* provider = + ios::GetChromeBrowserProvider()->GetAppDistributionProvider(); + if (provider->IsPreFirebaseLegacyUser(install_date)) { + enabled_state = FirebaseConfiguredState::kDisabledLegacyInstallation; + } else if (installed_delta.InDaysFloored() >= + kConversionAttributionWindowInDays) { enabled_state = FirebaseConfiguredState::kDisabledConversionWindow; } else { [FIRApp configure];
diff --git a/ios/chrome/app/firebase_utils_unittest.mm b/ios/chrome/app/firebase_utils_unittest.mm index fb21636..3f17037f 100644 --- a/ios/chrome/app/firebase_utils_unittest.mm +++ b/ios/chrome/app/firebase_utils_unittest.mm
@@ -18,6 +18,9 @@ #if BUILDFLAG(FIREBASE_ENABLED) #import "ios/third_party/firebase/Analytics/FirebaseCore.framework/Headers/FIRApp.h" #endif // BUILDFLAG(FIREBASE_ENABLED) +#include "ios/chrome/test/ios_chrome_scoped_testing_chrome_browser_provider.h" +#include "ios/public/provider/chrome/browser/distribution/test_app_distribution_provider.h" +#include "ios/public/provider/chrome/browser/test_chrome_browser_provider.h" #include "ios/web/public/test/test_web_thread_bundle.h" #include "testing/gtest/include/gtest/gtest.h" #include "testing/platform_test.h" @@ -28,6 +31,29 @@ #error "This file requires ARC support." #endif +#if BUILDFLAG(FIREBASE_ENABLED) +class LegacyUserAppDistributionProvider : public TestAppDistributionProvider { + public: + bool IsPreFirebaseLegacyUser(int64_t install_date) override { return true; } +}; + +class FakeChromeBrowserProvider : public ios::TestChromeBrowserProvider { + public: + FakeChromeBrowserProvider() + : app_distribution_provider_( + std::make_unique<LegacyUserAppDistributionProvider>()) {} + ~FakeChromeBrowserProvider() override {} + + AppDistributionProvider* GetAppDistributionProvider() const override { + return app_distribution_provider_.get(); + } + + private: + std::unique_ptr<LegacyUserAppDistributionProvider> app_distribution_provider_; + DISALLOW_COPY_AND_ASSIGN(FakeChromeBrowserProvider); +}; +#endif // BUILDFLAG(FIREBASE_ENABLED) + class FirebaseUtilsTest : public PlatformTest { public: FirebaseUtilsTest() @@ -84,7 +110,7 @@ // window. int64_t before_attribution = base::TimeDelta::FromDays(kConversionAttributionWindowInDays + 1) - .InMilliseconds(); + .InSeconds(); SetInstallDate(base::Time::Now().ToTimeT() - before_attribution); // Expects Firebase SDK initialization to be not called. [[firapp_ reject] configure]; @@ -95,6 +121,23 @@ EXPECT_OCMOCK_VERIFY(firapp_); } +TEST_F(FirebaseUtilsTest, DisabledLegacyInstallation) { + // Sets up the ChromeProviderEnvironment with a fake provider that responds + // positively that user is a legacy user predating Firebase integration. + IOSChromeScopedTestingChromeBrowserProvider provider_( + std::make_unique<FakeChromeBrowserProvider>()); + // Set an app install date that is at least a year ago. + int64_t a_year_ago = base::TimeDelta::FromDays(365).InSeconds(); + SetInstallDate(base::Time::Now().ToTimeT() - a_year_ago); + // Expects Firebase SDK initialization to be not called. + [[firapp_ reject] configure]; + InitializeFirebase(/*is_first_run=*/true); + histogram_tester_.ExpectUniqueSample( + kFirebaseConfiguredHistogramName, + FirebaseConfiguredState::kDisabledLegacyInstallation, 1); + EXPECT_OCMOCK_VERIFY(firapp_); +} + #else TEST_F(FirebaseUtilsTest, DisabledInitializedHistogram) {
diff --git a/ios/chrome/browser/BUILD.gn b/ios/chrome/browser/BUILD.gn index aff3b33..b6f5a5c 100644 --- a/ios/chrome/browser/BUILD.gn +++ b/ios/chrome/browser/BUILD.gn
@@ -87,6 +87,7 @@ "//components/flags_ui", "//components/flags_ui:switches", "//components/handoff", + "//components/invalidation/impl:impl", "//components/keyed_service/core", "//components/keyed_service/ios", "//components/metrics",
diff --git a/ios/chrome/browser/about_flags.mm b/ios/chrome/browser/about_flags.mm index d75e597..0853824 100644 --- a/ios/chrome/browser/about_flags.mm +++ b/ios/chrome/browser/about_flags.mm
@@ -30,6 +30,7 @@ #include "components/flags_ui/feature_entry_macros.h" #include "components/flags_ui/flags_storage.h" #include "components/flags_ui/flags_ui_switches.h" +#include "components/invalidation/impl/invalidation_switches.h" #include "components/ntp_tiles/switches.h" #include "components/omnibox/browser/omnibox_field_trial.h" #include "components/password_manager/core/common/password_manager_features.h" @@ -381,6 +382,9 @@ flag_descriptions::kOmniboxTabSwitchSuggestionsDescription, flags_ui::kOsIos, FEATURE_VALUE_TYPE(omnibox::kOmniboxTabSwitchSuggestions)}, + {"fcm-invalidations", flag_descriptions::kFCMInvalidationsName, + flag_descriptions::kFCMInvalidationsDescription, flags_ui::kOsIos, + FEATURE_VALUE_TYPE(invalidation::switches::kFCMInvalidations)}, }; // Add all switches from experimental flags to |command_line|.
diff --git a/ios/chrome/browser/app_launcher/app_launcher_tab_helper_unittest.mm b/ios/chrome/browser/app_launcher/app_launcher_tab_helper_unittest.mm index 02df437..38901f1 100644 --- a/ios/chrome/browser/app_launcher/app_launcher_tab_helper_unittest.mm +++ b/ios/chrome/browser/app_launcher/app_launcher_tab_helper_unittest.mm
@@ -116,6 +116,7 @@ auto navigation_manager = std::make_unique<FakeNavigationManager>(); navigation_manager_ = navigation_manager.get(); web_state_.SetNavigationManager(std::move(navigation_manager)); + web_state_.SetCurrentURL(GURL("https://chromium.org")); tab_helper_ = AppLauncherTabHelper::FromWebState(&web_state_); }
diff --git a/ios/chrome/browser/autocomplete/BUILD.gn b/ios/chrome/browser/autocomplete/BUILD.gn index 27f4696..fd0a873a 100644 --- a/ios/chrome/browser/autocomplete/BUILD.gn +++ b/ios/chrome/browser/autocomplete/BUILD.gn
@@ -6,8 +6,8 @@ sources = [ "autocomplete_classifier_factory.cc", "autocomplete_classifier_factory.h", - "autocomplete_provider_client_impl.cc", "autocomplete_provider_client_impl.h", + "autocomplete_provider_client_impl.mm", "autocomplete_scheme_classifier_impl.h", "autocomplete_scheme_classifier_impl.mm", "in_memory_url_index_factory.cc", @@ -36,7 +36,9 @@ "//ios/chrome/browser/search_engines", "//ios/chrome/browser/signin", "//ios/chrome/browser/sync", + "//ios/chrome/browser/tabs", "//ios/chrome/browser/unified_consent", + "//ios/chrome/browser/web_state_list", "//ios/public/provider/chrome/browser", "//ios/web", "//url",
diff --git a/ios/chrome/browser/autocomplete/autocomplete_provider_client_impl.cc b/ios/chrome/browser/autocomplete/autocomplete_provider_client_impl.mm similarity index 91% rename from ios/chrome/browser/autocomplete/autocomplete_provider_client_impl.cc rename to ios/chrome/browser/autocomplete/autocomplete_provider_client_impl.mm index 37daccf..5b92bfe 100644 --- a/ios/chrome/browser/autocomplete/autocomplete_provider_client_impl.cc +++ b/ios/chrome/browser/autocomplete/autocomplete_provider_client_impl.mm
@@ -28,9 +28,17 @@ #include "ios/chrome/browser/search_engines/template_url_service_factory.h" #include "ios/chrome/browser/signin/signin_manager_factory.h" #include "ios/chrome/browser/sync/profile_sync_service_factory.h" +#import "ios/chrome/browser/tabs/tab_model.h" +#import "ios/chrome/browser/tabs/tab_model_list.h" #include "ios/chrome/browser/unified_consent/unified_consent_service_factory.h" +#import "ios/chrome/browser/web_state_list/web_state_list.h" +#import "ios/web/public/web_state/web_state.h" #include "services/network/public/cpp/shared_url_loader_factory.h" +#if !defined(__has_feature) || !__has_feature(objc_arc) +#error "This file requires ARC support." +#endif + AutocompleteProviderClientImpl::AutocompleteProviderClientImpl( ios::ChromeBrowserState* browser_state) : browser_state_(browser_state), @@ -217,5 +225,18 @@ bool AutocompleteProviderClientImpl::IsTabOpenWithURL( const GURL& url, const AutocompleteInput* input) { + TabModel* tab_model = + TabModelList::GetLastActiveTabModelForChromeBrowserState(browser_state_); + WebStateList* web_state_list = tab_model.webStateList; + if (!web_state_list) + return false; + + for (int index = 0; index < web_state_list->count(); index++) { + web::WebState* web_state = web_state_list->GetWebStateAt(index); + + if (web_state != web_state_list->GetActiveWebState() && + url == web_state->GetVisibleURL()) + return true; + } return false; }
diff --git a/ios/chrome/browser/browser_state/browser_state_keyed_service_factories.mm b/ios/chrome/browser/browser_state/browser_state_keyed_service_factories.mm index 623cefa8..c5f6200 100644 --- a/ios/chrome/browser/browser_state/browser_state_keyed_service_factories.mm +++ b/ios/chrome/browser/browser_state/browser_state_keyed_service_factories.mm
@@ -27,7 +27,7 @@ #include "ios/chrome/browser/history/history_service_factory.h" #include "ios/chrome/browser/history/top_sites_factory.h" #include "ios/chrome/browser/history/web_history_service_factory.h" -#include "ios/chrome/browser/invalidation/ios_chrome_profile_invalidation_provider_factory.h" +#include "ios/chrome/browser/invalidation/ios_chrome_deprecated_profile_invalidation_provider_factory.h" #include "ios/chrome/browser/language/language_model_manager_factory.h" #include "ios/chrome/browser/language/url_language_histogram_factory.h" #include "ios/chrome/browser/ntp_snippets/ios_chrome_content_suggestions_service_factory.h" @@ -116,7 +116,7 @@ IOSChromeFaviconLoaderFactory::GetInstance(); IOSChromeContentSuggestionsServiceFactory::GetInstance(); IOSChromePasswordStoreFactory::GetInstance(); - IOSChromeProfileInvalidationProviderFactory::GetInstance(); + IOSChromeDeprecatedProfileInvalidationProviderFactory::GetInstance(); ModelTypeStoreServiceFactory::GetInstance(); ProfileSyncServiceFactory::GetInstance(); IOSUserEventServiceFactory::GetInstance();
diff --git a/ios/chrome/browser/browser_state/chrome_browser_state_manager_impl.cc b/ios/chrome/browser/browser_state/chrome_browser_state_manager_impl.cc index 50c644f..9bc94a70 100644 --- a/ios/chrome/browser/browser_state/chrome_browser_state_manager_impl.cc +++ b/ios/chrome/browser/browser_state/chrome_browser_state_manager_impl.cc
@@ -32,7 +32,7 @@ #include "ios/chrome/browser/chrome_constants.h" #include "ios/chrome/browser/chrome_paths.h" #include "ios/chrome/browser/desktop_promotion/desktop_promotion_sync_service_factory.h" -#include "ios/chrome/browser/invalidation/ios_chrome_profile_invalidation_provider_factory.h" +#include "ios/chrome/browser/invalidation/ios_chrome_deprecated_profile_invalidation_provider_factory.h" #include "ios/chrome/browser/pref_names.h" #include "ios/chrome/browser/signin/account_consistency_service_factory.h" #include "ios/chrome/browser/signin/account_fetcher_service_factory.h" @@ -216,7 +216,7 @@ ->InitCookieListener(); ios::AccountConsistencyServiceFactory::GetForBrowserState(browser_state); invalidation::ProfileInvalidationProvider* invalidation_provider = - IOSChromeProfileInvalidationProviderFactory::GetForBrowserState( + IOSChromeDeprecatedProfileInvalidationProviderFactory::GetForBrowserState( browser_state); invalidation::InvalidationService* invalidation_service = invalidation_provider ? invalidation_provider->GetInvalidationService()
diff --git a/ios/chrome/browser/invalidation/BUILD.gn b/ios/chrome/browser/invalidation/BUILD.gn index 6099a5b..0ac4f06 100644 --- a/ios/chrome/browser/invalidation/BUILD.gn +++ b/ios/chrome/browser/invalidation/BUILD.gn
@@ -5,8 +5,8 @@ source_set("invalidation") { configs += [ "//build/config/compiler:enable_arc" ] sources = [ - "ios_chrome_profile_invalidation_provider_factory.h", - "ios_chrome_profile_invalidation_provider_factory.mm", + "ios_chrome_deprecated_profile_invalidation_provider_factory.h", + "ios_chrome_deprecated_profile_invalidation_provider_factory.mm", ] deps = [ "//base",
diff --git a/ios/chrome/browser/invalidation/ios_chrome_profile_invalidation_provider_factory.h b/ios/chrome/browser/invalidation/ios_chrome_deprecated_profile_invalidation_provider_factory.h similarity index 63% rename from ios/chrome/browser/invalidation/ios_chrome_profile_invalidation_provider_factory.h rename to ios/chrome/browser/invalidation/ios_chrome_deprecated_profile_invalidation_provider_factory.h index 8c2aa6a..c46f6bc 100644 --- a/ios/chrome/browser/invalidation/ios_chrome_profile_invalidation_provider_factory.h +++ b/ios/chrome/browser/invalidation/ios_chrome_deprecated_profile_invalidation_provider_factory.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 IOS_CHROME_BROWSER_INVALIDATION_IOS_CHROME_PROFILE_INVALIDATION_PROVIDER_FACTORY_H_ -#define IOS_CHROME_BROWSER_INVALIDATION_IOS_CHROME_PROFILE_INVALIDATION_PROVIDER_FACTORY_H_ +#ifndef IOS_CHROME_BROWSER_INVALIDATION_IOS_CHROME_DEPRECATED_PROFILE_INVALIDATION_PROVIDER_FACTORY_H_ +#define IOS_CHROME_BROWSER_INVALIDATION_IOS_CHROME_DEPRECATED_PROFILE_INVALIDATION_PROVIDER_FACTORY_H_ #include <memory> @@ -29,7 +29,7 @@ // A BrowserContextKeyedServiceFactory to construct InvalidationServices wrapped // in ProfileInvalidationProviders. -class IOSChromeProfileInvalidationProviderFactory +class IOSChromeDeprecatedProfileInvalidationProviderFactory : public BrowserStateKeyedServiceFactory { public: // Returns the ProfileInvalidationProvider for the given |browser_state|, @@ -37,14 +37,14 @@ static invalidation::ProfileInvalidationProvider* GetForBrowserState( ios::ChromeBrowserState* browser_state); - static IOSChromeProfileInvalidationProviderFactory* GetInstance(); + static IOSChromeDeprecatedProfileInvalidationProviderFactory* GetInstance(); private: friend struct base::DefaultSingletonTraits< - IOSChromeProfileInvalidationProviderFactory>; + IOSChromeDeprecatedProfileInvalidationProviderFactory>; - IOSChromeProfileInvalidationProviderFactory(); - ~IOSChromeProfileInvalidationProviderFactory() override; + IOSChromeDeprecatedProfileInvalidationProviderFactory(); + ~IOSChromeDeprecatedProfileInvalidationProviderFactory() override; // BrowserStateKeyedServiceFactory: std::unique_ptr<KeyedService> BuildServiceInstanceFor( @@ -52,7 +52,8 @@ void RegisterBrowserStatePrefs( user_prefs::PrefRegistrySyncable* registry) override; - DISALLOW_COPY_AND_ASSIGN(IOSChromeProfileInvalidationProviderFactory); + DISALLOW_COPY_AND_ASSIGN( + IOSChromeDeprecatedProfileInvalidationProviderFactory); }; -#endif // IOS_CHROME_BROWSER_INVALIDATION_IOS_CHROME_PROFILE_INVALIDATION_PROVIDER_FACTORY_H_ +#endif // IOS_CHROME_BROWSER_INVALIDATION_IOS_CHROME_DEPRECATED_PROFILE_INVALIDATION_PROVIDER_FACTORY_H_
diff --git a/ios/chrome/browser/invalidation/ios_chrome_profile_invalidation_provider_factory.mm b/ios/chrome/browser/invalidation/ios_chrome_deprecated_profile_invalidation_provider_factory.mm similarity index 79% rename from ios/chrome/browser/invalidation/ios_chrome_profile_invalidation_provider_factory.mm rename to ios/chrome/browser/invalidation/ios_chrome_deprecated_profile_invalidation_provider_factory.mm index 842ef975..51749a5e 100644 --- a/ios/chrome/browser/invalidation/ios_chrome_profile_invalidation_provider_factory.mm +++ b/ios/chrome/browser/invalidation/ios_chrome_deprecated_profile_invalidation_provider_factory.mm
@@ -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 "ios/chrome/browser/invalidation/ios_chrome_profile_invalidation_provider_factory.h" +#include "ios/chrome/browser/invalidation/ios_chrome_deprecated_profile_invalidation_provider_factory.h" #include <memory> #include <utility> @@ -37,20 +37,21 @@ // static invalidation::ProfileInvalidationProvider* -IOSChromeProfileInvalidationProviderFactory::GetForBrowserState( +IOSChromeDeprecatedProfileInvalidationProviderFactory::GetForBrowserState( ios::ChromeBrowserState* browser_state) { return static_cast<ProfileInvalidationProvider*>( GetInstance()->GetServiceForBrowserState(browser_state, true)); } // static -IOSChromeProfileInvalidationProviderFactory* -IOSChromeProfileInvalidationProviderFactory::GetInstance() { - return base::Singleton<IOSChromeProfileInvalidationProviderFactory>::get(); +IOSChromeDeprecatedProfileInvalidationProviderFactory* +IOSChromeDeprecatedProfileInvalidationProviderFactory::GetInstance() { + return base::Singleton< + IOSChromeDeprecatedProfileInvalidationProviderFactory>::get(); } -IOSChromeProfileInvalidationProviderFactory:: - IOSChromeProfileInvalidationProviderFactory() +IOSChromeDeprecatedProfileInvalidationProviderFactory:: + IOSChromeDeprecatedProfileInvalidationProviderFactory() : BrowserStateKeyedServiceFactory( "InvalidationService", BrowserStateDependencyManager::GetInstance()) { @@ -58,11 +59,11 @@ DependsOn(IOSChromeGCMProfileServiceFactory::GetInstance()); } -IOSChromeProfileInvalidationProviderFactory:: - ~IOSChromeProfileInvalidationProviderFactory() {} +IOSChromeDeprecatedProfileInvalidationProviderFactory:: + ~IOSChromeDeprecatedProfileInvalidationProviderFactory() {} std::unique_ptr<KeyedService> -IOSChromeProfileInvalidationProviderFactory::BuildServiceInstanceFor( +IOSChromeDeprecatedProfileInvalidationProviderFactory::BuildServiceInstanceFor( web::BrowserState* context) const { ios::ChromeBrowserState* browser_state = ios::ChromeBrowserState::FromBrowserState(context); @@ -88,8 +89,8 @@ std::move(service), std::move(identity_provider)); } -void IOSChromeProfileInvalidationProviderFactory::RegisterBrowserStatePrefs( - user_prefs::PrefRegistrySyncable* registry) { +void IOSChromeDeprecatedProfileInvalidationProviderFactory:: + RegisterBrowserStatePrefs(user_prefs::PrefRegistrySyncable* registry) { ProfileInvalidationProvider::RegisterProfilePrefs(registry); InvalidatorStorage::RegisterProfilePrefs(registry); }
diff --git a/ios/chrome/browser/ios_chrome_flag_descriptions.cc b/ios/chrome/browser/ios_chrome_flag_descriptions.cc index 8723dbf0..0611e54 100644 --- a/ios/chrome/browser/ios_chrome_flag_descriptions.cc +++ b/ios/chrome/browser/ios_chrome_flag_descriptions.cc
@@ -163,6 +163,11 @@ const char kExternalSearchName[] = "External Search"; const char kExternalSearchDescription[] = "Enable support for External Search."; +const char kFCMInvalidationsName[] = + "Enable invalidations delivery via new FCM based protocol"; +const char kFCMInvalidationsDescription[] = + "Use the new FCM-based protocol for deliveling invalidations"; + const char kFullscreenViewportAdjustmentExperimentName[] = "Fullscreen Viewport Adjustment Mode"; const char kFullscreenViewportAdjustmentExperimentDescription[] =
diff --git a/ios/chrome/browser/ios_chrome_flag_descriptions.h b/ios/chrome/browser/ios_chrome_flag_descriptions.h index 2e40e59..3c646f12b 100644 --- a/ios/chrome/browser/ios_chrome_flag_descriptions.h +++ b/ios/chrome/browser/ios_chrome_flag_descriptions.h
@@ -135,6 +135,10 @@ extern const char kExternalSearchName[]; extern const char kExternalSearchDescription[]; +// Title and description for the flag to enable invaliations delivery via FCM. +extern const char kFCMInvalidationsName[]; +extern const char kFCMInvalidationsDescription[]; + // Title and description for the command line switch used to determine the // active fullscreen viewport adjustment mode. extern const char kFullscreenViewportAdjustmentExperimentName[];
diff --git a/ios/chrome/browser/passwords/BUILD.gn b/ios/chrome/browser/passwords/BUILD.gn index 4e75b34..6b60454 100644 --- a/ios/chrome/browser/passwords/BUILD.gn +++ b/ios/chrome/browser/passwords/BUILD.gn
@@ -25,6 +25,8 @@ "ios_chrome_save_password_infobar_delegate.mm", "ios_chrome_update_password_infobar_delegate.h", "ios_chrome_update_password_infobar_delegate.mm", + "ios_password_infobar_controller.h", + "ios_password_infobar_controller.mm", "js_credential_manager.h", "js_credential_manager.mm", "notify_auto_signin_view_controller.h",
diff --git a/ios/chrome/browser/passwords/ios_chrome_password_manager_infobar_delegate.h b/ios/chrome/browser/passwords/ios_chrome_password_manager_infobar_delegate.h index 3931787..8d6c0e0a 100644 --- a/ios/chrome/browser/passwords/ios_chrome_password_manager_infobar_delegate.h +++ b/ios/chrome/browser/passwords/ios_chrome_password_manager_infobar_delegate.h
@@ -19,12 +19,15 @@ // Base class for password manager infobar delegates, e.g. // IOSChromeSavePasswordInfoBarDelegate and -// IOSChromeUpdatePasswordInfoBarDelegate. Provides link text and action for -// smart lock. +// IOSChromeUpdatePasswordInfoBarDelegate. class IOSChromePasswordManagerInfoBarDelegate : public ConfirmInfoBarDelegate { public: ~IOSChromePasswordManagerInfoBarDelegate() override; + // Getter for the message displayed in addition to the title. If no message + // was set, this returns an empty string. + base::string16 GetDetailsMessageText() const; + protected: IOSChromePasswordManagerInfoBarDelegate( bool is_sync_user,
diff --git a/ios/chrome/browser/passwords/ios_chrome_password_manager_infobar_delegate.mm b/ios/chrome/browser/passwords/ios_chrome_password_manager_infobar_delegate.mm index 2c39a57..db638df 100644 --- a/ios/chrome/browser/passwords/ios_chrome_password_manager_infobar_delegate.mm +++ b/ios/chrome/browser/passwords/ios_chrome_password_manager_infobar_delegate.mm
@@ -8,7 +8,9 @@ #include "base/strings/string16.h" #include "components/password_manager/core/browser/password_form_manager_for_ui.h" +#include "ios/chrome/grit/ios_strings.h" #include "ios/chrome/grit/ios_theme_resources.h" +#include "ui/base/l10n/l10n_util.h" #if !defined(__has_feature) || !__has_feature(objc_arc) #error "This file requires ARC support." @@ -26,6 +28,12 @@ infobar_response_(password_manager::metrics_util::NO_DIRECT_INTERACTION), is_sync_user_(is_sync_user) {} +base::string16 IOSChromePasswordManagerInfoBarDelegate::GetDetailsMessageText() + const { + return is_sync_user_ ? l10n_util::GetStringUTF16(IDS_SAVE_PASSWORD_FOOTER) + : base::string16(); +} + int IOSChromePasswordManagerInfoBarDelegate::GetIconId() const { return IDR_IOS_INFOBAR_SAVE_PASSWORD; };
diff --git a/ios/chrome/browser/passwords/ios_chrome_save_password_infobar_delegate.mm b/ios/chrome/browser/passwords/ios_chrome_save_password_infobar_delegate.mm index af5e4f0..d2ad368 100644 --- a/ios/chrome/browser/passwords/ios_chrome_save_password_infobar_delegate.mm +++ b/ios/chrome/browser/passwords/ios_chrome_save_password_infobar_delegate.mm
@@ -13,6 +13,8 @@ #include "components/password_manager/core/browser/password_form_metrics_recorder.h" #include "components/password_manager/core/browser/password_manager_constants.h" #include "components/strings/grit/components_strings.h" +#include "ios/chrome/browser/infobars/infobar.h" +#import "ios/chrome/browser/passwords/ios_password_infobar_controller.h" #include "ios/chrome/grit/ios_chromium_strings.h" #include "ios/chrome/grit/ios_strings.h" #include "ui/base/l10n/l10n_util.h" @@ -33,8 +35,11 @@ auto delegate = base::WrapUnique(new IOSChromeSavePasswordInfoBarDelegate( is_sync_user, std::move(form_to_save))); delegate->set_dispatcher(dispatcher); + IOSPasswordInfoBarController* controller = + [[IOSPasswordInfoBarController alloc] + initWithInfoBarDelegate:delegate.get()]; infobar_manager->AddInfoBar( - infobar_manager->CreateConfirmInfoBar(std::move(delegate))); + std::make_unique<InfoBarIOS>(controller, std::move(delegate))); } IOSChromeSavePasswordInfoBarDelegate::~IOSChromeSavePasswordInfoBarDelegate() {
diff --git a/ios/chrome/browser/passwords/ios_chrome_update_password_infobar_delegate.mm b/ios/chrome/browser/passwords/ios_chrome_update_password_infobar_delegate.mm index 65ece545..e7eab4a 100644 --- a/ios/chrome/browser/passwords/ios_chrome_update_password_infobar_delegate.mm +++ b/ios/chrome/browser/passwords/ios_chrome_update_password_infobar_delegate.mm
@@ -42,8 +42,8 @@ [[UpdatePasswordInfoBarController alloc] initWithBaseViewController:baseViewController infoBarDelegate:delegate.get()]; - auto infobar = std::make_unique<InfoBarIOS>(controller, std::move(delegate)); - infobar_manager->AddInfoBar(std::move(infobar)); + infobar_manager->AddInfoBar( + std::make_unique<InfoBarIOS>(controller, std::move(delegate))); } IOSChromeUpdatePasswordInfoBarDelegate::
diff --git a/ios/chrome/browser/passwords/ios_password_infobar_controller.h b/ios/chrome/browser/passwords/ios_password_infobar_controller.h new file mode 100644 index 0000000..2daf092 --- /dev/null +++ b/ios/chrome/browser/passwords/ios_password_infobar_controller.h
@@ -0,0 +1,14 @@ +// 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 IOS_CHROME_BROWSER_PASSWORDS_IOS_PASSWORD_INFOBAR_CONTROLLER_H_ +#define IOS_CHROME_BROWSER_PASSWORDS_IOS_PASSWORD_INFOBAR_CONTROLLER_H_ + +#import "ios/chrome/browser/infobars/confirm_infobar_controller.h" + +@interface IOSPasswordInfoBarController : ConfirmInfoBarController + +@end + +#endif // IOS_CHROME_BROWSER_PASSWORDS_IOS_PASSWORD_INFOBAR_CONTROLLER_H_
diff --git a/ios/chrome/browser/passwords/ios_password_infobar_controller.mm b/ios/chrome/browser/passwords/ios_password_infobar_controller.mm new file mode 100644 index 0000000..7ba3ad3 --- /dev/null +++ b/ios/chrome/browser/passwords/ios_password_infobar_controller.mm
@@ -0,0 +1,31 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#import "ios/chrome/browser/passwords/ios_password_infobar_controller.h" + +#include "base/strings/sys_string_conversions.h" +#import "ios/chrome/browser/infobars/confirm_infobar_controller+protected.h" +#import "ios/chrome/browser/passwords/ios_chrome_password_manager_infobar_delegate.h" +#import "ios/chrome/browser/ui/infobars/confirm_infobar_view.h" + +#if !defined(__has_feature) || !__has_feature(objc_arc) +#error "This file requires ARC support." +#endif + +@implementation IOSPasswordInfoBarController + +- (void)updateInfobarLabel:(ConfirmInfoBarView*)view { + [super updateInfobarLabel:view]; + + auto* delegate = static_cast<IOSChromePasswordManagerInfoBarDelegate*>( + self.infoBarDelegate); + base::string16 message = delegate->GetDetailsMessageText(); + if (message.empty()) + return; + + [view addFooterLabel:base::SysUTF16ToNSString( + delegate->GetDetailsMessageText())]; +} + +@end
diff --git a/ios/chrome/browser/passwords/update_password_infobar_controller.h b/ios/chrome/browser/passwords/update_password_infobar_controller.h index 1845429..acb7d0ae 100644 --- a/ios/chrome/browser/passwords/update_password_infobar_controller.h +++ b/ios/chrome/browser/passwords/update_password_infobar_controller.h
@@ -5,13 +5,13 @@ #ifndef IOS_CHROME_BROWSER_PASSWORDS_UPDATE_PASSWORD_INFOBAR_CONTROLLER_H_ #define IOS_CHROME_BROWSER_PASSWORDS_UPDATE_PASSWORD_INFOBAR_CONTROLLER_H_ -#include "ios/chrome/browser/infobars/confirm_infobar_controller.h" +#import "ios/chrome/browser/passwords/ios_password_infobar_controller.h" class IOSChromeUpdatePasswordInfoBarDelegate; // Controller for the Update Password info bar. Presents an info bar that asks // the user whether they want to update their password. -@interface UpdatePasswordInfoBarController : ConfirmInfoBarController +@interface UpdatePasswordInfoBarController : IOSPasswordInfoBarController - (instancetype)init NS_UNAVAILABLE;
diff --git a/ios/chrome/browser/sync/ios_chrome_sync_client.mm b/ios/chrome/browser/sync/ios_chrome_sync_client.mm index b5c8152..31a056b 100644 --- a/ios/chrome/browser/sync/ios_chrome_sync_client.mm +++ b/ios/chrome/browser/sync/ios_chrome_sync_client.mm
@@ -54,7 +54,7 @@ #include "ios/chrome/browser/dom_distiller/dom_distiller_service_factory.h" #include "ios/chrome/browser/favicon/favicon_service_factory.h" #include "ios/chrome/browser/history/history_service_factory.h" -#include "ios/chrome/browser/invalidation/ios_chrome_profile_invalidation_provider_factory.h" +#include "ios/chrome/browser/invalidation/ios_chrome_deprecated_profile_invalidation_provider_factory.h" #include "ios/chrome/browser/passwords/ios_chrome_password_store_factory.h" #include "ios/chrome/browser/pref_names.h" #include "ios/chrome/browser/reading_list/reading_list_model_factory.h" @@ -193,7 +193,7 @@ invalidation::InvalidationService* IOSChromeSyncClient::GetInvalidationService() { invalidation::ProfileInvalidationProvider* provider = - IOSChromeProfileInvalidationProviderFactory::GetForBrowserState( + IOSChromeDeprecatedProfileInvalidationProviderFactory::GetForBrowserState( browser_state_); if (provider) return provider->GetInvalidationService();
diff --git a/ios/chrome/browser/sync/profile_sync_service_factory.cc b/ios/chrome/browser/sync/profile_sync_service_factory.cc index b11737b..ede0d70 100644 --- a/ios/chrome/browser/sync/profile_sync_service_factory.cc +++ b/ios/chrome/browser/sync/profile_sync_service_factory.cc
@@ -24,7 +24,7 @@ #include "ios/chrome/browser/favicon/favicon_service_factory.h" #include "ios/chrome/browser/gcm/ios_chrome_gcm_profile_service_factory.h" #include "ios/chrome/browser/history/history_service_factory.h" -#include "ios/chrome/browser/invalidation/ios_chrome_profile_invalidation_provider_factory.h" +#include "ios/chrome/browser/invalidation/ios_chrome_deprecated_profile_invalidation_provider_factory.h" #include "ios/chrome/browser/passwords/ios_chrome_password_store_factory.h" #include "ios/chrome/browser/reading_list/reading_list_model_factory.h" #include "ios/chrome/browser/search_engines/template_url_service_factory.h" @@ -111,7 +111,8 @@ DependsOn(IdentityManagerFactory::GetInstance()); DependsOn(IOSChromeGCMProfileServiceFactory::GetInstance()); DependsOn(IOSChromePasswordStoreFactory::GetInstance()); - DependsOn(IOSChromeProfileInvalidationProviderFactory::GetInstance()); + DependsOn( + IOSChromeDeprecatedProfileInvalidationProviderFactory::GetInstance()); DependsOn(ModelTypeStoreServiceFactory::GetInstance()); DependsOn(ReadingListModelFactory::GetInstance()); DependsOn(SessionSyncServiceFactory::GetInstance());
diff --git a/ios/chrome/browser/ui/app_launcher/app_launcher_coordinator_unittest.mm b/ios/chrome/browser/ui/app_launcher/app_launcher_coordinator_unittest.mm index 6f5e8d1..2f66cca6 100644 --- a/ios/chrome/browser/ui/app_launcher/app_launcher_coordinator_unittest.mm +++ b/ios/chrome/browser/ui/app_launcher/app_launcher_coordinator_unittest.mm
@@ -43,22 +43,6 @@ id application_ = nil; }; -// Tests that an empty URL does not prompt user and does not launch application. -TEST_F(AppLauncherCoordinatorTest, EmptyUrl) { - BOOL app_exists = [coordinator_ appLauncherTabHelper:nullptr - launchAppWithURL:GURL::EmptyGURL() - linkTransition:NO]; - EXPECT_FALSE(app_exists); - EXPECT_EQ(nil, base_view_controller_.presentedViewController); -} - -// Tests that an invalid URL does not launch application. -TEST_F(AppLauncherCoordinatorTest, InvalidUrl) { - BOOL app_exists = [coordinator_ appLauncherTabHelper:nullptr - launchAppWithURL:GURL("invalid") - linkTransition:NO]; - EXPECT_FALSE(app_exists); -} // Tests that an itunes URL shows an alert. TEST_F(AppLauncherCoordinatorTest, ItmsUrlShowsAlert) {
diff --git a/ios/chrome/browser/ui/autofill/save_card_infobar_view.mm b/ios/chrome/browser/ui/autofill/save_card_infobar_view.mm index 02cced2d..6d18fe8 100644 --- a/ios/chrome/browser/ui/autofill/save_card_infobar_view.mm +++ b/ios/chrome/browser/ui/autofill/save_card_infobar_view.mm
@@ -155,33 +155,23 @@ } - (void)layoutSubviews { + // Set a bottom margin equal to the height of the secondary toolbar, if any. + // Deduct the bottom safe area inset as it is already included in the height + // of the secondary toolbar. + // TODO(crbug.com/894449): This won't update the infobar's position after the + // secondary toolbar reappears. Consider adding a constraint to the + // |layoutGuide| in |didMoveToSuperview|. + NamedGuide* layoutGuide = + [NamedGuide guideWithName:kSecondaryToolbarGuide view:self]; + self.footerViewBottomAnchorConstraint.constant = + layoutGuide.layoutFrame.size.height; + [super layoutSubviews]; [self.sizingDelegate didSetInfoBarTargetHeight:CGRectGetHeight(self.frame)]; } -- (void)setFrame:(CGRect)frame { - [super setFrame:frame]; - - // Updates layout of subviews immediately, if layout updates are pending, - // rather than waiting for the next update cycle. Otherwise, the layout breaks - // on iPhone X. - // TODO(crbug.com/862688): Investigate why this is happening. - [self layoutIfNeeded]; -} - - (CGSize)sizeThatFits:(CGSize)size { - // Set a bottom margin equal to the height of the secondary toolbar, if any. - // Deduct the bottom safe area inset as it is already included in the height - // of the secondary toolbar. - NamedGuide* layoutGuide = - [NamedGuide guideWithName:kSecondaryToolbarGuide view:self]; - CGFloat bottomSafeAreaInset = SafeAreaInsetsForView(self).bottom; - self.footerViewBottomAnchorConstraint.constant = - layoutGuide.constrained - ? layoutGuide.layoutFrame.size.height - bottomSafeAreaInset - : 0; - CGSize computedSize = [self systemLayoutSizeFittingSize:size]; return CGSizeMake(size.width, computedSize.height); } @@ -326,8 +316,8 @@ UIEdgeInsetsMake(kButtonsTopPadding, kPadding, kPadding, kPadding); [self addSubview:footerView]; - self.footerViewBottomAnchorConstraint = [safeAreaLayoutGuide.bottomAnchor - constraintEqualToAnchor:footerView.bottomAnchor]; + self.footerViewBottomAnchorConstraint = + [self.bottomAnchor constraintEqualToAnchor:footerView.bottomAnchor]; [NSLayoutConstraint activateConstraints:@[ [safeAreaLayoutGuide.leadingAnchor constraintEqualToAnchor:footerView.leadingAnchor],
diff --git a/ios/chrome/browser/ui/browser_view_controller.mm b/ios/chrome/browser/ui/browser_view_controller.mm index e77d34b0..e5f854a8 100644 --- a/ios/chrome/browser/ui/browser_view_controller.mm +++ b/ios/chrome/browser/ui/browser_view_controller.mm
@@ -243,8 +243,6 @@ #include "ios/public/provider/chrome/browser/chrome_browser_provider.h" #include "ios/public/provider/chrome/browser/ui/app_rating_prompt.h" #include "ios/public/provider/chrome/browser/ui/default_ios_web_view_factory.h" -#import "ios/public/provider/chrome/browser/voice/voice_search_bar.h" -#import "ios/public/provider/chrome/browser/voice/voice_search_bar_owner.h" #include "ios/public/provider/chrome/browser/voice/voice_search_controller.h" #include "ios/public/provider/chrome/browser/voice/voice_search_provider.h" #import "ios/third_party/material_components_ios/src/components/Snackbar/src/MaterialSnackbar.h" @@ -327,8 +325,6 @@ // Duration of the toolbar animation. const NSTimeInterval kLegacyFullscreenControllerToolbarAnimationDuration = 0.3; -const CGFloat kVoiceSearchBarHeight = 59.0; - // Dimensions to use when downsizing an image for search-by-image. const CGFloat kSearchByImageMaxImageArea = 90000.0; const CGFloat kSearchByImageMaxImageWidth = 600.0; @@ -451,8 +447,6 @@ ToolbarHeightProviderForFullscreen, UIGestureRecognizerDelegate, UpgradeCenterClient, - VoiceSearchBarDelegate, - VoiceSearchBarOwner, WebStatePrinter> { // The dependency factory passed on initialization. Used to vend objects used // by the BVC. @@ -538,11 +532,6 @@ // Bridge class to deliver container change notifications to BVC. std::unique_ptr<InfoBarContainerDelegateIOS> _infoBarContainerDelegate; - // TODO(crbug.com/800266): Remove this object. - // Voice search bar at the bottom of the view overlayed on |contentArea| - // when displaying voice search results. - UIView<VoiceSearchBar>* _voiceSearchBar; - // The image fetcher used to save images and perform image-based searches. std::unique_ptr<image_fetcher::IOSImageDataFetcherWrapper> _imageFetcher; @@ -656,8 +645,6 @@ // Whether BVC prefers to hide the status bar. This value is used to determine // the response from the |prefersStatusBarHidden| method. @property(nonatomic, assign) BOOL hideStatusBar; -// Whether the VoiceSearchBar should be displayed. -@property(nonatomic, readonly) BOOL shouldShowVoiceSearchBar; // Coordinator for displaying a modal overlay with activity indicator to prevent // the user from interacting with the browser view. @property(nonatomic, strong) @@ -880,8 +867,6 @@ // ------------ // Lazily instantiates |_voiceSearchController|. - (void)ensureVoiceSearchControllerCreated; -// Shows/hides the voice search bar. -- (void)updateVoiceSearchBarVisibilityAnimated:(BOOL)animated; // Reading List // ------------ @@ -1277,17 +1262,6 @@ return _inNewTabAnimation; } -- (BOOL)shouldShowVoiceSearchBar { - // On iPads, the voice search bar should only be shown for regular horizontal - // size class configurations. It should always be shown for voice search - // results Tabs on iPhones, including configurations with regular horizontal - // size classes (i.e. landscape iPhone 6 Plus). - BOOL compactWidth = self.traitCollection.horizontalSizeClass == - UIUserInterfaceSizeClassCompact; - return self.tabModel.currentTab.isVoiceSearchResultsTab && - (![self canShowTabStrip] || compactWidth); -} - - (void)setHideStatusBar:(BOOL)hideStatusBar { if (_hideStatusBar == hideStatusBar) return; @@ -1522,7 +1496,6 @@ [self ensureVoiceSearchControllerCreated]; // Present voice search. - [_voiceSearchBar prepareToPresentVoiceSearch]; _voiceSearchController->StartRecognition(self, [_model currentTab]); [self.dispatcher cancelOmniboxEdit]; } @@ -1852,8 +1825,6 @@ // view controller). [self.presentedViewController traitCollectionDidChange:previousTraitCollection]; - // Update voice search bar visibility. - [self updateVoiceSearchBarVisibilityAnimated:NO]; // Change the height of the secondary toolbar to show/hide it. self.secondaryToolbarHeightConstraint.constant = [self secondaryToolbarHeightWithInset]; @@ -3045,22 +3016,6 @@ } } -- (void)updateVoiceSearchBarVisibilityAnimated:(BOOL)animated { - // Voice search bar exists and is shown/hidden. - BOOL show = self.shouldShowVoiceSearchBar; - if (_voiceSearchBar && _voiceSearchBar.hidden != show) - return; - - // Voice search bar doesn't exist and thus is not visible. - if (!_voiceSearchBar && !show) - return; - - if (animated) - [_voiceSearchBar animateToBecomeVisible:show]; - else - _voiceSearchBar.hidden = !show; -} - #pragma mark - Private Methods: Reading List - (void)addToReadingListURL:(const GURL&)URL title:(NSString*)title { @@ -3153,14 +3108,6 @@ return @[]; NSMutableArray* overlays = [NSMutableArray array]; - UIView* voiceSearchView = [self voiceSearchOverlayViewForTab:tab]; - if (voiceSearchView) { - CGFloat voiceSearchYOffset = [self voiceSearchOverlayYOffsetForTab:tab]; - SnapshotOverlay* voiceSearchOverlay = - [[SnapshotOverlay alloc] initWithView:voiceSearchView - yOffset:voiceSearchYOffset]; - [overlays addObject:voiceSearchOverlay]; - } UIView* infoBarView = [self infoBarOverlayViewForTab:tab]; if (infoBarView) { CGFloat infoBarYOffset = [self infoBarOverlayYOffsetForTab:tab]; @@ -3249,27 +3196,16 @@ CGRectGetHeight(_downloadManagerCoordinator.viewController.view.frame); } -// Provides a view that encompasses the voice search bar if it's displayed or -// nil if the voice search bar isn't displayed. -- (UIView*)voiceSearchOverlayViewForTab:(Tab*)tab { - Tab* currentTab = [_model currentTab]; - if (tab && tab == currentTab && tab.isVoiceSearchResultsTab && - _voiceSearchBar && ![_voiceSearchBar isHidden]) { - return _voiceSearchBar; - } - return nil; -} - // Returns a vertical voice search bar offset relative to the tab content. - (CGFloat)voiceSearchOverlayYOffsetForTab:(Tab*)tab { - if (tab != [_model currentTab] || [_voiceSearchBar isHidden]) { + if (tab != [_model currentTab]) { // There is no UI representation for non-current tabs or there is // no visible voice search. Return offset outside of tab. return CGRectGetMaxY(self.view.frame); } else { // The voice search bar on iPhone is displayed at the bottom of a tab. CGRect visibleFrame = [self visibleFrameForTab:_model.currentTab]; - return CGRectGetMaxY(visibleFrame) - kVoiceSearchBarHeight; + return CGRectGetMaxY(visibleFrame); } } @@ -4315,14 +4251,7 @@ Tab* currentTab = [_model currentTab]; DCHECK(currentTab); - BOOL wasVoiceSearchTab = currentTab.isVoiceSearchResultsTab; currentTab.navigationManager->LoadURLWithParams(params); - // When a Tab becomes a voice search Tab, the voice search bar doesn't need - // to be animated on screen because the transition animator will handle the - // animations. When a Tab stops being a voice search Tab, the voice search - // bar should be animated away. - if (currentTab.isVoiceSearchResultsTab != wasVoiceSearchTab) - [self updateVoiceSearchBarVisibilityAnimated:wasVoiceSearchTab]; } - (void)loadJavaScriptFromLocationBar:(NSString*)script { @@ -4852,8 +4781,6 @@ // no language selector presented. [_languageSelectionCoordinator dismissLanguageSelector]; } - [self updateVoiceSearchBarVisibilityAnimated:NO]; - self.currentWebState->GetWebViewProxy().scrollViewProxy.clipsToBounds = NO; [_paymentRequestManager setActiveWebState:newTab.webState]; @@ -4878,12 +4805,6 @@ } } -- (void)tabModel:(TabModel*)model didStartLoadingTab:(Tab*)tab { - if (tab == [_model currentTab]) { - [self updateVoiceSearchBarVisibilityAnimated:NO]; - } -} - - (void)tabModel:(TabModel*)model didFinishLoadingTab:(Tab*)tab success:(BOOL)success { @@ -5232,7 +5153,6 @@ self.contentArea.frame = sideSwipeView.frame; [self.view insertSubview:self.contentArea aboveSubview:_fakeStatusBarView]; - [self updateVoiceSearchBarVisibilityAnimated:NO]; [self updateToolbar]; // Reset horizontal stack view. @@ -5264,7 +5184,6 @@ - (void)updateAccessoryViewsForSideSwipeWithVisibility:(BOOL)visible { if (visible) { - [self updateVoiceSearchBarVisibilityAnimated:NO]; [self updateToolbar]; [_infoBarContainer->view() setHidden:NO]; } else { @@ -5272,7 +5191,6 @@ // for welcome page. [self hideFindBarWithAnimation:NO]; [_infoBarContainer->view() setHidden:YES]; - [_voiceSearchBar setHidden:YES]; } } @@ -5389,45 +5307,9 @@ _rateThisAppDialog = nil; } -#pragma mark - VoiceSearchBarOwner - -- (id<VoiceSearchBar>)voiceSearchBar { - return _voiceSearchBar; -} - -#pragma mark - VoiceSearchBarDelegate - -- (BOOL)isTTSEnabledForVoiceSearchBar:(id<VoiceSearchBar>)voiceSearchBar { - DCHECK_EQ(_voiceSearchBar, voiceSearchBar); - [self ensureVoiceSearchControllerCreated]; - return _voiceSearchController->IsTextToSpeechEnabled() && - _voiceSearchController->IsTextToSpeechSupported(); -} - -- (void)voiceSearchBarDidUpdateButtonState:(id<VoiceSearchBar>)voiceSearchBar { - DCHECK_EQ(_voiceSearchBar, voiceSearchBar); - SnapshotTabHelper::FromWebState(self.tabModel.currentTab.webState) - ->UpdateSnapshot(/*with_overlays=*/true, /*visible_frame_only=*/true); -} - #pragma mark - LogoAnimationControllerOwnerOwner (Public) - (id<LogoAnimationControllerOwner>)logoAnimationControllerOwner { - return [self currentLogoAnimationControllerOwner]; -} - -#pragma mark - LogoAnimationControllerOwnerOwner helpers - -// The LogoAnimationControllerOwner to be used for the next logo transition -// animation. -- (id<LogoAnimationControllerOwner>)currentLogoAnimationControllerOwner { - Protocol* ownerProtocol = @protocol(LogoAnimationControllerOwner); - if ([_voiceSearchBar conformsToProtocol:ownerProtocol] && - self.shouldShowVoiceSearchBar) { - // Use |_voiceSearchBar| for VoiceSearch results tab and dismissal - // animations. - return static_cast<id<LogoAnimationControllerOwner>>(_voiceSearchBar); - } id currentNativeController = [self nativeControllerForTab:self.tabModel.currentTab]; Protocol* possibleOwnerProtocol =
diff --git a/ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_cell.h b/ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_cell.h index d2212f06..3fc5d52 100644 --- a/ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_cell.h +++ b/ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_cell.h
@@ -29,7 +29,7 @@ // Returns the height needed by a cell contained in |width| and containing the // listed informations. + (CGFloat)heightForWidth:(CGFloat)width - withImage:(BOOL)hasImage + withImageAvailable:(BOOL)hasImage title:(NSString*)title publisherName:(NSString*)publisherName publicationDate:(NSString*)publicationDate;
diff --git a/ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_cell.mm b/ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_cell.mm index f19f6b7f..1f434a7 100644 --- a/ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_cell.mm +++ b/ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_cell.mm
@@ -5,6 +5,7 @@ #import "ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_cell.h" #include "ios/chrome/browser/ui/ui_util.h" +#import "ios/chrome/browser/ui/uikit_ui_util.h" #import "ios/chrome/browser/ui/util/i18n_string.h" #import "ios/chrome/common/favicon/favicon_view.h" #import "ios/chrome/common/ui_util/constraints_ui_util.h" @@ -48,8 +49,20 @@ @property(nonatomic, strong) UIImageView* contentImageView; // Constraint for the size of the image. @property(nonatomic, strong) NSLayoutConstraint* imageSizeConstraint; -// Constraint for the distance between the texts and the image. -@property(nonatomic, strong) NSLayoutConstraint* imageTitleSpacing; +// Constraint for the horizontal distance between the texts and the image +// (standard content size). +@property(nonatomic, strong) NSLayoutConstraint* imageTitleHorizontalSpacing; +// Constraint for the vertical distance between the texts and the image +// (accessibility content size). +@property(nonatomic, strong) NSLayoutConstraint* imageTitleVerticalSpacing; + +// When they are activated, the image is on the leading side of the text. +// They conflict with the accessibilityConstraints. +@property(nonatomic, strong) NSArray<NSLayoutConstraint*>* standardConstraints; +// When they are activated, the image is above the text. The text is taking the +// full width. They conflict with the standardConstraints. +@property(nonatomic, strong) + NSArray<NSLayoutConstraint*>* accessibilityConstraints; // Applies the constraints on the elements. Called in the init. - (void)applyConstraints; @@ -65,7 +78,6 @@ @synthesize contentImageView = _contentImageView; @synthesize faviconView = _faviconView; @synthesize imageSizeConstraint = _imageSizeConstraint; -@synthesize imageTitleSpacing = _imageTitleSpacing; @synthesize displayImage = _displayImage; - (instancetype)initWithFrame:(CGRect)frame { @@ -152,11 +164,13 @@ - (void)setDisplayImage:(BOOL)displayImage { if (displayImage) { - self.imageTitleSpacing.constant = kStandardSpacing; + self.imageTitleHorizontalSpacing.constant = kStandardSpacing; + self.imageTitleVerticalSpacing.constant = kStandardSpacing; self.imageSizeConstraint.constant = kImageSize; self.imageContainer.hidden = NO; } else { - self.imageTitleSpacing.constant = 0; + self.imageTitleHorizontalSpacing.constant = 0; + self.imageTitleVerticalSpacing.constant = 0; self.imageSizeConstraint.constant = 0; self.imageContainer.hidden = YES; } @@ -164,31 +178,31 @@ } + (CGFloat)heightForWidth:(CGFloat)width - withImage:(BOOL)hasImage + withImageAvailable:(BOOL)hasImage title:(NSString*)title publisherName:(NSString*)publisherName publicationDate:(NSString*)publicationDate { - UILabel* titleLabel = [[UILabel alloc] init]; - [self configureTitleLabel:titleLabel]; - titleLabel.text = title; + UILabel* titleLabel = [[UILabel alloc] init]; + [self configureTitleLabel:titleLabel]; + titleLabel.text = title; - UILabel* additionalInfoLabel = [[UILabel alloc] init]; - additionalInfoLabel.font = [self additionalInformationFont]; - additionalInfoLabel.text = - [self stringForPublisher:publisherName date:publicationDate]; + UILabel* additionalInfoLabel = [[UILabel alloc] init]; + additionalInfoLabel.font = [self additionalInformationFont]; + additionalInfoLabel.text = + [self stringForPublisher:publisherName date:publicationDate]; - CGSize sizeForLabels = - CGSizeMake(width - [self labelMarginWithImage:hasImage], 500); + CGSize sizeForLabels = + CGSizeMake(width - [self labelHorizontalMarginsWithImage:hasImage], 500); - CGFloat minimalHeight = kImageSize + kStandardSpacing; + CGFloat minimalHeight = kImageSize + kStandardSpacing; - CGFloat labelHeight = kStandardSpacing; - labelHeight += [titleLabel sizeThatFits:sizeForLabels].height; - labelHeight += kSmallSpacing; - CGFloat additionalInfoHeight = - [additionalInfoLabel sizeThatFits:sizeForLabels].height; - labelHeight += MAX(additionalInfoHeight, kFaviconSize); - return MAX(minimalHeight, labelHeight); + CGFloat labelHeight = [titleLabel sizeThatFits:sizeForLabels].height; + labelHeight += [self labelVerticalMarginsWithImage:hasImage]; + labelHeight += kSmallSpacing; + CGFloat additionalInfoHeight = + [additionalInfoLabel sizeThatFits:sizeForLabels].height; + labelHeight += MAX(additionalInfoHeight, kFaviconSize); + return MAX(minimalHeight, labelHeight); } #pragma mark - UICollectionViewCell @@ -203,8 +217,24 @@ - (void)traitCollectionDidChange:(UITraitCollection*)previousTraitCollection { [super traitCollectionDidChange:previousTraitCollection]; - if (self.traitCollection.preferredContentSizeCategory != - previousTraitCollection.preferredContentSizeCategory) { + UIContentSizeCategory currentCategory = + self.traitCollection.preferredContentSizeCategory; + UIContentSizeCategory previousCategory = + previousTraitCollection.preferredContentSizeCategory; + + BOOL isCurrentCategoryAccessibility = + ContentSizeCategoryIsAccessibilityCategory(currentCategory); + if (isCurrentCategoryAccessibility != + ContentSizeCategoryIsAccessibilityCategory(previousCategory)) { + if (isCurrentCategoryAccessibility) { + [NSLayoutConstraint deactivateConstraints:self.standardConstraints]; + [NSLayoutConstraint activateConstraints:self.accessibilityConstraints]; + } else { + [NSLayoutConstraint deactivateConstraints:self.accessibilityConstraints]; + [NSLayoutConstraint activateConstraints:self.standardConstraints]; + } + } + if (currentCategory != previousCategory) { [[self class] configureTitleLabel:_titleLabel]; _additionalInformationLabel.font = [[self class] additionalInformationFont]; } @@ -220,7 +250,8 @@ CGFloat parentWidth = CGRectGetWidth(self.contentView.bounds); self.titleLabel.preferredMaxLayoutWidth = - parentWidth - [[self class] labelMarginWithImage:self.displayImage]; + parentWidth - + [[self class] labelHorizontalMarginsWithImage:self.displayImage]; self.additionalInformationLabel.preferredMaxLayoutWidth = parentWidth - kFaviconSize - kSmallSpacing - 2 * kStandardSpacing; @@ -234,9 +265,6 @@ - (void)applyConstraints { _imageSizeConstraint = [_imageContainer.heightAnchor constraintEqualToConstant:kImageSize]; - _imageTitleSpacing = [_titleLabel.leadingAnchor - constraintEqualToAnchor:_imageContainer.trailingAnchor - constant:kStandardSpacing]; [NSLayoutConstraint activateConstraints:@[ // Image. @@ -245,10 +273,6 @@ constraintLessThanOrEqualToAnchor:_faviconView.bottomAnchor], [_imageContainer.widthAnchor constraintEqualToAnchor:_imageContainer.heightAnchor], - [_imageContainer.topAnchor constraintEqualToAnchor:_titleLabel.topAnchor], - - // Text. - _imageTitleSpacing, // Additional Information. [_additionalInformationLabel.trailingAnchor @@ -277,11 +301,36 @@ AddSameConstraints(_contentImageView, _imageContainer); + _imageTitleHorizontalSpacing = [_titleLabel.leadingAnchor + constraintEqualToAnchor:_imageContainer.trailingAnchor + constant:kStandardSpacing]; + _imageTitleVerticalSpacing = [_titleLabel.topAnchor + constraintEqualToAnchor:_imageContainer.bottomAnchor + constant:kStandardSpacing]; + _standardConstraints = @[ + _imageTitleHorizontalSpacing, + [_titleLabel.topAnchor constraintEqualToAnchor:_imageContainer.topAnchor], + ]; + + _accessibilityConstraints = @[ + [_titleLabel.leadingAnchor + constraintEqualToAnchor:self.contentView.leadingAnchor + constant:kStandardSpacing], + _imageTitleVerticalSpacing, + ]; + + if (ContentSizeCategoryIsAccessibilityCategory( + self.traitCollection.preferredContentSizeCategory)) { + [NSLayoutConstraint activateConstraints:self.accessibilityConstraints]; + } else { + [NSLayoutConstraint activateConstraints:self.standardConstraints]; + } + ApplyVisualConstraintsWithMetrics( @[ @"H:[title]-(space)-|", @"H:|-(space)-[image]", - @"V:|-(space)-[title]", + @"V:|-(space)-[image]", @"H:[favicon]-(small)-[additional]", ], @{ @@ -313,12 +362,32 @@ return [UIFont preferredFontForTextStyle:UIFontTextStyleCaption2]; } -// Returns the margin for the labels, depending if the cell |hasImage|. -+ (CGFloat)labelMarginWithImage:(BOOL)hasImage { - CGFloat offset = hasImage ? kImageSize + kStandardSpacing : 0; +// Returns the horizontal margin for the labels, depending if the cell +// |hasImage| and the content size category. ++ (CGFloat)labelHorizontalMarginsWithImage:(BOOL)hasImage { + BOOL isCurrentCategoryAccessibility = + ContentSizeCategoryIsAccessibilityCategory( + [UIApplication sharedApplication].preferredContentSizeCategory); + + CGFloat offset = (hasImage && !isCurrentCategoryAccessibility) + ? kImageSize + kStandardSpacing + : 0; return 2 * kStandardSpacing + offset; } +// Returns the vertical margin for the labels, depending if the cell |hasImage| +// and the content size category. ++ (CGFloat)labelVerticalMarginsWithImage:(BOOL)hasImage { + BOOL isCurrentCategoryAccessibility = + ContentSizeCategoryIsAccessibilityCategory( + [UIApplication sharedApplication].preferredContentSizeCategory); + + CGFloat offset = (hasImage && isCurrentCategoryAccessibility) + ? kImageSize + kStandardSpacing + : 0; + return kStandardSpacing + offset; +} + // Returns the attributed string to be displayed. + (NSString*)stringForPublisher:(NSString*)publisherName date:(NSString*)date { return AdjustStringForLocaleDirection(
diff --git a/ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_item.mm b/ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_item.mm index 89223ea..90f4454a 100644 --- a/ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_item.mm +++ b/ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_item.mm
@@ -93,7 +93,7 @@ - (CGFloat)cellHeightForWidth:(CGFloat)width { return [self.cellClass heightForWidth:width - withImage:self.hasImage + withImageAvailable:self.hasImage title:self.title publisherName:self.publisher publicationDate:[self relativeDate]];
diff --git a/ios/chrome/browser/ui/infobars/confirm_infobar_view.h b/ios/chrome/browser/ui/infobars/confirm_infobar_view.h index ae6d1850..5c19fce 100644 --- a/ios/chrome/browser/ui/infobars/confirm_infobar_view.h +++ b/ios/chrome/browser/ui/infobars/confirm_infobar_view.h
@@ -60,6 +60,9 @@ target:(id)target action:(SEL)action; +// Adds to the infobar a footer label below the title. +- (void)addFooterLabel:(NSString*)label; + @end #endif // IOS_CHROME_BROWSER_UI_INFOBARS_CONFIRM_INFOBAR_VIEW_H_
diff --git a/ios/chrome/browser/ui/infobars/confirm_infobar_view.mm b/ios/chrome/browser/ui/infobars/confirm_infobar_view.mm index 6262707..d620558c 100644 --- a/ios/chrome/browser/ui/infobars/confirm_infobar_view.mm +++ b/ios/chrome/browser/ui/infobars/confirm_infobar_view.mm
@@ -113,11 +113,79 @@ } // namespace -// UIView containing a switch and a label. -@interface SwitchView : BidiContainerView +// UIView containing a label. +@interface InfobarFooterView : BidiContainerView + +@property(nonatomic, readonly) UILabel* label; +@property(nonatomic) CGFloat preferredLabelWidth; // Initialize the view's label with |labelText|. -- (id)initWithLabel:(NSString*)labelText isOn:(BOOL)isOn; +- (instancetype)initWithText:(NSString*)labelText NS_DESIGNATED_INITIALIZER; + +- (instancetype)initWithFrame:(CGRect)frame NS_UNAVAILABLE; +- (instancetype)initWithCoder:(NSCoder*)aDecoder NS_UNAVAILABLE; + +// Returns the height taken by the view constrained by a width of |width|. +// If |layout| is yes, it sets the frame of the view to fit |width|. +- (CGFloat)heightRequiredForFooterWithWidth:(CGFloat)width layout:(BOOL)layout; + +// Returns the preferred width. A smaller width requires eliding the text. +- (CGFloat)preferredWidth; +@end + +@implementation InfobarFooterView + +- (instancetype)initWithText:(NSString*)labelText { + // Creates label. + UILabel* label = [[UILabel alloc] initWithFrame:CGRectZero]; + label.textAlignment = NSTextAlignmentNatural; + label.font = InfoBarSwitchLabelFont(); + label.text = labelText; + label.textColor = [UIColor darkGrayColor]; + label.backgroundColor = [UIColor clearColor]; + label.lineBreakMode = NSLineBreakByWordWrapping; + label.numberOfLines = 0; + label.adjustsFontSizeToFitWidth = NO; + [label sizeToFit]; + + self = [super initWithFrame:label.frame]; + if (!self) + return nil; + _label = label; + _preferredLabelWidth = CGRectGetMaxX(_label.frame); + [self addSubview:_label]; + return self; +} + +- (CGFloat)heightRequiredForFooterWithWidth:(CGFloat)width layout:(BOOL)layout { + CGFloat widthLeftForLabel = width; + CGSize maxSize = CGSizeMake(widthLeftForLabel, CGFLOAT_MAX); + CGSize labelSize = + [[self.label text] cr_boundingSizeWithSize:maxSize + font:[self.label font]]; + CGFloat viewHeight = labelSize.height; + if (layout) { + // Lays out the label and the switch to fit in {width, viewHeight}. + CGRect newLabelFrame = CGRectMake(0, 0, labelSize.width, labelSize.height); + newLabelFrame = AlignRectOriginAndSizeToPixels(newLabelFrame); + [self.label setFrame:newLabelFrame]; + } + return viewHeight; +} + +- (CGFloat)preferredWidth { + return self.preferredLabelWidth; +} + +@end + +// UIView containing a switch and a label. +@interface SwitchView : InfobarFooterView + +// Initialize the view's label with |labelText|. +- (instancetype)initWithText:(NSString*)labelText + isOn:(BOOL)isOn NS_DESIGNATED_INITIALIZER; +- (instancetype)initWithText:(NSString*)labelText NS_UNAVAILABLE; // Specifies the object, action, and tag used when the switch is toggled. - (void)setTag:(NSInteger)tag target:(id)target action:(SEL)action; @@ -125,7 +193,7 @@ // Returns the height taken by the view constrained by a width of |width|. // If |layout| is yes, it sets the frame of the label and the switch to fit // |width|. -- (CGFloat)heightRequiredForSwitchWithWidth:(CGFloat)width layout:(BOOL)layout; +- (CGFloat)heightRequiredForFooterWithWidth:(CGFloat)width layout:(BOOL)layout; // Returns the preferred width. A smaller width requires eliding the text. - (CGFloat)preferredWidth; @@ -133,46 +201,34 @@ @end @implementation SwitchView { - UILabel* label_; UISwitch* switch_; CGFloat preferredTotalWidth_; - CGFloat preferredLabelWidth_; // Layout metrics for calculating item placement. const LayoutMetrics* metrics_; } -- (id)initWithLabel:(NSString*)labelText isOn:(BOOL)isOn { +- (instancetype)initWithText:(NSString*)labelText isOn:(BOOL)isOn { metrics_ = &kLayoutMetrics; - // Creates switch and label. - UILabel* tempLabel = [[UILabel alloc] initWithFrame:CGRectZero]; - [tempLabel setTextAlignment:NSTextAlignmentNatural]; - [tempLabel setFont:InfoBarSwitchLabelFont()]; - [tempLabel setText:labelText]; - [tempLabel setBackgroundColor:[UIColor clearColor]]; - [tempLabel setLineBreakMode:NSLineBreakByWordWrapping]; - [tempLabel setNumberOfLines:0]; - [tempLabel setAdjustsFontSizeToFitWidth:NO]; - UISwitch* tempSwitch = [[UISwitch alloc] initWithFrame:CGRectZero]; - [tempSwitch setExclusiveTouch:YES]; - [tempSwitch setAccessibilityLabel:labelText]; - [tempSwitch setOnTintColor:[[MDCPalette cr_bluePalette] tint500]]; - [tempSwitch setOn:isOn]; + self = [super initWithText:labelText]; + if (!self) + return nil; + + self.label.textColor = [UIColor blackColor]; + switch_ = [[UISwitch alloc] initWithFrame:CGRectZero]; + switch_.exclusiveTouch = YES; + switch_.accessibilityLabel = labelText; + switch_.onTintColor = [[MDCPalette cr_bluePalette] tint500]; + switch_.on = isOn; // Computes the size and initializes the view. - CGSize maxSize = CGSizeMake(CGFLOAT_MAX, CGFLOAT_MAX); - CGSize labelSize = - [[tempLabel text] cr_boundingSizeWithSize:maxSize font:[tempLabel font]]; - CGSize switchSize = [tempSwitch frame].size; + CGSize labelSize = self.label.frame.size; + CGSize switchSize = switch_.frame.size; CGRect frameRect = CGRectMake( 0, 0, labelSize.width + metrics_->space_between_widgets + switchSize.width, std::max(labelSize.height, switchSize.height)); - self = [super initWithFrame:frameRect]; - if (!self) - return nil; - label_ = tempLabel; - switch_ = tempSwitch; + [self setFrame:frameRect]; // Sets the position of the label and the switch. The label is left aligned // and the switch is right aligned. Both are vertically centered. @@ -187,12 +243,12 @@ labelFrame = AlignRectOriginAndSizeToPixels(labelFrame); switchFrame = AlignRectOriginAndSizeToPixels(switchFrame); - [label_ setFrame:labelFrame]; + [self.label setFrame:labelFrame]; [switch_ setFrame:switchFrame]; preferredTotalWidth_ = CGRectGetMaxX(switchFrame); - preferredLabelWidth_ = CGRectGetMaxX(labelFrame); + self.preferredLabelWidth = CGRectGetMaxX(labelFrame); - [self addSubview:label_]; + [self addSubview:self.label]; [self addSubview:switch_]; return self; } @@ -204,12 +260,13 @@ forControlEvents:UIControlEventValueChanged]; } -- (CGFloat)heightRequiredForSwitchWithWidth:(CGFloat)width layout:(BOOL)layout { +- (CGFloat)heightRequiredForFooterWithWidth:(CGFloat)width layout:(BOOL)layout { CGFloat widthLeftForLabel = width - [switch_ frame].size.width - metrics_->space_between_widgets; CGSize maxSize = CGSizeMake(widthLeftForLabel, CGFLOAT_MAX); CGSize labelSize = - [[label_ text] cr_boundingSizeWithSize:maxSize font:[label_ font]]; + [[self.label text] cr_boundingSizeWithSize:maxSize + font:[self.label font]]; CGFloat viewHeight = std::max(labelSize.height, [switch_ frame].size.height); if (layout) { // Lays out the label and the switch to fit in {width, viewHeight}. @@ -218,7 +275,7 @@ newLabelFrame.origin.y = (viewHeight - labelSize.height) / 2; newLabelFrame.size = labelSize; newLabelFrame = AlignRectOriginAndSizeToPixels(newLabelFrame); - [label_ setFrame:newLabelFrame]; + [self.label setFrame:newLabelFrame]; CGRect newSwitchFrame; newSwitchFrame.origin.x = CGRectGetMaxX(newLabelFrame) + metrics_->space_between_widgets; @@ -282,8 +339,8 @@ UIImageView* imageView_; // Close button. UIButton* closeButton_; - // View containing the switch and its label. - SwitchView* switchView_; + // View containing the label and maybe switch. + InfobarFooterView* InfobarFooterView_; // We are using a LabelLinkController with an UILabel to be able to have // parts of the label underlined and clickable. This label_ may be nil if // the delegate returns an empty string for GetMessageText(). @@ -386,14 +443,14 @@ // Returns the width needed for the switch. - (CGFloat)preferredWidthOfSwitch { - return [switchView_ preferredWidth]; + return [InfobarFooterView_ preferredWidth]; } // Returns the space required to separate the left aligned widgets (label) from // the right aligned widgets (switch, buttons), assuming they fit on one line. - (CGFloat)widthToSeparateRightAndLeftWidgets { BOOL leftWidgetsArePresent = (label_ != nil); - BOOL rightWidgetsArePresent = button1_ || button2_ || switchView_; + BOOL rightWidgetsArePresent = button1_ || button2_ || InfobarFooterView_; if (!leftWidgetsArePresent || !rightWidgetsArePresent) return 0; return metrics_->minimum_space_between_right_and_left_aligned_widgets; @@ -402,7 +459,7 @@ // Returns the space required to separate the switch and the buttons. - (CGFloat)widthToSeparateSwitchAndButtons { BOOL buttonsArePresent = button1_ || button2_; - BOOL switchIsPresent = (switchView_ != nil); + BOOL switchIsPresent = (InfobarFooterView_ != nil); if (!buttonsArePresent || !switchIsPresent) return 0; return metrics_->space_between_widgets; @@ -564,15 +621,15 @@ [button2_ setFrame:frame]; } // Lays out the switch view to the left of the buttons. - if (switchView_) { - frame = - CGRectMake(widthOfScreen - buttonMargin - widthOfButtonAndSwitch, - (metrics_->minimum_infobar_height - - [switchView_ frame].size.height) / - 2.0, - preferredWidthOfSwitch, [switchView_ frame].size.height); + if (InfobarFooterView_) { + frame = CGRectMake( + widthOfScreen - buttonMargin - widthOfButtonAndSwitch, + (metrics_->minimum_infobar_height - + [InfobarFooterView_ frame].size.height) / + 2.0, + preferredWidthOfSwitch, [InfobarFooterView_ frame].size.height); frame = AlignRectOriginAndSizeToPixels(frame); - [switchView_ setFrame:frame]; + [InfobarFooterView_ setFrame:frame]; } } } else { @@ -598,13 +655,15 @@ [self widthOfLabelOnASingleLine], labelHeight); labelFrame = AlignRectOriginAndSizeToPixels(labelFrame); [label_ setFrame:labelFrame]; - if (switchView_) { + if (InfobarFooterView_) { CGRect switchRect = CGRectMake( widthOfScreen - rightMarginOnFirstLine - preferredWidthOfSwitch, - (heightOfLabelAndSwitch - [switchView_ frame].size.height) / 2, - preferredWidthOfSwitch, [switchView_ frame].size.height); + (heightOfLabelAndSwitch - + [InfobarFooterView_ frame].size.height) / + 2, + preferredWidthOfSwitch, [InfobarFooterView_ frame].size.height); switchRect = AlignRectOriginAndSizeToPixels(switchRect); - [switchView_ setFrame:switchRect]; + [InfobarFooterView_ setFrame:switchRect]; } } } else { @@ -632,14 +691,14 @@ // Computes the height of the switch view (if any), and optionally lays it // out. CGFloat heightOfSwitchWithPadding = 0; - if (switchView_ != nil) { + if (InfobarFooterView_ != nil) { // The switch view is aligned with the first line's label, hence the // call to |leftMarginOnFirstLine|. CGFloat widthAvailableForSwitchView = [self frame].size.width - [self leftMarginOnFirstLine] - metrics_->right_margin; - CGFloat heightOfSwitch = [switchView_ - heightRequiredForSwitchWithWidth:widthAvailableForSwitchView + CGFloat heightOfSwitch = [InfobarFooterView_ + heightRequiredForFooterWithWidth:widthAvailableForSwitchView layout:layout]; // If there are buttons underneath the switch, add padding. if (button1_ || button2_) { @@ -654,7 +713,7 @@ CGRectMake([self leftMarginOnFirstLine], heightOfLabelWithPadding, widthAvailableForSwitchView, heightOfSwitch); switchRect = AlignRectOriginAndSizeToPixels(switchRect); - [switchView_ setFrame:switchRect]; + [InfobarFooterView_ setFrame:switchRect]; } } heightOfLabelAndSwitch = @@ -749,9 +808,15 @@ tag:(NSInteger)tag target:(id)target action:(SEL)action { - switchView_ = [[SwitchView alloc] initWithLabel:label isOn:isOn]; - [switchView_ setTag:tag target:target action:action]; - [self addSubview:switchView_]; + SwitchView* switchView = [[SwitchView alloc] initWithText:label isOn:isOn]; + [switchView setTag:tag target:target action:action]; + InfobarFooterView_ = switchView; + [self addSubview:InfobarFooterView_]; +} + +- (void)addFooterLabel:(NSString*)label { + InfobarFooterView_ = [[InfobarFooterView alloc] initWithText:label]; + [self addSubview:InfobarFooterView_]; } - (void)addLeftIcon:(UIImage*)image {
diff --git a/ios/chrome/browser/ui/omnibox/autocomplete_match_formatter.mm b/ios/chrome/browser/ui/omnibox/autocomplete_match_formatter.mm index d7b1414..a41cee13 100644 --- a/ios/chrome/browser/ui/omnibox/autocomplete_match_formatter.mm +++ b/ios/chrome/browser/ui/omnibox/autocomplete_match_formatter.mm
@@ -235,6 +235,10 @@ self.isStarred); } +- (BOOL)isTabMatch { + return _match.has_tab_match; +} + #pragma mark helpers // Create a string to display for an answer line.
diff --git a/ios/chrome/browser/ui/omnibox/autocomplete_suggestion.h b/ios/chrome/browser/ui/omnibox/autocomplete_suggestion.h index c908da7..12fb95cd 100644 --- a/ios/chrome/browser/ui/omnibox/autocomplete_suggestion.h +++ b/ios/chrome/browser/ui/omnibox/autocomplete_suggestion.h
@@ -28,6 +28,8 @@ // image is in template rendering mode, it is expected to be tinted by the image // view. - (UIImage*)suggestionTypeIcon; +// Some suggestions are opened in an other tab. +- (BOOL)isTabMatch; // Text of the suggestion. - (NSAttributedString*)text;
diff --git a/ios/chrome/browser/ui/tab_grid/BUILD.gn b/ios/chrome/browser/ui/tab_grid/BUILD.gn index 80ce26a..5b494f97 100644 --- a/ios/chrome/browser/ui/tab_grid/BUILD.gn +++ b/ios/chrome/browser/ui/tab_grid/BUILD.gn
@@ -88,6 +88,7 @@ "//ios/chrome/browser/ui/tab_grid/transitions", "//ios/chrome/browser/ui/table_view:styler", "//ios/chrome/common/ui_util", + "//ios/web/public", "//ui/base", ] }
diff --git a/ios/chrome/browser/ui/uikit_ui_util.h b/ios/chrome/browser/ui/uikit_ui_util.h index 976bf18..46b29de 100644 --- a/ios/chrome/browser/ui/uikit_ui_util.h +++ b/ios/chrome/browser/ui/uikit_ui_util.h
@@ -248,4 +248,8 @@ // more than 99 tabs open. NSString* TextForTabCount(long count); +// Helper check if |category| is an accessibility category. For iOS 11+ it is a +// wrapper around UIContentSizeCategoryIsAccessibilityCategory. +BOOL ContentSizeCategoryIsAccessibilityCategory(UIContentSizeCategory category); + #endif // IOS_CHROME_BROWSER_UI_UIKIT_UI_UTIL_H_
diff --git a/ios/chrome/browser/ui/uikit_ui_util.mm b/ios/chrome/browser/ui/uikit_ui_util.mm index e04ba59..51aa794 100644 --- a/ios/chrome/browser/ui/uikit_ui_util.mm +++ b/ios/chrome/browser/ui/uikit_ui_util.mm
@@ -679,3 +679,16 @@ return @":)"; return [NSString stringWithFormat:@"%ld", count]; } + +BOOL ContentSizeCategoryIsAccessibilityCategory( + UIContentSizeCategory category) { + if (@available(iOS 11.0, *)) { + return UIContentSizeCategoryIsAccessibilityCategory(category); + } else { + return category == UIContentSizeCategoryAccessibilityExtraExtraExtraLarge || + category == UIContentSizeCategoryAccessibilityExtraExtraLarge || + category == UIContentSizeCategoryAccessibilityExtraLarge || + category == UIContentSizeCategoryAccessibilityLarge || + category == UIContentSizeCategoryAccessibilityMedium; + } +}
diff --git a/ios/public/provider/chrome/browser/distribution/app_distribution_provider.h b/ios/public/provider/chrome/browser/distribution/app_distribution_provider.h index b60afcf..832dcce0 100644 --- a/ios/public/provider/chrome/browser/distribution/app_distribution_provider.h +++ b/ios/public/provider/chrome/browser/distribution/app_distribution_provider.h
@@ -30,6 +30,10 @@ // Cancels any pending distribution notifications. virtual void CancelDistributionNotifications(); + // Returns whether user who installed Chrome on |install_date| predates + // integration with Firebase for installation attribution. + virtual bool IsPreFirebaseLegacyUser(int64_t install_date); + private: DISALLOW_COPY_AND_ASSIGN(AppDistributionProvider); };
diff --git a/ios/public/provider/chrome/browser/distribution/app_distribution_provider.mm b/ios/public/provider/chrome/browser/distribution/app_distribution_provider.mm index 3f744451..39827c9 100644 --- a/ios/public/provider/chrome/browser/distribution/app_distribution_provider.mm +++ b/ios/public/provider/chrome/browser/distribution/app_distribution_provider.mm
@@ -21,3 +21,7 @@ bool is_first_run) {} void AppDistributionProvider::CancelDistributionNotifications() {} + +bool AppDistributionProvider::IsPreFirebaseLegacyUser(int64_t install_date) { + return false; +}
diff --git a/ios/public/provider/chrome/browser/distribution/test_app_distribution_provider.h b/ios/public/provider/chrome/browser/distribution/test_app_distribution_provider.h index 7efef29..e620c4e 100644 --- a/ios/public/provider/chrome/browser/distribution/test_app_distribution_provider.h +++ b/ios/public/provider/chrome/browser/distribution/test_app_distribution_provider.h
@@ -25,6 +25,7 @@ scoped_refptr<network::SharedURLLoaderFactory> shared_url_loader_factory, bool is_first_run) override; void CancelDistributionNotifications() override; + bool IsPreFirebaseLegacyUser(int64_t install_date) override; private: DISALLOW_COPY_AND_ASSIGN(TestAppDistributionProvider);
diff --git a/ios/public/provider/chrome/browser/distribution/test_app_distribution_provider.mm b/ios/public/provider/chrome/browser/distribution/test_app_distribution_provider.mm index eb89745..959d597 100644 --- a/ios/public/provider/chrome/browser/distribution/test_app_distribution_provider.mm +++ b/ios/public/provider/chrome/browser/distribution/test_app_distribution_provider.mm
@@ -21,3 +21,8 @@ bool is_first_run) {} void TestAppDistributionProvider::CancelDistributionNotifications() {} + +bool TestAppDistributionProvider::IsPreFirebaseLegacyUser( + int64_t install_date) { + return false; +}
diff --git a/ios/public/provider/chrome/browser/voice/BUILD.gn b/ios/public/provider/chrome/browser/voice/BUILD.gn index 0e67bbdf..217f919 100644 --- a/ios/public/provider/chrome/browser/voice/BUILD.gn +++ b/ios/public/provider/chrome/browser/voice/BUILD.gn
@@ -7,8 +7,6 @@ sources = [ "audio_session_controller.h", "logo_animation_controller.h", - "voice_search_bar.h", - "voice_search_bar_owner.h", "voice_search_controller.h", "voice_search_controller.mm", "voice_search_language.h",
diff --git a/ios/public/provider/chrome/browser/voice/voice_search_bar.h b/ios/public/provider/chrome/browser/voice/voice_search_bar.h deleted file mode 100644 index f6591d2..0000000 --- a/ios/public/provider/chrome/browser/voice/voice_search_bar.h +++ /dev/null
@@ -1,42 +0,0 @@ -// Copyright 2016 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef IOS_PUBLIC_PROVIDER_CHROME_BROWSER_VOICE_VOICE_SEARCH_BAR_H_ -#define IOS_PUBLIC_PROVIDER_CHROME_BROWSER_VOICE_VOICE_SEARCH_BAR_H_ - -#import <Foundation/Foundation.h> - -@protocol VoiceSearchBarDelegate; - -// TODO(crbug.com/800266): Check if those protocols are still relevant with the -// adaptive toolbar. - -// Protocol used by bottom toolbars containing a button to launch VoiceSearch. -@protocol VoiceSearchBar<NSObject> - -// The VoiceSearchBar's delegate. -@property(nonatomic, assign) id<VoiceSearchBarDelegate> voiceSearchBarDelegate; - -// Animates the view up from the bottom of the its superview so that it's -// visible or down so that it's no longer visible. -- (void)animateToBecomeVisible:(BOOL)visible; - -// Sets necessary state to prepare for presenting voice search. -- (void)prepareToPresentVoiceSearch; - -@end - -// The delegate protocol for VoiceSearchBar. -@protocol VoiceSearchBarDelegate - -// Returns whether Text To Speech is enabled for |voiceSearchBar|. -- (BOOL)isTTSEnabledForVoiceSearchBar:(id<VoiceSearchBar>)voiceSearchBar; - -// Called to notify the delegate that the state of |voiceSearchBar|'s -// VoiceSearch button appearance has been updated. -- (void)voiceSearchBarDidUpdateButtonState:(id<VoiceSearchBar>)voiceSearchBar; - -@end - -#endif // IOS_PUBLIC_PROVIDER_CHROME_BROWSER_VOICE_VOICE_SEARCH_BAR_H_
diff --git a/ios/public/provider/chrome/browser/voice/voice_search_bar_owner.h b/ios/public/provider/chrome/browser/voice/voice_search_bar_owner.h deleted file mode 100644 index 5ff7704..0000000 --- a/ios/public/provider/chrome/browser/voice/voice_search_bar_owner.h +++ /dev/null
@@ -1,20 +0,0 @@ -// Copyright 2016 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef IOS_PUBLIC_PROVIDER_CHROME_BROWSER_VOICE_VOICE_SEARCH_BAR_OWNER_H_ -#define IOS_PUBLIC_PROVIDER_CHROME_BROWSER_VOICE_VOICE_SEARCH_BAR_OWNER_H_ - -#import <Foundation/Foundation.h> - -@protocol VoiceSearchBar; - -// Protocol implemented by UIViewControllers that own a VoiceSearchBar. -@protocol VoiceSearchBarOwner<NSObject> - -// The VoiceSearchBar. -@property(nonatomic, readonly) id<VoiceSearchBar> voiceSearchBar; - -@end - -#endif // IOS_PUBLIC_PROVIDER_CHROME_BROWSER_VOICE_VOICE_SEARCH_BAR_OWNER_H_
diff --git a/ios/public/provider/chrome/browser/voice/voice_search_provider.h b/ios/public/provider/chrome/browser/voice/voice_search_provider.h index b47ee07..92b4550 100644 --- a/ios/public/provider/chrome/browser/voice/voice_search_provider.h +++ b/ios/public/provider/chrome/browser/voice/voice_search_provider.h
@@ -13,7 +13,6 @@ @protocol ApplicationCommands; class AudioSessionController; -@protocol VoiceSearchBar; class VoiceSearchController; namespace ios { @@ -41,15 +40,6 @@ virtual scoped_refptr<VoiceSearchController> CreateVoiceSearchController( ios::ChromeBrowserState* browser_state) const; - // Creates a new VoiceSearchBar. Returns an autoreleased view. - virtual UIView<VoiceSearchBar>* BuildVoiceSearchBar(CGRect frame) const; - - // Creates a new VoiceSearchBar which uses |dispatcher| to send commands. - // Returns an autoreleased view. - virtual UIView<VoiceSearchBar>* BuildVoiceSearchBar( - CGRect frame, - id<ApplicationCommands> dispatcher) const; - private: DISALLOW_COPY_AND_ASSIGN(VoiceSearchProvider); };
diff --git a/ios/public/provider/chrome/browser/voice/voice_search_provider.mm b/ios/public/provider/chrome/browser/voice/voice_search_provider.mm index 52d979d..1db4e98 100644 --- a/ios/public/provider/chrome/browser/voice/voice_search_provider.mm +++ b/ios/public/provider/chrome/browser/voice/voice_search_provider.mm
@@ -28,13 +28,3 @@ return scoped_refptr<VoiceSearchController>(nullptr); } -UIView<VoiceSearchBar>* VoiceSearchProvider::BuildVoiceSearchBar( - CGRect frame) const { - return nil; -} - -UIView<VoiceSearchBar>* VoiceSearchProvider::BuildVoiceSearchBar( - CGRect frame, - id<ApplicationCommands> dispatcher) const { - return BuildVoiceSearchBar(frame); -}
diff --git a/ios/showcase/content_suggestions/sc_content_suggestions_item.mm b/ios/showcase/content_suggestions/sc_content_suggestions_item.mm index 5dff91a..89e19bc 100644 --- a/ios/showcase/content_suggestions/sc_content_suggestions_item.mm +++ b/ios/showcase/content_suggestions/sc_content_suggestions_item.mm
@@ -50,7 +50,7 @@ - (CGFloat)cellHeightForWidth:(CGFloat)width { return [self.cellClass heightForWidth:width - withImage:self.hasImage + withImageAvailable:self.hasImage title:self.title publisherName:self.publisher publicationDate:self.publicationDate];
diff --git a/media/audio/BUILD.gn b/media/audio/BUILD.gn index c1fc438..38e7bb1 100644 --- a/media/audio/BUILD.gn +++ b/media/audio/BUILD.gn
@@ -231,13 +231,9 @@ ] libs += [ - "dmoguids.lib", "dxguid.lib", - "msdmo.lib", "setupapi.lib", - "strmiids.lib", "winmm.lib", - "wmcodecdspuuid.lib", ] }
diff --git a/media/audio/win/audio_low_latency_input_win.cc b/media/audio/win/audio_low_latency_input_win.cc index 1cce7d614..90b1215 100644 --- a/media/audio/win/audio_low_latency_input_win.cc +++ b/media/audio/win/audio_low_latency_input_win.cc
@@ -4,11 +4,7 @@ #include "media/audio/win/audio_low_latency_input_win.h" -#include <audiopolicy.h> -#include <mediaobj.h> #include <objbase.h> -#include <uuids.h> -#include <wmcodecdsp.h> #include <algorithm> #include <cmath> @@ -70,125 +66,18 @@ return true; } -// Returns the index of the device in the device collection, or -1 for the -// default device, as used by the voice processing DMO. -base::Optional<WORD> GetAudioDeviceCollectionIndexFromId( - const std::string& device_id, - const EDataFlow data_flow) { - // The default device is specified with -1. - if (AudioDeviceDescription::IsDefaultDevice(device_id)) - return -1; - - WORD device_index = -1; - HRESULT hr = E_FAIL; - // The default communications does not have an index itself, so we need to - // find the index for the underlying device. - if (AudioDeviceDescription::IsCommunicationsDevice(device_id)) { - const std::string communications_id = - (data_flow == eCapture) - ? CoreAudioUtil::GetCommunicationsInputDeviceID() - : CoreAudioUtil::GetCommunicationsOutputDeviceID(); - hr = CoreAudioUtil::GetDeviceCollectionIndex(communications_id, data_flow, - &device_index); - } else { - // Otherwise, just look for the device_id directly. - hr = CoreAudioUtil::GetDeviceCollectionIndex(device_id, data_flow, - &device_index); - } - - if (FAILED(hr) || hr == S_FALSE) - return base::nullopt; - - return device_index; -} - -// Implementation of IMediaBuffer, as required for -// IMediaObject::ProcessOutput(). After consuming data provided by -// ProcessOutput(), call SetLength() to update the buffer availability. -// Example implementation: -// http://msdn.microsoft.com/en-us/library/dd376684(v=vs.85).aspx -class MediaBufferImpl : public IMediaBuffer { - public: - explicit MediaBufferImpl(DWORD max_length) - : data_(new BYTE[max_length]), max_length_(max_length) {} - - // IMediaBuffer implementation. - STDMETHOD(GetBufferAndLength)(BYTE** buffer, DWORD* length) { - if (!buffer || !length) - return E_POINTER; - - *buffer = data_.get(); - *length = length_; - return S_OK; - } - - STDMETHOD(GetMaxLength)(DWORD* max_length) { - if (!max_length) - return E_POINTER; - - *max_length = max_length_; - return S_OK; - } - - STDMETHOD(SetLength)(DWORD length) { - if (length > max_length_) - return E_INVALIDARG; - - length_ = length; - return S_OK; - } - - // IUnknown implementation. - STDMETHOD_(ULONG, AddRef)() { return InterlockedIncrement(&ref_count_); } - - STDMETHOD(QueryInterface)(REFIID riid, void** object) { - if (!object) - return E_POINTER; - if (riid != IID_IMediaBuffer && riid != IID_IUnknown) - return E_NOINTERFACE; - - *object = static_cast<IMediaBuffer*>(this); - AddRef(); - return S_OK; - } - - STDMETHOD_(ULONG, Release)() { - LONG ref_count = InterlockedDecrement(&ref_count_); - if (ref_count == 0) - delete this; - - return ref_count; - } - - private: - virtual ~MediaBufferImpl() {} - - std::unique_ptr<BYTE[]> data_; - DWORD length_ = 0; - const DWORD max_length_; - LONG ref_count_ = 0; -}; - } // namespace WASAPIAudioInputStream::WASAPIAudioInputStream( AudioManagerWin* manager, const AudioParameters& params, const std::string& device_id, - const AudioManager::LogCallback& log_callback, - AudioManagerBase::VoiceProcessingMode voice_processing_mode) - : manager_(manager), - device_id_(device_id), - output_device_id_for_aec_(AudioDeviceDescription::kDefaultDeviceId), - log_callback_(log_callback), - use_voice_processing_(voice_processing_mode == - AudioManagerBase::VoiceProcessingMode::kEnabled) { + const AudioManager::LogCallback& log_callback) + : manager_(manager), device_id_(device_id), log_callback_(log_callback) { DCHECK(manager_); DCHECK(!device_id_.empty()); DCHECK(!log_callback_.is_null()); - DVLOG_IF(1, use_voice_processing_) << "Using Windows voice capture DSP DMO."; - // Load the Avrt DLL if not already loaded. Required to support MMCSS. bool avrt_init = avrt::Initialize(); DCHECK(avrt_init) << "Failed to load the Avrt.dll"; @@ -255,16 +144,6 @@ return false; } - // If voice processing is enabled, initialize the DMO that is used for it. The - // remainder of the function initializes an audio capture client (the normal - // case). Either the DMO or the capture client is used. - // TODO(grunell): Refactor out the audio capture client initialization to its - // own function. - if (use_voice_processing_) { - opened_ = InitializeDmo(); - return opened_; - } - // Obtain an IAudioClient interface which enables us to create and initialize // an audio stream between an audio application and the audio engine. hr = endpoint_device_->Activate(__uuidof(IAudioClient), CLSCTX_INPROC_SERVER, @@ -312,27 +191,17 @@ if (started_) return; - // TODO(grunell): Refactor the |use_voice_processing_| conditions in this - // function to clean up the code. - if (use_voice_processing_) { - // Pre-fill render buffer with silence. - if (!CoreAudioUtil::FillRenderEndpointBufferWithSilence( - audio_client_for_render_.Get(), audio_render_client_.Get())) { - DLOG(WARNING) << "Failed to pre-fill render buffer with silence."; - } - } else { - if (device_id_ == AudioDeviceDescription::kLoopbackWithMuteDeviceId && - system_audio_volume_) { - BOOL muted = false; - system_audio_volume_->GetMute(&muted); + if (device_id_ == AudioDeviceDescription::kLoopbackWithMuteDeviceId && + system_audio_volume_) { + BOOL muted = false; + system_audio_volume_->GetMute(&muted); - // If the system audio is muted at the time of capturing, then no need to - // mute it again, and later we do not unmute system audio when stopping - // capturing. - if (!muted) { - system_audio_volume_->SetMute(true, NULL); - mute_done_ = true; - } + // If the system audio is muted at the time of capturing, then no need to + // mute it again, and later we do not unmute system audio when stopping + // capturing. + if (!muted) { + system_audio_volume_->SetMute(true, NULL); + mute_done_ = true; } } @@ -351,31 +220,21 @@ base::SimpleThread::Options(base::ThreadPriority::REALTIME_AUDIO))); capture_thread_->Start(); - HRESULT hr = E_FAIL; - if (use_voice_processing_) { - hr = audio_client_for_render_->Start(); - if (FAILED(hr)) { - DLOG(ERROR) << "Failed to start output streaming: " << std::hex << hr - << ", proceeding without rendering."; - } - } else { - // Start streaming data between the endpoint buffer and the audio engine. - hr = audio_client_->Start(); - if (FAILED(hr)) { - DLOG(ERROR) << "Failed to start input streaming."; - log_callback_.Run(base::StringPrintf( - "WASAPIAIS::Start: Failed to start audio client, hresult = %#lx", - hr)); - } + // Start streaming data between the endpoint buffer and the audio engine. + HRESULT hr = audio_client_->Start(); + if (FAILED(hr)) { + DLOG(ERROR) << "Failed to start input streaming."; + log_callback_.Run(base::StringPrintf( + "WASAPIAIS::Start: Failed to start audio client, hresult = %#lx", hr)); + } - if (SUCCEEDED(hr) && audio_render_client_for_loopback_.Get()) { - hr = audio_render_client_for_loopback_->Start(); - if (FAILED(hr)) - log_callback_.Run(base::StringPrintf( - "WASAPIAIS::Start: Failed to start render client for loopback, " - "hresult = %#lx", - hr)); - } + if (SUCCEEDED(hr) && audio_render_client_for_loopback_.Get()) { + hr = audio_render_client_for_loopback_->Start(); + if (FAILED(hr)) + log_callback_.Run(base::StringPrintf( + "WASAPIAIS::Start: Failed to start render client for loopback, " + "hresult = %#lx", + hr)); } started_ = SUCCEEDED(hr); @@ -406,21 +265,10 @@ SetEvent(stop_capture_event_.Get()); } - // TODO(grunell): Refactor the |use_voice_processing_| conditions in this - // function to clean up the code. - if (use_voice_processing_) { - // Stop the render audio streaming. The input streaming needs no explicit - // stopping. - HRESULT hr = audio_client_for_render_->Stop(); - if (FAILED(hr)) { - DLOG(ERROR) << "Failed to stop output streaming."; - } - } else { - // Stop the input audio streaming. - HRESULT hr = audio_client_->Stop(); - if (FAILED(hr)) { - DLOG(ERROR) << "Failed to stop input streaming."; - } + // Stop the input audio streaming. + HRESULT hr = audio_client_->Stop(); + if (FAILED(hr)) { + LOG(ERROR) << "Failed to stop input streaming."; } // Wait until the thread completes and perform cleanup. @@ -430,12 +278,6 @@ capture_thread_.reset(); } - if (use_voice_processing_) { - HRESULT hr = voice_capture_dmo_->FreeStreamingResources(); - if (FAILED(hr)) - DLOG(ERROR) << "Failed to free dmo resources."; - } - started_ = false; sink_ = NULL; } @@ -524,58 +366,7 @@ void WASAPIAudioInputStream::SetOutputDeviceForAec( const std::string& output_device_id) { - if (!use_voice_processing_) - return; - - if (output_device_id == output_device_id_for_aec_) - return; - - output_device_id_for_aec_ = output_device_id; - - if (opened_) { - // Set devices. - Microsoft::WRL::ComPtr<IPropertyStore> ps; - HRESULT hr = voice_capture_dmo_->QueryInterface(IID_IPropertyStore, &ps); - if (FAILED(hr) || !ps) { - log_callback_.Run( - base::StringPrintf("WASAPIAIS:SetOutputDeviceForAec: Getting DMO " - "property store failed.")); - return; - } - - if (!SetDmoDevices(ps.Get())) { - log_callback_.Run( - "WASAPIAIS:SetOutputDeviceForAec: Setting device indices failed."); - return; - } - } - - if (started_) { - DCHECK(opened_); - // Recreate the dummy render client on the new output. - HRESULT hr = audio_client_for_render_->Stop(); - if (FAILED(hr)) { - DLOG(ERROR) << "Failed to stop output streaming."; - } - - CreateDummyRenderClientsForDmo(); - - if (!CoreAudioUtil::FillRenderEndpointBufferWithSilence( - audio_client_for_render_.Get(), audio_render_client_.Get())) { - DLOG(WARNING) << "Failed to pre-fill render buffer with silence."; - } - - hr = audio_client_for_render_->Start(); - if (FAILED(hr)) { - DLOG(ERROR) << "Failed to start output streaming: " << std::hex << hr - << ", proceeding without rendering."; - } - } - - log_callback_.Run(base::StringPrintf( - "WASAPIAIS:SetOutputDeviceForAec: Successfully updated AEC output " - "device to %s", - output_device_id.c_str())); + // Not supported. Do nothing. } void WASAPIAudioInputStream::Run() { @@ -619,10 +410,31 @@ DVLOG(1) << "AudioBlockFifo buffer count: " << buffers_required; - bool success = - use_voice_processing_ ? RunWithDmo() : RunWithAudioCaptureClient(); + bool recording = true; + bool error = false; + HANDLE wait_array[2] = {stop_capture_event_.Get(), + audio_samples_ready_event_.Get()}; - if (!success) { + while (recording && !error) { + // Wait for a close-down event or a new capture event. + DWORD wait_result = WaitForMultipleObjects(2, wait_array, FALSE, INFINITE); + switch (wait_result) { + case WAIT_OBJECT_0 + 0: + // |stop_capture_event_| has been set. + recording = false; + break; + case WAIT_OBJECT_0 + 1: + // |audio_samples_ready_event_| has been set. + PullCaptureDataAndPushToSink(); + break; + case WAIT_FAILED: + default: + error = true; + break; + } + } + + if (recording && error) { // TODO(henrika): perhaps it worth improving the cleanup here by e.g. // stopping the audio client, joining the thread etc.? NOTREACHED() << "WASAPI capturing failed with error code " @@ -637,54 +449,6 @@ fifo_.reset(); } -bool WASAPIAudioInputStream::RunWithAudioCaptureClient() { - HANDLE wait_array[2] = {stop_capture_event_.Get(), - audio_samples_ready_event_.Get()}; - - while (true) { - // Wait for a close-down event or a new capture event. - DWORD wait_result = WaitForMultipleObjects(2, wait_array, FALSE, INFINITE); - switch (wait_result) { - case WAIT_OBJECT_0 + 0: - // |stop_capture_event_| has been set. - return true; - case WAIT_OBJECT_0 + 1: - // |audio_samples_ready_event_| has been set. - PullCaptureDataAndPushToSink(); - break; - case WAIT_FAILED: - default: - return false; - } - } - - return false; -} - -bool WASAPIAudioInputStream::RunWithDmo() { - while (true) { - // Poll every 5 ms, or wake up on capture stop signal. - DWORD wait_result = WaitForSingleObject(stop_capture_event_.Get(), 5); - switch (wait_result) { - case WAIT_OBJECT_0: - // |stop_capture_event_| has been set. - return true; - case WAIT_TIMEOUT: - PullDmoCaptureDataAndPushToSink(); - if (!CoreAudioUtil::FillRenderEndpointBufferWithSilence( - audio_client_for_render_.Get(), audio_render_client_.Get())) { - DLOG(WARNING) << "Failed to fill render buffer with silence."; - } - break; - case WAIT_FAILED: - default: - return false; - } - } - - return false; -} - void WASAPIAudioInputStream::PullCaptureDataAndPushToSink() { TRACE_EVENT1("audio", "WASAPIAudioInputStream::PullCaptureDataAndPushToSink", "sample rate", input_format_.nSamplesPerSec); @@ -813,106 +577,6 @@ } // while (true) } -void WASAPIAudioInputStream::PullDmoCaptureDataAndPushToSink() { - TRACE_EVENT1("audio", - "WASAPIAudioInputStream::PullDmoCaptureDataAndPushToSink", - "sample rate", input_format_.nSamplesPerSec); - - // Pull data from the capture endpoint buffer until it's empty or an error - // occurs. - while (true) { - DWORD status = 0; - DMO_OUTPUT_DATA_BUFFER data_buffer = {0}; - data_buffer.pBuffer = media_buffer_.Get(); - - // Get processed capture data from the DMO. - HRESULT hr = - voice_capture_dmo_->ProcessOutput(0, // dwFlags - 1, // cOutputBufferCount - &data_buffer, - &status); // Must be ignored. - if (FAILED(hr)) { - DLOG(ERROR) << "DMO ProcessOutput failed, hr = 0x" << std::hex << hr; - break; - } - - BYTE* data; - ULONG data_length = 0; - // Get a pointer to the data buffer. This should be valid until the next - // call to ProcessOutput. - hr = media_buffer_->GetBufferAndLength(&data, &data_length); - if (FAILED(hr)) { - DLOG(ERROR) << "Could not get buffer, hr = 0x" << std::hex << hr; - break; - } - - if (data_length > 0) { - const int samples_produced = data_length / frame_size_bytes_; - - base::TimeTicks capture_time; - if (data_buffer.dwStatus & DMO_OUTPUT_DATA_BUFFERF_TIME && - data_buffer.rtTimestamp > 0) { - // See conversion notes on |capture_time_100ns| in - // PullCaptureDataAndPushToSink(). - capture_time += - base::TimeDelta::FromMicroseconds(data_buffer.rtTimestamp / 10.0); - } else { - // We may not get the timestamp from ProcessOutput(), fall back on - // current timestamp. - capture_time = base::TimeTicks::Now(); - } - - // Adjust |capture_time| for the FIFO before pushing. - capture_time -= AudioTimestampHelper::FramesToTime( - fifo_->GetAvailableFrames(), input_format_.nSamplesPerSec); - - fifo_->Push(data, samples_produced, input_format_.wBitsPerSample / 8); - - // Reset length to indicate buffer availability. - hr = media_buffer_->SetLength(0); - if (FAILED(hr)) - DLOG(ERROR) << "Could not reset length, hr = 0x" << std::hex << hr; - - // Get a cached AGC volume level which is updated once every second on the - // audio manager thread. Note that, |volume| is also updated each time - // SetVolume() is called through IPC by the render-side AGC. - double volume = 0.0; - GetAgcVolume(&volume); - - while (fifo_->available_blocks()) { - if (converter_) { - if (imperfect_buffer_size_conversion_ && - fifo_->available_blocks() == 1) { - // Special case. We need to buffer up more audio before we can - // convert or else we'll suffer an underrun. - // TODO(grunell): Verify this is really true. - break; - } - converter_->Convert(convert_bus_.get()); - sink_->OnData(convert_bus_.get(), capture_time, volume); - - // Move the capture time forward for each vended block. - capture_time += AudioTimestampHelper::FramesToTime( - convert_bus_->frames(), output_format_.nSamplesPerSec); - } else { - sink_->OnData(fifo_->Consume(), capture_time, volume); - - // Move the capture time forward for each vended block. - capture_time += AudioTimestampHelper::FramesToTime( - packet_size_frames_, input_format_.nSamplesPerSec); - } - } - } // if (data_length > 0) - - if (!(data_buffer.dwStatus & DMO_OUTPUT_DATA_BUFFERF_INCOMPLETE)) { - // The DMO cannot currently produce more data. This is the normal case; - // otherwise it means the DMO had more than 10 ms of data available and - // ProcessOutput should be called again. - break; - } - } // while (true) -} - void WASAPIAudioInputStream::HandleError(HRESULT err) { NOTREACHED() << "Error code: " << err; if (sink_) @@ -1334,223 +998,6 @@ FormatRelatedInitError::kCount); } -bool WASAPIAudioInputStream::InitializeDmo() { - HRESULT hr = ::CoCreateInstance(CLSID_CWMAudioAEC, NULL, CLSCTX_INPROC_SERVER, - IID_IMediaObject, &voice_capture_dmo_); - if (FAILED(hr)) { - DLOG(ERROR) << "Creating DMO failed."; - return false; - } - - if (!SetDmoProperties()) - return false; - - if (!SetDmoFormat()) - return false; - - hr = voice_capture_dmo_->AllocateStreamingResources(); - if (FAILED(hr)) { - DLOG(ERROR) << "Allocating DMO resources failed."; - return false; - } - - SetupConverterAndStoreFormatInfo(); - - media_buffer_ = - new MediaBufferImpl(endpoint_buffer_size_frames_ * frame_size_bytes_); - - if (!CreateDummyRenderClientsForDmo()) - return false; - - // Get volume interface. - Microsoft::WRL::ComPtr<IAudioSessionManager> audio_session_manager; - hr = endpoint_device_->Activate(__uuidof(IAudioSessionManager), - CLSCTX_INPROC_SERVER, NULL, - &audio_session_manager); - if (FAILED(hr)) { - DLOG(ERROR) << "Obtaining audio session manager failed."; - return false; - } - hr = audio_session_manager->GetSimpleAudioVolume( - NULL, // AudioSessionGuid. NULL for default session. - FALSE, // CrossProcessSession. - &simple_audio_volume_); - if (FAILED(hr)) { - DLOG(ERROR) << "Obtaining audio volume interface failed."; - return false; - } - - return true; -} - -bool WASAPIAudioInputStream::SetDmoProperties() { - Microsoft::WRL::ComPtr<IPropertyStore> ps; - HRESULT hr = voice_capture_dmo_->QueryInterface(IID_IPropertyStore, &ps); - if (FAILED(hr) || !ps) { - DLOG(ERROR) << "Getting DMO property store failed."; - return false; - } - - // Set devices. - if (!SetDmoDevices(ps.Get())) { - DLOG(ERROR) << "Setting device indices failed."; - return false; - } - - // Set DMO mode to AEC only. - if (FAILED(CoreAudioUtil::SetVtI4Property( - ps.Get(), MFPKEY_WMAAECMA_SYSTEM_MODE, SINGLE_CHANNEL_AEC))) { - DLOG(ERROR) << "Setting DMO system mode failed."; - return false; - } - - // Enable the feature mode. This lets us override the default processing - // settings below. - if (FAILED(CoreAudioUtil::SetBoolProperty( - ps.Get(), MFPKEY_WMAAECMA_FEATURE_MODE, VARIANT_TRUE))) { - DLOG(ERROR) << "Setting DMO feature mode failed."; - return false; - } - - // Disable analog AGC (default enabled). - if (FAILED(CoreAudioUtil::SetBoolProperty( - ps.Get(), MFPKEY_WMAAECMA_MIC_GAIN_BOUNDER, VARIANT_FALSE))) { - DLOG(ERROR) << "Setting DMO mic gain bounder failed."; - return false; - } - - // Disable noise suppression (default enabled). - if (FAILED(CoreAudioUtil::SetVtI4Property(ps.Get(), MFPKEY_WMAAECMA_FEATR_NS, - 0))) { - DLOG(ERROR) << "Disabling DMO NS failed."; - return false; - } - - return true; -} - -bool WASAPIAudioInputStream::SetDmoFormat() { - DMO_MEDIA_TYPE mt; // Media type. - mt.majortype = MEDIATYPE_Audio; - mt.subtype = MEDIASUBTYPE_PCM; - mt.lSampleSize = 0; - mt.bFixedSizeSamples = TRUE; - mt.bTemporalCompression = FALSE; - mt.formattype = FORMAT_WaveFormatEx; - - HRESULT hr = MoInitMediaType(&mt, sizeof(WAVEFORMATEX)); - if (FAILED(hr)) { - DLOG(ERROR) << "Init media type for DMO failed."; - return false; - } - - WAVEFORMATEX* dmo_output_format = - reinterpret_cast<WAVEFORMATEX*>(mt.pbFormat); - dmo_output_format->wFormatTag = WAVE_FORMAT_PCM; - dmo_output_format->nChannels = 1; - dmo_output_format->nSamplesPerSec = 16000; - dmo_output_format->nAvgBytesPerSec = 32000; - dmo_output_format->nBlockAlign = 2; - dmo_output_format->wBitsPerSample = 16; - dmo_output_format->cbSize = 0; - - DCHECK(IsSupportedFormatForConversion(*dmo_output_format)); - - // Store the format used. - input_format_.wFormatTag = dmo_output_format->wFormatTag; - input_format_.nChannels = dmo_output_format->nChannels; - input_format_.nSamplesPerSec = dmo_output_format->nSamplesPerSec; - input_format_.wBitsPerSample = dmo_output_format->wBitsPerSample; - input_format_.nBlockAlign = dmo_output_format->nBlockAlign; - input_format_.nAvgBytesPerSec = dmo_output_format->nAvgBytesPerSec; - input_format_.cbSize = dmo_output_format->cbSize; - - hr = voice_capture_dmo_->SetOutputType(0, &mt, 0); - MoFreeMediaType(&mt); - if (FAILED(hr)) { - DLOG(ERROR) << "Setting DMO output type failed."; - return false; - } - - // We use 10 ms buffer size for the DMO. - endpoint_buffer_size_frames_ = input_format_.nSamplesPerSec / 100; - - return true; -} - -bool WASAPIAudioInputStream::SetDmoDevices(IPropertyStore* ps) { - // Look up the input device's index. - const base::Optional<WORD> input_device_index = - GetAudioDeviceCollectionIndexFromId(device_id_, eCapture); - - if (!input_device_index) { - log_callback_.Run( - base::StringPrintf("WASAPIAIS:SetDmoDevices: Could not " - "resolve input device index for %s", - device_id_.c_str())); - return false; - } - - // Look up the output device's index. - const base::Optional<WORD> output_device_index = - GetAudioDeviceCollectionIndexFromId(output_device_id_for_aec_, eRender); - if (!output_device_index) { - log_callback_.Run( - base::StringPrintf("WASAPIAIS:SetDmoDevices: Could not " - "resolve output device index for %s", - output_device_id_for_aec_.c_str())); - return false; - } - - // The DEVICE_INDEXES property packs the input and output indices into the - // upper and lower halves of a LONG. - LONG device_index_value = - (static_cast<ULONG>(*output_device_index) << 16) + - (static_cast<ULONG>(*input_device_index) & 0x0000ffff); - return !FAILED(CoreAudioUtil::SetVtI4Property( - ps, MFPKEY_WMAAECMA_DEVICE_INDEXES, device_index_value)); -} - -bool WASAPIAudioInputStream::CreateDummyRenderClientsForDmo() { - Microsoft::WRL::ComPtr<IAudioClient> audio_client(CoreAudioUtil::CreateClient( - output_device_id_for_aec_, eRender, eConsole)); - if (!audio_client.Get()) { - DLOG(ERROR) << "Failed to create audio client for dummy rendering for DMO."; - return false; - } - - WAVEFORMATPCMEX mix_format; - HRESULT hr = - CoreAudioUtil::GetSharedModeMixFormat(audio_client.Get(), &mix_format); - if (FAILED(hr)) { - DLOG(ERROR) << "Failed to get mix format."; - return false; - } - - hr = audio_client->Initialize(AUDCLNT_SHAREMODE_SHARED, - 0, // Stream flags - 0, // Buffer duration - 0, // Device period - reinterpret_cast<WAVEFORMATEX*>(&mix_format), - NULL); - if (FAILED(hr)) { - DLOG(ERROR) << "Failed to initalize audio client for rendering."; - return false; - } - - Microsoft::WRL::ComPtr<IAudioRenderClient> audio_render_client = - CoreAudioUtil::CreateRenderClient(audio_client.Get()); - if (!audio_render_client.Get()) { - DLOG(ERROR) << "Failed to create audio render client."; - return false; - } - - audio_client_for_render_ = audio_client; - audio_render_client_ = audio_render_client; - - return true; -} - double WASAPIAudioInputStream::ProvideInput(AudioBus* audio_bus, uint32_t frames_delayed) { fifo_->Consume()->CopyTo(audio_bus);
diff --git a/media/audio/win/audio_low_latency_input_win.h b/media/audio/win/audio_low_latency_input_win.h index 938bba7..ee8307d 100644 --- a/media/audio/win/audio_low_latency_input_win.h +++ b/media/audio/win/audio_low_latency_input_win.h
@@ -58,7 +58,6 @@ #include <Audioclient.h> #include <MMDeviceAPI.h> -#include <dmo.h> #include <endpointvolume.h> #include <stddef.h> #include <stdint.h> @@ -94,12 +93,10 @@ public: // The ctor takes all the usual parameters, plus |manager| which is the // the audio manager who is creating this object. - WASAPIAudioInputStream( - AudioManagerWin* manager, - const AudioParameters& params, - const std::string& device_id, - const AudioManager::LogCallback& log_callback, - AudioManagerBase::VoiceProcessingMode voice_processing_mode); + WASAPIAudioInputStream(AudioManagerWin* manager, + const AudioParameters& params, + const std::string& device_id, + const AudioManager::LogCallback& log_callback); // The dtor is typically called by the AudioManager only and it is usually // triggered by calling AudioInputStream::Close(). @@ -119,27 +116,16 @@ bool started() const { return started_; } private: - // DelegateSimpleThread::Delegate implementation. Calls either - // RunWithAudioCaptureClient() or RunWithDmo(). + // DelegateSimpleThread::Delegate implementation. void Run() override; - // Waits for an event that the audio capture client has data ready. - bool RunWithAudioCaptureClient(); - - // Polls the DMO (voice processing component) for data every 5 ms. - bool RunWithDmo(); - - // Pulls capture data from the audio capture client and pushes it to the sink. + // Pulls capture data from the endpoint device and pushes it to the sink. void PullCaptureDataAndPushToSink(); - // Pulls capture data from the DMO and pushes it to the sink. - void PullDmoCaptureDataAndPushToSink(); - // Issues the OnError() callback to the |sink_|. void HandleError(HRESULT err); - // The Open() method is divided into these sub methods when not using the - // voice processing DMO. + // The Open() method is divided into these sub methods. HRESULT SetCaptureDevice(); HRESULT GetAudioEngineStreamFormat(); // Returns whether the desired format is supported or not and writes the @@ -155,15 +141,6 @@ // the format. void MaybeReportFormatRelatedInitError(HRESULT hr) const; - // The Open() method is divided into these sub methods when using the voice - // processing DMO. In addition, SetupConverterAndStoreFormatInfo() above is - // also called. - bool InitializeDmo(); - bool SetDmoProperties(); - bool SetDmoFormat(); - bool SetDmoDevices(IPropertyStore* ps); - bool CreateDummyRenderClientsForDmo(); - // AudioConverter::InputCallback implementation. double ProvideInput(AudioBus* audio_bus, uint32_t frames_delayed) override; @@ -215,10 +192,10 @@ WAVEFORMATEX output_format_; // Contains the audio format we get data from the audio engine in. Set to - // |output_format_| at construction and might be changed to a close match - // if the audio engine doesn't support the originally set format, or to the - // format the voice capture DMO outputs if it's used. Note that this is also - // the format after the fifo, i.e. the input format to the converter if any. + // |output_format_| at construction and might be changed to a close match if + // the audio engine doesn't support the originally set format. Note that this + // is also the format after the fifo, i.e. the input format to the converter + // if any. WAVEFORMATEX input_format_; bool opened_ = false; @@ -237,8 +214,7 @@ // converter. size_t packet_size_bytes_ = 0; - // Length of the audio endpoint buffer, or the buffer size used for the DMO. - // That is, the buffer size before the fifo. + // Length of the audio endpoint buffer, i.e. the buffer size before the fifo. uint32_t endpoint_buffer_size_frames_ = 0; // Contains the unique name of the selected endpoint device. @@ -246,10 +222,6 @@ // device role and is not a valid ID as such. std::string device_id_; - // Contains the unique name of the output device from which to cancel echo, in - // case voice processing is enabled, i.e. |use_voice_processing_| is true. - std::string output_device_id_for_aec_; - // Pointer to the object that will receive the recorded audio samples. AudioInputCallback* sink_ = nullptr; @@ -325,22 +297,6 @@ UINT64 total_lost_frames_ = 0; UINT64 largest_glitch_frames_ = 0; - // Indicates if the voice processing DMO should be used. - bool use_voice_processing_ = false; - - // The voice processing DMO and its data buffer. - Microsoft::WRL::ComPtr<IMediaObject> voice_capture_dmo_; - Microsoft::WRL::ComPtr<IMediaBuffer> media_buffer_; - - // Dummy rendering when using the DMO. The DMO requires audio rendering to the - // device it's set up to use, otherwise it won't produce any capture audio - // data. Normally, when the DMO is used there's a render stream, but it's not - // guaranteed so we need to support the lack of it. We do this by always - // opening a render client and rendering silence to it when the DMO is - // running. - Microsoft::WRL::ComPtr<IAudioClient> audio_client_for_render_; - Microsoft::WRL::ComPtr<IAudioRenderClient> audio_render_client_; - SEQUENCE_CHECKER(sequence_checker_); DISALLOW_COPY_AND_ASSIGN(WASAPIAudioInputStream);
diff --git a/media/audio/win/audio_low_latency_input_win_unittest.cc b/media/audio/win/audio_low_latency_input_win_unittest.cc index 170d56e..13cf3734 100644 --- a/media/audio/win/audio_low_latency_input_win_unittest.cc +++ b/media/audio/win/audio_low_latency_input_win_unittest.cc
@@ -170,16 +170,11 @@ // also allows the user to modify the default settings. class AudioInputStreamWrapper { public: - explicit AudioInputStreamWrapper(AudioManager* audio_manager, - bool use_voice_processing) + explicit AudioInputStreamWrapper(AudioManager* audio_manager) : audio_man_(audio_manager) { EXPECT_TRUE(SUCCEEDED(CoreAudioUtil::GetPreferredAudioParameters( AudioDeviceDescription::kDefaultDeviceId, false, &default_params_))); EXPECT_EQ(format(), AudioParameters::AUDIO_PCM_LOW_LATENCY); - if (use_voice_processing) { - default_params_.set_effects(default_params_.effects() | - AudioParameters::ECHO_CANCELLER); - } frames_per_buffer_ = default_params_.frames_per_buffer(); } @@ -227,9 +222,8 @@ // Convenience method which creates a default AudioInputStream object. static AudioInputStream* CreateDefaultAudioInputStream( - AudioManager* audio_manager, - bool use_voice_processing) { - AudioInputStreamWrapper aisw(audio_manager, use_voice_processing); + AudioManager* audio_manager) { + AudioInputStreamWrapper aisw(audio_manager); AudioInputStream* ais = aisw.Create(); return ais; } @@ -264,9 +258,7 @@ DISALLOW_COPY_AND_ASSIGN(ScopedAudioInputStream); }; -// The test class. The boolean parameter specifies if voice processing should be -// used. -class WinAudioInputTest : public ::testing::TestWithParam<bool> { +class WinAudioInputTest : public ::testing::Test { public: WinAudioInputTest() { audio_manager_ = @@ -311,16 +303,15 @@ media::AudioDeviceDescriptions device_descriptions; device_info_accessor.GetAudioInputDeviceDescriptions(&device_descriptions); - // All devices in the device description list should have the experimental - // echo canceller capability. + // No device should have any effects. for (const auto& device : device_descriptions) { AudioParameters params = device_info_accessor.GetInputStreamParameters(device.unique_id); - EXPECT_EQ(params.effects(), AudioParameters::EXPERIMENTAL_ECHO_CANCELLER); + EXPECT_EQ(params.effects(), AudioParameters::NO_EFFECTS); } // The two loopback devices are not included in the device description list - // above. They should have no effects. + // above. They should also have no effects. AudioParameters params = device_info_accessor.GetInputStreamParameters( AudioDeviceDescription::kLoopbackInputDeviceId); EXPECT_EQ(params.effects(), AudioParameters::NO_EFFECTS); @@ -331,27 +322,27 @@ } // Test Create(), Close() calling sequence. -TEST_P(WinAudioInputTest, WASAPIAudioInputStreamCreateAndClose) { +TEST_F(WinAudioInputTest, WASAPIAudioInputStreamCreateAndClose) { ABORT_AUDIO_TEST_IF_NOT(HasCoreAudioAndInputDevices(audio_manager_.get())); ScopedAudioInputStream ais( - CreateDefaultAudioInputStream(audio_manager_.get(), GetParam())); + CreateDefaultAudioInputStream(audio_manager_.get())); ais.Close(); } // Test Open(), Close() calling sequence. -TEST_P(WinAudioInputTest, WASAPIAudioInputStreamOpenAndClose) { +TEST_F(WinAudioInputTest, WASAPIAudioInputStreamOpenAndClose) { ABORT_AUDIO_TEST_IF_NOT(HasCoreAudioAndInputDevices(audio_manager_.get())); ScopedAudioInputStream ais( - CreateDefaultAudioInputStream(audio_manager_.get(), GetParam())); + CreateDefaultAudioInputStream(audio_manager_.get())); EXPECT_TRUE(ais->Open()); ais.Close(); } // Test Open(), Start(), Close() calling sequence. -TEST_P(WinAudioInputTest, WASAPIAudioInputStreamOpenStartAndClose) { +TEST_F(WinAudioInputTest, WASAPIAudioInputStreamOpenStartAndClose) { ABORT_AUDIO_TEST_IF_NOT(HasCoreAudioAndInputDevices(audio_manager_.get())); ScopedAudioInputStream ais( - CreateDefaultAudioInputStream(audio_manager_.get(), GetParam())); + CreateDefaultAudioInputStream(audio_manager_.get())); EXPECT_TRUE(ais->Open()); MockAudioInputCallback sink; ais->Start(&sink); @@ -359,10 +350,10 @@ } // Test Open(), Start(), Stop(), Close() calling sequence. -TEST_P(WinAudioInputTest, WASAPIAudioInputStreamOpenStartStopAndClose) { +TEST_F(WinAudioInputTest, WASAPIAudioInputStreamOpenStartStopAndClose) { ABORT_AUDIO_TEST_IF_NOT(HasCoreAudioAndInputDevices(audio_manager_.get())); ScopedAudioInputStream ais( - CreateDefaultAudioInputStream(audio_manager_.get(), GetParam())); + CreateDefaultAudioInputStream(audio_manager_.get())); EXPECT_TRUE(ais->Open()); MockAudioInputCallback sink; ais->Start(&sink); @@ -371,10 +362,10 @@ } // Test some additional calling sequences. -TEST_P(WinAudioInputTest, WASAPIAudioInputStreamMiscCallingSequences) { +TEST_F(WinAudioInputTest, WASAPIAudioInputStreamMiscCallingSequences) { ABORT_AUDIO_TEST_IF_NOT(HasCoreAudioAndInputDevices(audio_manager_.get())); ScopedAudioInputStream ais( - CreateDefaultAudioInputStream(audio_manager_.get(), GetParam())); + CreateDefaultAudioInputStream(audio_manager_.get())); // Open(), Open() should fail the second time. EXPECT_TRUE(ais->Open()); @@ -396,7 +387,7 @@ ais.Close(); } -TEST_P(WinAudioInputTest, WASAPIAudioInputStreamTestPacketSizes) { +TEST_F(WinAudioInputTest, WASAPIAudioInputStreamTestPacketSizes) { ABORT_AUDIO_TEST_IF_NOT(HasCoreAudioAndInputDevices(audio_manager_.get())); int count = 0; @@ -405,7 +396,7 @@ // Create default WASAPI input stream which records in stereo using // the shared mixing rate. The default buffer size is 10ms. - AudioInputStreamWrapper aisw(audio_manager_.get(), GetParam()); + AudioInputStreamWrapper aisw(audio_manager_.get()); ScopedAudioInputStream ais(aisw.Create()); EXPECT_TRUE(ais->Open()); @@ -479,7 +470,7 @@ } // Test that we can capture a stream in loopback. -TEST_P(WinAudioInputTest, WASAPIAudioInputStreamLoopback) { +TEST_F(WinAudioInputTest, WASAPIAudioInputStreamLoopback) { AudioDeviceInfoAccessorForTests device_info_accessor(audio_manager_.get()); ABORT_AUDIO_TEST_IF_NOT(device_info_accessor.HasAudioOutputDevices() && CoreAudioUtil::IsSupported()); @@ -513,7 +504,7 @@ // To include disabled tests in test execution, just invoke the test program // with --gtest_also_run_disabled_tests or set the GTEST_ALSO_RUN_DISABLED_TESTS // environment variable to a value greater than 0. -TEST_P(WinAudioInputTest, DISABLED_WASAPIAudioInputStreamRecordToFile) { +TEST_F(WinAudioInputTest, DISABLED_WASAPIAudioInputStreamRecordToFile) { ABORT_AUDIO_TEST_IF_NOT(HasCoreAudioAndInputDevices(audio_manager_.get())); // Name of the output PCM file containing captured data. The output file @@ -521,7 +512,7 @@ // Example of full name: \src\build\Debug\out_stereo_10sec.pcm. const char* file_name = "out_10sec.pcm"; - AudioInputStreamWrapper aisw(audio_manager_.get(), GetParam()); + AudioInputStreamWrapper aisw(audio_manager_.get()); ScopedAudioInputStream ais(aisw.Create()); ASSERT_TRUE(ais->Open()); @@ -535,7 +526,7 @@ ais.Close(); } -TEST_P(WinAudioInputTest, DISABLED_WASAPIAudioInputStreamResampleToFile) { +TEST_F(WinAudioInputTest, DISABLED_WASAPIAudioInputStreamResampleToFile) { ABORT_AUDIO_TEST_IF_NOT(HasCoreAudioAndInputDevices(audio_manager_.get())); // This is basically the same test as WASAPIAudioInputStreamRecordToFile @@ -570,8 +561,6 @@ // Otherwise (e.g. 44.1kHz, 22.05kHz etc) we convert to 48kHz. const int hw_sample_rate = params.sample_rate(); params.Reset(params.format(), test.layout, test.rate, test.frames); - if (GetParam()) - params.set_effects(params.effects() | AudioParameters::ECHO_CANCELLER); std::string file_name(base::StringPrintf( "resampled_10sec_%i_to_%i_%s.pcm", hw_sample_rate, params.sample_rate(), @@ -595,8 +584,4 @@ } } -INSTANTIATE_TEST_CASE_P(/* Intentially left empty */, - WinAudioInputTest, - ::testing::Bool()); - } // namespace media
diff --git a/media/audio/win/audio_manager_win.cc b/media/audio/win/audio_manager_win.cc index 0dd2120f..0d98248 100644 --- a/media/audio/win/audio_manager_win.cc +++ b/media/audio/win/audio_manager_win.cc
@@ -23,7 +23,6 @@ #include "base/strings/string_number_conversions.h" #include "base/win/windows_version.h" #include "media/audio/audio_device_description.h" -#include "media/audio/audio_features.h" #include "media/audio/audio_io.h" #include "media/audio/win/audio_device_listener_win.h" #include "media/audio/win/audio_low_latency_input_win.h" @@ -187,12 +186,6 @@ if (user_buffer_size) parameters.set_frames_per_buffer(user_buffer_size); - if (device_id != AudioDeviceDescription::kLoopbackInputDeviceId && - device_id != AudioDeviceDescription::kLoopbackWithMuteDeviceId) { - parameters.set_effects(parameters.effects() | - AudioParameters::EXPERIMENTAL_ECHO_CANCELLER); - } - return parameters; } @@ -263,14 +256,7 @@ const LogCallback& log_callback) { // Used for both AUDIO_PCM_LOW_LATENCY and AUDIO_PCM_LINEAR. DVLOG(1) << "MakeLowLatencyInputStream: " << device_id; - - VoiceProcessingMode voice_processing_mode = - params.effects() & AudioParameters::ECHO_CANCELLER - ? VoiceProcessingMode::kEnabled - : VoiceProcessingMode::kDisabled; - - return new WASAPIAudioInputStream(this, params, device_id, log_callback, - voice_processing_mode); + return new WASAPIAudioInputStream(this, params, device_id, log_callback); } std::string AudioManagerWin::GetDefaultInputDeviceID() {
diff --git a/media/audio/win/core_audio_util_win.cc b/media/audio/win/core_audio_util_win.cc index b9c47d9a..fc681c8ac 100644 --- a/media/audio/win/core_audio_util_win.cc +++ b/media/audio/win/core_audio_util_win.cc
@@ -902,71 +902,4 @@ return true; } -HRESULT CoreAudioUtil::GetDeviceCollectionIndex(const std::string& device_id, - EDataFlow data_flow, - WORD* index) { - ComPtr<IMMDeviceEnumerator> enumerator = CreateDeviceEnumerator(); - if (!enumerator.Get()) { - DLOG(ERROR) << "Failed to create device enumerator."; - return E_FAIL; - } - - ComPtr<IMMDeviceCollection> device_collection; - HRESULT hr = enumerator->EnumAudioEndpoints(data_flow, DEVICE_STATE_ACTIVE, - &device_collection); - if (FAILED(hr)) { - DLOG(ERROR) << "Failed to get device collection."; - return hr; - } - - UINT number_of_devices = 0; - hr = device_collection->GetCount(&number_of_devices); - if (FAILED(hr)) { - DLOG(ERROR) << "Failed to get device collection count."; - return hr; - } - - ComPtr<IMMDevice> device; - for (WORD i = 0; i < number_of_devices; ++i) { - hr = device_collection->Item(i, &device); - if (FAILED(hr)) { - DLOG(WARNING) << "Failed to get device."; - continue; - } - ScopedCoMem<WCHAR> current_device_id; - hr = device->GetId(¤t_device_id); - if (FAILED(hr)) { - DLOG(WARNING) << "Failed to get device id."; - continue; - } - if (base::UTF16ToUTF8(current_device_id.get()) == device_id) { - *index = i; - return S_OK; - } - } - - DVLOG(1) << "No matching device found."; - return S_FALSE; -} - -HRESULT CoreAudioUtil::SetBoolProperty(IPropertyStore* property_store, - REFPROPERTYKEY key, - VARIANT_BOOL value) { - base::win::ScopedPropVariant pv; - PROPVARIANT* pv_ptr = pv.Receive(); - pv_ptr->vt = VT_BOOL; - pv_ptr->boolVal = value; - return property_store->SetValue(key, pv.get()); -} - -HRESULT CoreAudioUtil::SetVtI4Property(IPropertyStore* property_store, - REFPROPERTYKEY key, - LONG value) { - base::win::ScopedPropVariant pv; - PROPVARIANT* pv_ptr = pv.Receive(); - pv_ptr->vt = VT_I4; - pv_ptr->lVal = value; - return property_store->SetValue(key, pv.get()); -} - } // namespace media
diff --git a/media/audio/win/core_audio_util_win.h b/media/audio/win/core_audio_util_win.h index 6a2b0dab..8a3174b 100644 --- a/media/audio/win/core_audio_util_win.h +++ b/media/audio/win/core_audio_util_win.h
@@ -207,23 +207,6 @@ static bool FillRenderEndpointBufferWithSilence( IAudioClient* client, IAudioRenderClient* render_client); - // Gets the device collection index for the device specified by |device_id|. - // If the device is found in the device collection, the index is written to - // |*index| and S_OK is returned. If the device is not found, S_FALSE is - // returned and |*index| is left unchanged. In case of an error, the error - // result is returned and |*index| is left unchanged. - static HRESULT GetDeviceCollectionIndex(const std::string& device_id, - EDataFlow data_flow, - WORD* index); - - // Sets the property identified by |key| to |value| in |*property_store|. - static HRESULT SetBoolProperty(IPropertyStore* property_store, - REFPROPERTYKEY key, - VARIANT_BOOL value); - static HRESULT SetVtI4Property(IPropertyStore* property_store, - REFPROPERTYKEY key, - LONG value); - private: CoreAudioUtil() {} ~CoreAudioUtil() {}
diff --git a/media/filters/android/video_frame_extractor.cc b/media/filters/android/video_frame_extractor.cc index cdbe3cc..dc1c299 100644 --- a/media/filters/android/video_frame_extractor.cc +++ b/media/filters/android/video_frame_extractor.cc
@@ -76,6 +76,11 @@ } auto packet = ReadVideoFrame(); + if (!packet) { + OnError(); + return; + } + ConvertPacket(packet.get()); NotifyComplete( std::vector<uint8_t>(packet->data, packet->data + packet->size),
diff --git a/media/filters/android/video_frame_extractor_unittest.cc b/media/filters/android/video_frame_extractor_unittest.cc index 549ebb6..91a9bc5 100644 --- a/media/filters/android/video_frame_extractor_unittest.cc +++ b/media/filters/android/video_frame_extractor_unittest.cc
@@ -6,6 +6,8 @@ #include <memory> +#include "base/files/file_util.h" +#include "base/files/scoped_temp_dir.h" #include "base/run_loop.h" #include "base/test/scoped_task_environment.h" #include "base/test/test_mock_time_task_runner.h" @@ -41,36 +43,55 @@ ~VideoFrameExtractorTest() override {} protected: - void SetUp() override { - data_source_ = std::make_unique<FileDataSource>(); + void SetUp() override { ASSERT_TRUE(temp_dir_.CreateUniqueTempDir()); } - CHECK(data_source_->Initialize(GetTestDataFilePath("bear.mp4"))); + ExtractVideoFrameResult ExtractFrame(const base::FilePath& file_path) { + base::File file( + file_path, base::File::Flags::FLAG_OPEN | base::File::Flags::FLAG_READ); + DCHECK(file.IsValid()); + data_source_ = std::make_unique<FileDataSource>(); + CHECK(data_source_->Initialize(file_path)); extractor_ = std::make_unique<VideoFrameExtractor>(data_source_.get()); + + ExtractVideoFrameResult result; + base::RunLoop loop; + extractor_->Start( + base::BindOnce(&OnFrameExtracted, &result, loop.QuitClosure())); + loop.Run(); + return result; } - void TearDown() override { extractor_.reset(); } - - VideoFrameExtractor* extractor() { return extractor_.get(); } + const base::FilePath& temp_dir() const { return temp_dir_.GetPath(); } private: + base::test::ScopedTaskEnvironment scoped_task_environment_; + base::ScopedTempDir temp_dir_; std::unique_ptr<FileDataSource> data_source_; std::unique_ptr<VideoFrameExtractor> extractor_; - base::test::ScopedTaskEnvironment scoped_task_environment_; DISALLOW_COPY_AND_ASSIGN(VideoFrameExtractorTest); }; -// Verifies the encoded video frame is extracted correctly. +// Verifies the encoded video frame can be extracted correctly. TEST_F(VideoFrameExtractorTest, ExtractVideoFrame) { - ExtractVideoFrameResult result; - base::RunLoop loop; - extractor()->Start( - base::BindOnce(&OnFrameExtracted, &result, loop.QuitClosure())); - loop.Run(); + auto result = ExtractFrame(GetTestDataFilePath("bear.mp4")); EXPECT_TRUE(result.success); EXPECT_GT(result.encoded_frame.size(), 0u); EXPECT_EQ(result.decoder_config.codec(), VideoCodec::kCodecH264); } +// Verifies graceful failure when trying to extract frame from an invalid video +// file. +TEST_F(VideoFrameExtractorTest, ExtractInvalidVideoFile) { + // Creates a dummy video file, frame extraction should fail. + base::FilePath file = temp_dir().AppendASCII("test.txt"); + EXPECT_GT(base::WriteFile(file, "123", sizeof("123")), 0); + + auto result = ExtractFrame(file); + EXPECT_FALSE(result.success); + EXPECT_EQ(result.encoded_frame.size(), 0u); + EXPECT_FALSE(result.decoder_config.IsValidConfig()); +} + } // namespace } // namespace media
diff --git a/services/network/cors/cors_url_loader.cc b/services/network/cors/cors_url_loader.cc index e4931a6..b7b56a5e 100644 --- a/services/network/cors/cors_url_loader.cc +++ b/services/network/cors/cors_url_loader.cc
@@ -334,7 +334,11 @@ DCHECK(network_loader_); DCHECK(forwarding_client_); DCHECK(!is_waiting_follow_redirect_call_); - HandleComplete(status); + + URLLoaderCompletionStatus modified_status(status); + if (status.error_code == net::OK) + modified_status.cors_preflight_timing_info.swap(preflight_timing_info_); + HandleComplete(modified_status); } void CORSURLLoader::StartRequest() { @@ -384,7 +388,7 @@ // preflight request when |fetch_cors_flag_| is false (e.g., when the origin // of the url is equal to the origin of the request. if (!fetch_cors_flag_ || !NeedsPreflight(request_)) { - StartNetworkRequest(net::OK, base::nullopt); + StartNetworkRequest(net::OK, base::nullopt, base::nullopt); return; } @@ -402,14 +406,18 @@ void CORSURLLoader::StartNetworkRequest( int error_code, - base::Optional<CORSErrorStatus> status) { + base::Optional<CORSErrorStatus> status, + base::Optional<PreflightTimingInfo> preflight_timing_info) { if (error_code != net::OK) { HandleComplete(status ? URLLoaderCompletionStatus(*status) : URLLoaderCompletionStatus(error_code)); return; } - DCHECK(!status); + + if (preflight_timing_info) + preflight_timing_info_.push_back(*preflight_timing_info); + mojom::URLLoaderClientPtr network_client; network_client_binding_.Bind(mojo::MakeRequest(&network_client)); // Binding |this| as an unretained pointer is safe because
diff --git a/services/network/cors/cors_url_loader.h b/services/network/cors/cors_url_loader.h index 2c9e3a4..5d67f84 100644 --- a/services/network/cors/cors_url_loader.h +++ b/services/network/cors/cors_url_loader.h
@@ -10,6 +10,7 @@ #include "mojo/public/cpp/bindings/binding.h" #include "net/traffic_annotation/network_traffic_annotation.h" #include "services/network/public/cpp/cors/cors_error_status.h" +#include "services/network/public/cpp/cors/preflight_timing_info.h" #include "services/network/public/mojom/fetch_api.mojom.h" #include "services/network/public/mojom/url_loader_factory.mojom.h" #include "url/gurl.h" @@ -80,8 +81,10 @@ private: void StartRequest(); - void StartNetworkRequest(int net_error, - base::Optional<CORSErrorStatus> status); + void StartNetworkRequest( + int net_error, + base::Optional<CORSErrorStatus> status, + base::Optional<PreflightTimingInfo> preflight_timing_info); // Called when there is a connection error on the upstream pipe used for the // actual request. @@ -151,6 +154,9 @@ // We need to save this for redirect. net::MutableNetworkTrafficAnnotationTag traffic_annotation_; + // Holds timing info if a preflight was made. + std::vector<PreflightTimingInfo> preflight_timing_info_; + // Outlives |this|. const OriginAccessList* const origin_access_list_;
diff --git a/services/network/cors/preflight_controller.cc b/services/network/cors/preflight_controller.cc index 6f6aad7..3771204 100644 --- a/services/network/cors/preflight_controller.cc +++ b/services/network/cors/preflight_controller.cc
@@ -11,6 +11,7 @@ #include "base/no_destructor.h" #include "base/strings/string_util.h" #include "base/strings/stringprintf.h" +#include "base/time/time.h" #include "net/base/load_flags.h" #include "net/http/http_request_headers.h" #include "services/network/public/cpp/cors/cors.h" @@ -271,7 +272,8 @@ std::move(completion_callback_) .Run(net::ERR_FAILED, - CORSErrorStatus(mojom::CORSError::kPreflightDisallowedRedirect)); + CORSErrorStatus(mojom::CORSError::kPreflightDisallowedRedirect), + base::nullopt); RemoveFromController(); // |this| is deleted here. @@ -281,6 +283,14 @@ const ResourceResponseHead& head) { FinalizeLoader(); + timing_info_.start_time = head.request_start; + timing_info_.finish_time = base::TimeTicks::Now(); + timing_info_.alpn_negotiated_protocol = head.alpn_negotiated_protocol; + timing_info_.connection_info = head.connection_info; + head.headers->GetNormalizedHeader("Timing-Allow-Origin", + &timing_info_.timing_allow_origin); + timing_info_.transfer_size = head.encoded_data_length; + base::Optional<CORSErrorStatus> detected_error_status; std::unique_ptr<PreflightResult> result = CreatePreflightResult( final_url, head, original_request_, tainted_, &detected_error_status); @@ -299,9 +309,12 @@ original_request_.url, std::move(result)); } + base::Optional<PreflightTimingInfo> timing_info; + if (!detected_error_status) + timing_info = std::move(timing_info_); std::move(completion_callback_) .Run(detected_error_status ? net::ERR_FAILED : net::OK, - detected_error_status); + detected_error_status, std::move(timing_info)); RemoveFromController(); // |this| is deleted here. @@ -315,7 +328,7 @@ const int error = loader_->NetError(); DCHECK_NE(error, net::OK); FinalizeLoader(); - std::move(completion_callback_).Run(error, base::nullopt); + std::move(completion_callback_).Run(error, base::nullopt, base::nullopt); RemoveFromController(); // |this| is deleted here. } @@ -337,6 +350,8 @@ // Holds SimpleURLLoader instance for the CORS-preflight request. std::unique_ptr<SimpleURLLoader> loader_; + PreflightTimingInfo timing_info_; + // Holds caller's information. PreflightController::CompletionCallback completion_callback_; const ResourceRequest original_request_; @@ -384,7 +399,7 @@ request.request_initiator->Serialize(), request.url, request.fetch_credentials_mode, request.method, request.headers, request.is_revalidating)) { - std::move(callback).Run(net::OK, base::nullopt); + std::move(callback).Run(net::OK, base::nullopt, base::nullopt); return; }
diff --git a/services/network/cors/preflight_controller.h b/services/network/cors/preflight_controller.h index 9aaa178d..779c8f11 100644 --- a/services/network/cors/preflight_controller.h +++ b/services/network/cors/preflight_controller.h
@@ -17,6 +17,7 @@ #include "services/network/public/cpp/cors/cors_error_status.h" #include "services/network/public/cpp/cors/preflight_cache.h" #include "services/network/public/cpp/cors/preflight_result.h" +#include "services/network/public/cpp/cors/preflight_timing_info.h" #include "services/network/public/cpp/resource_request.h" #include "services/network/public/mojom/fetch_api.mojom.h" #include "services/network/public/mojom/url_loader_factory.mojom.h" @@ -32,8 +33,11 @@ // See also https://crbug.com/803766 to check a design doc. class COMPONENT_EXPORT(NETWORK_SERVICE) PreflightController final { public: + // PreflightTimingInfo is provided only when a preflight request was made. using CompletionCallback = - base::OnceCallback<void(int, base::Optional<CORSErrorStatus>)>; + base::OnceCallback<void(int net_error, + base::Optional<CORSErrorStatus>, + base::Optional<PreflightTimingInfo>)>; // Creates a CORS-preflight ResourceRequest for a specified |request| for a // URL that is originally requested. static std::unique_ptr<ResourceRequest> CreatePreflightRequestForTesting(
diff --git a/services/network/cors/preflight_controller_unittest.cc b/services/network/cors/preflight_controller_unittest.cc index e2f2e85..a300222 100644 --- a/services/network/cors/preflight_controller_unittest.cc +++ b/services/network/cors/preflight_controller_unittest.cc
@@ -18,6 +18,7 @@ #include "net/traffic_annotation/network_traffic_annotation_test_helper.h" #include "services/network/network_service.h" #include "services/network/public/cpp/cors/cors.h" +#include "services/network/public/cpp/cors/preflight_timing_info.h" #include "services/network/public/mojom/network_service.mojom.h" #include "services/network/public/mojom/url_loader_factory.mojom.h" #include "testing/gtest/include/gtest/gtest.h" @@ -199,8 +200,10 @@ } protected: - void HandleRequestCompletion(int net_error, - base::Optional<CORSErrorStatus> status) { + void HandleRequestCompletion( + int net_error, + base::Optional<CORSErrorStatus> status, + base::Optional<PreflightTimingInfo> timing_info) { net_error_ = net_error; status_ = status; run_loop_->Quit();
diff --git a/services/network/public/cpp/BUILD.gn b/services/network/public/cpp/BUILD.gn index 0a6c0ed..5086f0b 100644 --- a/services/network/public/cpp/BUILD.gn +++ b/services/network/public/cpp/BUILD.gn
@@ -84,6 +84,8 @@ sources = [ "cors/cors_error_status.cc", "cors/cors_error_status.h", + "cors/preflight_timing_info.cc", + "cors/preflight_timing_info.h", "data_element.cc", "data_element.h", "http_raw_request_response_info.cc",
diff --git a/services/network/public/cpp/cors/preflight_timing_info.cc b/services/network/public/cpp/cors/preflight_timing_info.cc new file mode 100644 index 0000000..2691e8c9 --- /dev/null +++ b/services/network/public/cpp/cors/preflight_timing_info.cc
@@ -0,0 +1,26 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "services/network/public/cpp/cors/preflight_timing_info.h" + +namespace network { + +namespace cors { + +PreflightTimingInfo::PreflightTimingInfo() = default; +PreflightTimingInfo::PreflightTimingInfo(const PreflightTimingInfo& info) = + default; +PreflightTimingInfo::~PreflightTimingInfo() = default; + +bool PreflightTimingInfo::operator==(const PreflightTimingInfo& rhs) const { + return start_time == rhs.start_time && finish_time == rhs.finish_time && + alpn_negotiated_protocol == rhs.alpn_negotiated_protocol && + connection_info == rhs.connection_info && + timing_allow_origin == rhs.timing_allow_origin && + transfer_size == rhs.transfer_size; +} + +} // namespace cors + +} // namespace network
diff --git a/services/network/public/cpp/cors/preflight_timing_info.h b/services/network/public/cpp/cors/preflight_timing_info.h new file mode 100644 index 0000000..a59c56f9 --- /dev/null +++ b/services/network/public/cpp/cors/preflight_timing_info.h
@@ -0,0 +1,43 @@ +// 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 SERVICES_NETWORK_PUBLIC_CPP_CORS_PREFLIGHT_TIMING_INFO_H_ +#define SERVICES_NETWORK_PUBLIC_CPP_CORS_PREFLIGHT_TIMING_INFO_H_ + +#include <string> + +#include "base/component_export.h" +#include "base/memory/scoped_refptr.h" +#include "net/http/http_response_headers.h" +#include "net/http/http_response_info.h" +#include "services/network/public/mojom/cors.mojom-shared.h" + +namespace network { + +namespace cors { + +// Stores performance monitoring information for CORS preflight requests that +// are made in the NetworkService. Will be used to carry information from the +// NetworkService to call sites via URLLoaderCompletionStatus. +struct COMPONENT_EXPORT(NETWORK_CPP_BASE) PreflightTimingInfo { + PreflightTimingInfo(); + PreflightTimingInfo(const PreflightTimingInfo& info); + ~PreflightTimingInfo(); + + base::TimeTicks start_time; + base::TimeTicks finish_time; + std::string alpn_negotiated_protocol; + net::HttpResponseInfo::ConnectionInfo connection_info = + net::HttpResponseInfo::CONNECTION_INFO_UNKNOWN; + std::string timing_allow_origin; + uint64_t transfer_size = 0; + + bool operator==(const PreflightTimingInfo& rhs) const; +}; + +} // namespace cors + +} // namespace network + +#endif // SERVICES_NETWORK_PUBLIC_CPP_CORS_PREFLIGHT_TIMING_INFO_H_
diff --git a/services/network/public/cpp/network_ipc_param_traits.h b/services/network/public/cpp/network_ipc_param_traits.h index 5b97007d..9dc08eaabb 100644 --- a/services/network/public/cpp/network_ipc_param_traits.h +++ b/services/network/public/cpp/network_ipc_param_traits.h
@@ -112,11 +112,21 @@ IPC_STRUCT_TRAITS_MEMBER(failed_parameter) IPC_STRUCT_TRAITS_END() +IPC_STRUCT_TRAITS_BEGIN(network::cors::PreflightTimingInfo) + IPC_STRUCT_TRAITS_MEMBER(start_time) + IPC_STRUCT_TRAITS_MEMBER(finish_time) + IPC_STRUCT_TRAITS_MEMBER(alpn_negotiated_protocol) + IPC_STRUCT_TRAITS_MEMBER(connection_info) + IPC_STRUCT_TRAITS_MEMBER(timing_allow_origin) + IPC_STRUCT_TRAITS_MEMBER(transfer_size) +IPC_STRUCT_TRAITS_END() + IPC_STRUCT_TRAITS_BEGIN(network::URLLoaderCompletionStatus) IPC_STRUCT_TRAITS_MEMBER(error_code) IPC_STRUCT_TRAITS_MEMBER(extended_error_code) IPC_STRUCT_TRAITS_MEMBER(exists_in_cache) IPC_STRUCT_TRAITS_MEMBER(completion_time) + IPC_STRUCT_TRAITS_MEMBER(cors_preflight_timing_info) IPC_STRUCT_TRAITS_MEMBER(encoded_data_length) IPC_STRUCT_TRAITS_MEMBER(encoded_body_length) IPC_STRUCT_TRAITS_MEMBER(decoded_body_length)
diff --git a/services/network/public/cpp/url_loader_completion_status.cc b/services/network/public/cpp/url_loader_completion_status.cc index 32004ff..4a6d60d 100644 --- a/services/network/public/cpp/url_loader_completion_status.cc +++ b/services/network/public/cpp/url_loader_completion_status.cc
@@ -29,6 +29,7 @@ extended_error_code == rhs.extended_error_code && exists_in_cache == rhs.exists_in_cache && completion_time == rhs.completion_time && + cors_preflight_timing_info == rhs.cors_preflight_timing_info && encoded_data_length == rhs.encoded_data_length && encoded_body_length == rhs.encoded_body_length && decoded_body_length == rhs.decoded_body_length &&
diff --git a/services/network/public/cpp/url_loader_completion_status.h b/services/network/public/cpp/url_loader_completion_status.h index 3897f29..6e243cb 100644 --- a/services/network/public/cpp/url_loader_completion_status.h +++ b/services/network/public/cpp/url_loader_completion_status.h
@@ -13,6 +13,7 @@ #include "base/time/time.h" #include "net/ssl/ssl_info.h" #include "services/network/public/cpp/cors/cors_error_status.h" +#include "services/network/public/cpp/cors/preflight_timing_info.h" #include "services/network/public/mojom/cors.mojom-shared.h" namespace network { @@ -48,6 +49,9 @@ // Time the request completed. base::TimeTicks completion_time; + // Timing info if CORS preflights were made. + std::vector<cors::PreflightTimingInfo> cors_preflight_timing_info; + // Total amount of data received from the network. int64_t encoded_data_length = 0;
diff --git a/skia/config/SkUserConfig.h b/skia/config/SkUserConfig.h index 3a18479..684cd62 100644 --- a/skia/config/SkUserConfig.h +++ b/skia/config/SkUserConfig.h
@@ -168,6 +168,8 @@ #define SK_SUPPORT_LEGACY_AAA_CHOICE #endif +#define SK_LEGACY_XFORM_CANVAS_IN_PICTURE_IMAGES + ///////////////////////// Imported from BUILD.gn and skia_common.gypi /* In some places Skia can use static initializers for global initialization,
diff --git a/testing/buildbot/filters/mojo.fyi.network_webview_instrumentation_test_apk.filter b/testing/buildbot/filters/mojo.fyi.network_webview_instrumentation_test_apk.filter index 303028a..0eac070 100644 --- a/testing/buildbot/filters/mojo.fyi.network_webview_instrumentation_test_apk.filter +++ b/testing/buildbot/filters/mojo.fyi.network_webview_instrumentation_test_apk.filter
@@ -5,11 +5,19 @@ # These tests currently fail when run with --enable-features=NetworkService # Uncategorized timeouts or test failures. + +# https://crbug.com/882650 (NS OOP) -*__multiprocess_mode + +# https://crbug.com/893561 -org.chromium.android_webview.test.AcceptLanguageTest.testAcceptLanguage + +# https://crbug.com/893562 -org.chromium.android_webview.test.AwContentsClientAutoLoginTest.testAutoLoginOnGoogleCom -org.chromium.android_webview.test.AwContentsClientAutoLoginTest.testAutoLoginOnNonGoogle -org.chromium.android_webview.test.AwContentsClientAutoLoginTest.testAutoLoginWithNullAccount + +# https://crbug.com/893563 -org.chromium.android_webview.test.AwContentsClientFullScreenTest.testFullscreenNotSupported_video -org.chromium.android_webview.test.AwContentsClientFullScreenTest.testFullscreenNotSupported_videoInsideDiv -org.chromium.android_webview.test.AwContentsClientFullScreenTest.testOnShowCustomViewAndPlayWithHtmlControl_video @@ -18,7 +26,11 @@ -org.chromium.android_webview.test.AwContentsClientFullScreenTest.testPowerSaveBlockerIsEnabledDuringFullscreenPlayback_video -org.chromium.android_webview.test.AwContentsClientFullScreenTest.testPowerSaveBlockerIsEnabledDuringFullscreenPlayback_videoInsideDiv -org.chromium.android_webview.test.AwContentsClientFullScreenTest.testPowerSaveBlockerIsTransferredToEmbedded + +# https://crbug.com/893564 -org.chromium.android_webview.test.AwContentsClientGetDefaultVideoPosterTest.testGetDefaultVideoPoster + +# https://crbug.com/893566 -org.chromium.android_webview.test.AwContentsClientShouldInterceptRequestTest.testBaseUrlOfLoadDataSentInRefererHeader -org.chromium.android_webview.test.AwContentsClientShouldInterceptRequestTest.testCalledForExistingFiles -org.chromium.android_webview.test.AwContentsClientShouldInterceptRequestTest.testCalledForIframe @@ -55,15 +67,23 @@ -org.chromium.android_webview.test.AwContentsClientShouldInterceptRequestTest.testNullInputStreamCausesErrorForMainFrame -org.chromium.android_webview.test.AwContentsClientShouldInterceptRequestTest.testOnLoadResourceCalledWithCorrectUrl -org.chromium.android_webview.test.AwContentsClientShouldInterceptRequestTest.testOnReceivedErrorCallback + +# https://crbug.com/893567 -org.chromium.android_webview.test.AwContentsClientShouldOverrideUrlLoadingTest.testCalledForIframeUnsupportedSchemeNavigations -org.chromium.android_webview.test.AwContentsClientShouldOverrideUrlLoadingTest.testWindowOpenCustomSchemeUrlInPopup -org.chromium.android_webview.test.AwContentsClientShouldOverrideUrlLoadingTest.testWindowOpenHttpUrlInPopup -org.chromium.android_webview.test.AwContentsClientShouldOverrideUrlLoadingTest.testWindowOpenHttpUrlInPopupAddsTrailingSlash + +# https://crbug.com/893568 -org.chromium.android_webview.test.AwContentsTest.testCanInjectHeaders -org.chromium.android_webview.test.AwContentsTest.testDownload -org.chromium.android_webview.test.AwContentsTest.testEscapingOfErrorPage + +# https://crbug.com/893569 -org.chromium.android_webview.test.AwServiceWorkerClientTest.testFetchResourceLoadingError -org.chromium.android_webview.test.AwServiceWorkerClientTest.testInvokeInterceptCallback + +# https://crbug.com/893570 -org.chromium.android_webview.test.AwSettingsTest.testAssetUrl -org.chromium.android_webview.test.AwSettingsTest.testBlockNetworkLoadsWithAudio -org.chromium.android_webview.test.AwSettingsTest.testBlockNetworkLoadsWithHttpResources @@ -76,7 +96,11 @@ -org.chromium.android_webview.test.AwSettingsTest.testFileUrlAccessToggleDoesNotBlockResourceUrls -org.chromium.android_webview.test.AwSettingsTest.testFileUrlAccessWithTwoViews -org.chromium.android_webview.test.AwSettingsTest.testResourceUrl + +# https://crbug.com/893572 -org.chromium.android_webview.test.ClientOnPageStartedTest.testOnPageStartedCalledOnceOnError + +# https://crbug.com/893573 -org.chromium.android_webview.test.ClientOnReceivedError2Test.testIframeSubresource -org.chromium.android_webview.test.ClientOnReceivedError2Test.testImageSubresource -org.chromium.android_webview.test.ClientOnReceivedError2Test.testMainFrame @@ -87,18 +111,26 @@ -org.chromium.android_webview.test.ClientOnReceivedError2Test.testOnNonExistentResourceUrl -org.chromium.android_webview.test.ClientOnReceivedError2Test.testUserGesture -org.chromium.android_webview.test.ClientOnReceivedError2Test.testUserGestureForIframeSubresource + +# https://crbug.com/893574 -org.chromium.android_webview.test.ClientOnReceivedErrorTest.testCacheMiss -org.chromium.android_webview.test.ClientOnReceivedErrorTest.testNonExistentAssetUrl -org.chromium.android_webview.test.ClientOnReceivedErrorTest.testNonExistentResourceUrl -org.chromium.android_webview.test.ClientOnReceivedErrorTest.testOnReceivedErrorOnInvalidScheme -org.chromium.android_webview.test.ClientOnReceivedErrorTest.testOnReceivedErrorOnInvalidUrl + +# https://crbug.com/891722 -org.chromium.android_webview.test.ClientOnReceivedHttpErrorTest.testAfterRedirect -org.chromium.android_webview.test.ClientOnReceivedHttpErrorTest.testForMainResource -org.chromium.android_webview.test.ClientOnReceivedHttpErrorTest.testForSubresource -org.chromium.android_webview.test.ClientOnReceivedHttpErrorTest.testForUserGesture -org.chromium.android_webview.test.ClientOnReceivedHttpErrorTest.testNotCalledIfNoHttpError + +# https://crbug.com/893575 -org.chromium.android_webview.test.CookieManagerStartupTest.testShouldInterceptRequestDeadlock -org.chromium.android_webview.test.CookieManagerStartupTest.testStartup + +# https://crbug.com/893576 -org.chromium.android_webview.test.CookieManagerTest.testAcceptCookie -org.chromium.android_webview.test.CookieManagerTest.testAcceptFileSchemeCookies -org.chromium.android_webview.test.CookieManagerTest.testRejectFileSchemeCookies @@ -106,27 +138,44 @@ -org.chromium.android_webview.test.CookieManagerTest.testThirdPartyCookieForWebSocketEnabledCase -org.chromium.android_webview.test.CookieManagerTest.testThirdPartyCookiesArePerWebview -org.chromium.android_webview.test.CookieManagerTest.testThirdPartyJavascriptCookie + +# https://crbug.com/893577 -org.chromium.android_webview.test.HttpCacheTest.testHttpCacheIsInsideCacheDir + +# https://crbug.com/893579 -org.chromium.android_webview.test.KeySystemTest.testNotSupportFooKeySystem -org.chromium.android_webview.test.KeySystemTest.testSupportClearKeySystem -org.chromium.android_webview.test.KeySystemTest.testSupportPlatformKeySystemNoPrefix + +# https://crbug.com/893580 -org.chromium.android_webview.test.LoadDataWithBaseUrlTest.testLoadDataWithBaseUrlAccessingFile -org.chromium.android_webview.test.LoadDataWithBaseUrlTest.testSetCookieInIframe -org.chromium.android_webview.test.LoadDataWithBaseUrlTest.testThirdPartyCookieInIframe + +# https://crbug.com/893581 -org.chromium.android_webview.test.LoadUrlTest.testLoadUrlWithExtraHeaders -org.chromium.android_webview.test.LoadUrlTest.testRedirectAndReloadWithExtraHeaders -org.chromium.android_webview.test.LoadUrlTest.testReloadWithExtraHeaders -org.chromium.android_webview.test.LoadUrlTest.testRendererNavigationAndGoBackWithExtraHeaders + +# https://crbug.com/893582 -org.chromium.android_webview.test.SafeBrowsingTest.testSafeBrowsingDontProceedCausesNetworkErrorForMainFrame -org.chromium.android_webview.test.SafeBrowsingTest.testSafeBrowsingHardcodedMalwareUrl -org.chromium.android_webview.test.SafeBrowsingTest.testSafeBrowsingHardcodedPhishingUrl -org.chromium.android_webview.test.SafeBrowsingTest.testSafeBrowsingOnSafeBrowsingHitBackToSafety -org.chromium.android_webview.test.SafeBrowsingTest.testSafeBrowsingShowsNetworkErrorForInvisibleViews + +# https://crbug.com/893583 -org.chromium.android_webview.test.VisualStateTest.testOnPageCommitVisible -org.chromium.android_webview.test.VisualStateTest.testVisualStateCallbackFromJsDuringFullscreenTransitions -org.chromium.android_webview.test.VisualStateTest.testVisualStateCallbackWaitsForJs -org.chromium.android_webview.test.VisualStateTest.testVisualStateCallbackWhenContainerViewDetached + +# https://crbug.com/893584 -org.chromium.android_webview.test.WebKitHitTestTest.testSrcEmailType -org.chromium.android_webview.test.WebKitHitTestTest.testSrcGeoType -org.chromium.android_webview.test.WebKitHitTestTest.testSrcPhoneType + +# https://crbug.com/893585 -org.chromium.android_webview.test.WebViewWebVrTest.testWebVrNotFunctional +
diff --git a/testing/buildbot/filters/webui_polymer2_interactive_ui_tests.filter b/testing/buildbot/filters/webui_polymer2_interactive_ui_tests.filter index f5e9158f..53d6a30 100644 --- a/testing/buildbot/filters/webui_polymer2_interactive_ui_tests.filter +++ b/testing/buildbot/filters/webui_polymer2_interactive_ui_tests.filter
@@ -25,10 +25,6 @@ CrSettingsAnimatedPagesTest.All CrSettingsFocusRowBehavior.FocusTest CrSettingsSyncPageTest.All -LoginUITest.PRE_InterruptedAutoStartEnrollment -LoginUITest.InterruptedAutoStartEnrollment -LoginUITest.PRE_LoginNoExceptions -LoginUITest.LoginNoExceptions MaterialBookmarksFocusTest.All MaterialHistoryFocusTest.All PrintPreviewDestinationDialogInteractiveTest.*
diff --git a/testing/variations/fieldtrial_testing_config.json b/testing/variations/fieldtrial_testing_config.json index 944357d..7fddb11 100644 --- a/testing/variations/fieldtrial_testing_config.json +++ b/testing/variations/fieldtrial_testing_config.json
@@ -2415,21 +2415,6 @@ ] } ], - "MacV2Sandbox": [ - { - "platforms": [ - "mac" - ], - "experiments": [ - { - "name": "Enabled", - "enable_features": [ - "MacV2Sandbox" - ] - } - ] - } - ], "MediaFoundationH264Encoding": [ { "platforms": [
diff --git a/third_party/WebKit/LayoutTests/FlagExpectations/enable-slimming-paint-v2 b/third_party/WebKit/LayoutTests/FlagExpectations/enable-slimming-paint-v2 index 05f7c4de8..8acbab2 100644 --- a/third_party/WebKit/LayoutTests/FlagExpectations/enable-slimming-paint-v2 +++ b/third_party/WebKit/LayoutTests/FlagExpectations/enable-slimming-paint-v2
@@ -115,9 +115,6 @@ Bug(none) compositing/3d-cube.html [ Failure ] Bug(none) compositing/absolute-inside-out-of-view-fixed.html [ Failure ] Bug(none) compositing/animation/hidden-composited.html [ Failure ] -Bug(none) compositing/backface-visibility/backface-visibility-image.html [ Failure ] -Bug(none) compositing/backface-visibility/backface-visibility-webgl.html [ Failure ] -Bug(none) compositing/canvas-with-object-fit-contain-in-composited-layer.html [ Failure ] Bug(none) compositing/change-preferCompositingToLCDText-setting.html [ Failure ] Bug(none) compositing/color-matching/image-color-matching.html [ Failure ] Bug(none) compositing/columns/composited-in-paginated.html [ Failure Crash ] @@ -137,7 +134,6 @@ Bug(none) compositing/filters/sw-nested-shadow-overlaps-hw-nested-shadow.html [ Failure Crash ] Bug(none) compositing/filters/sw-shadow-overlaps-hw-layer.html [ Failure Crash ] Bug(none) compositing/filters/sw-shadow-overlaps-hw-shadow.html [ Failure Crash ] -Bug(none) compositing/fixed-background-after-style-recalc.html [ Failure ] Bug(none) compositing/fixed-body-background-positioned.html [ Failure ] Bug(none) compositing/fixed-position-changed-to-absolute.html [ Failure ] Bug(none) compositing/flat-with-transformed-child.html [ Failure ] @@ -322,21 +318,13 @@ Bug(none) compositing/overflow/universal-accelerated-overflow-scroll.html [ Failure ] Bug(none) compositing/overlap-blending/reflection-opacity-huge.html [ Failure Crash ] Bug(none) compositing/perpendicular-layer-sorting.html [ Failure ] -Bug(none) compositing/plugins/webplugin-reflection.html [ Failure Crash ] -Bug(none) compositing/reflections/animation-inside-reflection.html [ Failure Crash ] -Bug(none) compositing/reflections/compositing-change-inside-reflection.html [ Failure Crash ] Bug(none) compositing/reflections/deeply-nested-reflections.html [ Failure Crash ] Bug(none) compositing/reflections/load-video-in-reflection.html [ Failure Crash ] Bug(none) compositing/reflections/nested-reflection-anchor-point.html [ Failure Crash ] Bug(none) compositing/reflections/nested-reflection-animated.html [ Failure Crash ] Bug(none) compositing/reflections/nested-reflection-mask-change.html [ Failure Crash ] -Bug(none) compositing/reflections/nested-reflection-on-overflow.html [ Failure Crash ] Bug(none) compositing/reflections/nested-reflection-opacity.html [ Failure Crash ] -Bug(none) compositing/reflections/nested-reflection-size-change.html [ Failure Crash ] -Bug(none) compositing/reflections/nested-reflection-transition.html [ Failure Crash ] -Bug(none) compositing/reflections/nested-reflection.html [ Failure Crash ] Bug(none) compositing/reflections/reflection-in-composited.html [ Failure Crash ] -Bug(none) compositing/reflections/transform-inside-reflection.html [ Failure Crash ] Bug(none) compositing/rtl/rtl-absolute-overflow-scrolled.html [ Failure Crash ] Bug(none) compositing/rtl/rtl-absolute-overflow.html [ Failure Crash ] Bug(none) compositing/rtl/rtl-fixed-overflow-scrolled.html [ Failure Crash ] @@ -389,13 +377,12 @@ Bug(none) compositing/video/video-controls-layer-creation-squashing.html [ Crash Failure ] Bug(none) compositing/video/video-controls-layer-creation.html [ Crash Failure ] Bug(none) compositing/video/video-poster.html [ Crash Failure ] -Bug(none) compositing/video/video-reflection.html [ Crash Failure ] Bug(none) compositing/visibility/layer-visible-content.html [ Failure ] Bug(none) compositing/visibility/overlays.html [ Failure Crash ] Bug(none) compositing/visibility/visibility-image-layers-dynamic.html [ Crash Failure ] Bug(none) compositing/visibility/visibility-image-layers.html [ Failure ] Bug(none) compositing/visibility/visibility-simple-video-layer.html [ Failure ] -Bug(none) compositing/webgl/webgl-reflection.html [ Failure Crash ] +Bug(none) compositing/webgl/webgl-reflection.html [ Failure Pass ] Bug(none) compositing/webgl/webgl-with-accelerated-background-color.html [ Failure Pass ] Bug(none) fast/backgrounds/background-inherit-color-bug.html [ Failure ] Bug(none) fast/backgrounds/background-leakage-transforms.html [ Failure ] @@ -429,7 +416,6 @@ Bug(none) fast/box-shadow/basic-shadows.html [ Failure ] Bug(none) fast/box-sizing/box-sizing.html [ Failure ] Bug(none) fast/canvas/canvas-composite-video.html [ Failure ] -Bug(none) fast/canvas/imagebitmap/transferFromImageBitmap-no-alpha.html [ Failure ] Bug(none) fast/canvas/OffscreenCanvas-2d-drawImage-in-worker.html [ Failure ] Bug(none) fast/canvas/OffscreenCanvas-2d-drawImage.html [ Failure ] Bug(none) fast/canvas/OffscreenCanvas-2d-gradients-in-worker.html [ Failure ] @@ -482,18 +468,17 @@ Bug(none) fast/events/touch/compositor-touch-hit-rects-global.html [ Failure Crash ] Bug(none) fast/events/touch/compositor-touch-hit-rects-many.html [ Failure ] Bug(none) fast/events/touch/compositor-touch-hit-rects-non-composited-scroll.html [ Failure ] +Bug(none) fast/events/touch/compositor-touch-hit-rects-non-composited-scroll-overflow-with-handler.html [ Failure ] Bug(none) fast/events/touch/compositor-touch-hit-rects-scroll.html [ Failure ] Bug(none) fast/events/touch/compositor-touch-hit-rects-squashing.html [ Failure ] Bug(none) fast/events/touch/compositor-touch-hit-rects-trigger-commit.html [ Failure ] Bug(none) fast/events/touch/compositor-touch-hit-rects-transform-changed-nolayout.html [ Failure ] +Bug(none) fast/events/touch/compositor-touch-hit-rects-with-negative-child.html [ Failure ] Bug(none) fast/events/touch/compositor-touch-hit-rects.html [ Failure ] Bug(none) fast/events/touch/gesture/gesture-scroll-by-page.html [ Failure ] Bug(none) fast/events/touch/touch-handler-assert-input-range.html [ Failure ] Bug(none) fast/events/touch/touch-rect-assert-first-layer-special.html [ Failure ] Bug(none) fast/events/touch/touch-rect-crash-on-unpromote-layer.html [ Failure ] -Bug(none) fast/events/wheel/wheelevent-in-horizontal-scrollbar-in-rtl.html [ Failure ] -Bug(none) fast/events/wheel/wheelevent-in-vertical-scrollbar-in-rtl.html [ Failure ] -Bug(none) fast/events/wheel/wheelevent-in-scrolling-div.html [ Failure ] Bug(none) fast/forms/button-default-title.html [ Failure ] Bug(none) fast/forms/fieldset/fieldset-align.html [ Failure ] Bug(none) fast/forms/select/listbox-appearance-basic.html [ Failure ] @@ -535,11 +520,8 @@ Bug(none) fast/multicol/composited-relpos-resize.html [ Failure ] Bug(none) fast/multicol/composited-with-child-layer-in-next-column.html [ Failure ] Bug(none) fast/multicol/composited-with-overflow-in-next-column.html [ Failure ] -Bug(none) fast/multicol/fixedpos-in-transform-at-column-boundary.html [ Crash ] Bug(none) fast/multicol/insane-column-count-and-padding-nested-crash.html [ Crash ] Bug(none) fast/multicol/mixed-opacity-test.html [ Failure ] -Bug(none) fast/multicol/nested-and-unbreakable-crash.html [ Crash ] -Bug(none) fast/multicol/overflow-unsplittable.html [ Failure ] Bug(none) fast/multicol/span/invalid-spanner-in-transform.html [ Failure ] Bug(none) fast/multicol/vertical-lr/composited-relpos-overlapping-will-change.html [ Failure ] Bug(none) fast/multicol/vertical-rl/composited-relpos-overlapping-will-change.html [ Failure ] @@ -553,7 +535,6 @@ Bug(none) fast/selectors/166.html [ Failure ] Bug(none) fast/sub-pixel/repaint-subpixel-layer-in-subpixel-composited-layer.html [ Failure ] Bug(none) fast/sub-pixel/should-not-repaint-subpixel-composited-layer.html [ Failure ] -Bug(none) fast/sub-pixel/sub-pixel-transparency-layer.html [ Failure ] Bug(none) fast/sub-pixel/transformed-iframe-copy-on-scroll.html [ Failure ] Bug(none) fast/table/023.html [ Failure ] Bug(none) fast/table/027-vertical.html [ Failure ] @@ -602,7 +583,6 @@ Bug(none) fast/table/backgr_simple-table-row.html [ Failure ] Bug(none) fast/table/backgr_simple-table.html [ Failure ] Bug(none) fast/text/capitalize-boundaries.html [ Failure ] -Bug(none) fast/text/selection/emphasis.html [ Failure ] Bug(none) fast/text/font-stretch-variant.html [ Failure ] Bug(none) fast/text/font-weight-variant.html [ Failure ] Bug(none) fast/text/international/bidi-neutral-run.html [ Failure ] @@ -615,8 +595,6 @@ Bug(none) images/cross-fade-invalidation.html [ Crash Failure Pass ] Bug(none) paint/pagination/pagination-change-clip-crash.html [ Failure ] -Bug(none) fast/multicol/input-with-overflow-second-column.html [ Failure ] - # Less invalidations or different invalidations without pixel failures. # Some might be good. Some might be under-invalidations for which under-invalidation # checking failed. @@ -665,7 +643,6 @@ Bug(none) paint/invalidation/scroll/invalidate-after-composited-scroll-of-window.html [ Failure ] Bug(none) paint/invalidation/invalidation-after-opacity-change-subtree.html [ Failure ] Bug(none) paint/invalidation/position/layout-state-only-positioned.html [ Failure ] -Bug(none) paint/invalidation/overflow/opacity-change-on-overflow-float.html [ Failure ] Bug(none) paint/invalidation/position/relative-positioned-movement-repaint.html [ Failure ] Bug(none) paint/invalidation/repaint-across-writing-mode-boundary.html [ Failure ] Bug(none) paint/invalidation/scroll/scroll-fixed-layer-with-transformed-parent-layer.html [ Failure ] @@ -720,12 +697,10 @@ # Other extra layers. Bug(none) compositing/composite-scrollable-fixed-position-when-descendants-composite.html [ Failure ] -Bug(none) paint/invalidation/position/abspos-shift-image-incorrect-repaint.html [ Failure ] Bug(none) paint/invalidation/image/canvas-composite-repaint-by-all-imagesource.html [ Failure ] Bug(none) paint/invalidation/overflow/clipped-overflow-visible-subtree.html [ Failure ] Bug(none) paint/invalidation/compositing/fixed-pos-with-abs-pos-child-scroll.html [ Failure ] Bug(none) paint/invalidation/compositing/should-not-repaint-scrolling-contents-outline-change.html [ Failure ] -Bug(none) paint/invalidation/create-layer-repaint.html [ Failure ] Bug(none) paint/invalidation/filters/filter-on-html-element-with-fixed-position-child.html [ Failure ] Bug(none) paint/invalidation/background/full-viewport-repaint-for-background-attachment-fixed.html [ Failure Crash ] Bug(none) paint/invalidation/scroll/inline-style-change-in-scrolled-view.html [ Failure ] @@ -851,19 +826,14 @@ Bug(none) fast/events/platform-wheelevent-paging-y-in-scrolling-div.html [ Failure ] Bug(none) fast/events/scroll-in-scaled-page-with-overflow-hidden.html [ Failure Crash ] Bug(none) fast/events/scrollbar-double-click.html [ Failure ] -Bug(none) fast/events/wheel/wheelevent-basic.html [ Failure ] Bug(none) fast/forms/suggestion-picker/date-suggestion-picker-mouse-operations.html [ Failure ] Bug(none) fast/forms/suggestion-picker/datetimelocal-suggestion-picker-mouse-operations.html [ Failure ] Bug(none) fast/forms/suggestion-picker/month-suggestion-picker-mouse-operations.html [ Failure ] Bug(none) fast/forms/suggestion-picker/time-suggestion-picker-mouse-operations.html [ Failure ] Bug(none) fast/forms/suggestion-picker/week-suggestion-picker-mouse-operations.html [ Failure ] -Bug(none) fast/scrolling/absolute-position-behind-scrollbar.html [ Failure ] -Bug(none) fast/scrolling/fixed-position-behind-scrollbar.html [ Failure Timeout ] Bug(none) fast/scroll-snap/snaps-after-scrollbar-scrolling.html [ Failure ] Bug(none) fast/events/remove-child-onscroll.html [ Timeout ] -Bug(none) fast/events/mouse-wheel-main-frame-scroll.html [ Timeout ] -Bug(none) fast/scrolling/hover-during-scroll.html [ Timeout ] crbug.com/651292 svg/dynamic-updates/SVGImageElement-dom-x-attr.html [ Pass Failure ] crbug.com/651292 svg/dynamic-updates/SVGImageElement-svgdom-height-prop.html [ Pass Failure ] @@ -876,7 +846,6 @@ crbug.com/651292 svg/dynamic-updates/SVGImageElement-dom-preserveAspectRatio-attr.html [ Pass Failure ] crbug.com/651292 svg/dynamic-updates/SVGImageElement-dom-y-attr.html [ Pass Failure ] -Bug(none) fast/scrolling/overflow-scrollability.html [ Failure ] Bug(none) compositing/lots-of-img-layers-with-opacity.html [ Failure ] Bug(none) compositing/lots-of-img-layers.html [ Failure ] Bug(none) compositing/opacity-with-mask.html [ Failure ] @@ -966,13 +935,11 @@ crbug.com/589265 compositing/masks/masked-ancestor.html [ Failure ] crbug.com/589265 compositing/masks/multiple-masks.html [ Failure ] crbug.com/589265 compositing/masks/simple-composited-mask.html [ Failure ] -crbug.com/589265 compositing/nested-border-radius-composited-child.html [ Failure ] crbug.com/589265 compositing/overflow/border-radius-on-parent-composited-grandchild.html [ Failure ] crbug.com/589265 compositing/overflow/nested-border-radius-clipping.html [ Failure ] crbug.com/589265 fast/borders/border-radius-with-composited-child.html [ Failure ] crbug.com/589265 fast/clip/overflow-border-radius-composited-parent.html [ Failure ] crbug.com/589265 fast/clip/overflow-border-radius-composited.html [ Failure ] -crbug.com/589265 paint/overflow/composited-rounded-clip-floating-element.html [ Failure ] crbug.com/589265 svg/custom/mask-changes.svg [ Failure ] crbug.com/589265 svg/custom/mask-colorspace.svg [ Failure ] @@ -995,9 +962,7 @@ crbug.com/589265 compositing/perspective-interest-rect.html [ Failure ] # Some work remains to fully support composited animation and scrolling. -crbug.com/702350 transitions/opacity-transform-transitions-inside-iframe.html [ Timeout ] crbug.com/702350 virtual/threaded/transitions/opacity-transform-transitions-inside-iframe.html [ Timeout ] -crbug.com/702353 transitions/transition-end-event-destroy-iframe.html [ Timeout ] crbug.com/702353 virtual/threaded/transitions/transition-end-event-destroy-iframe.html [ Timeout ] crbug.com/702365 virtual/threaded/animations/composited-filter-webkit-filter.html [ Failure ] crbug.com/702370 virtual/threaded/animations/compositor-independent-transform-cancel.html [ Failure ] @@ -1008,10 +973,6 @@ # approaches. http://crbug.com/692310#c12 crbug.com/692310 virtual/threaded/animations/composited-animations-rotate-zero-degrees.html [ Pass Failure Timeout ] -# This test uses internal call to initiate smooth scrolling on impl-thread. -crbug.com/667946 fast/compositor-wheel-scroll-latching/animated-scroll/touchpad-scroll-impl-to-main.html [ Failure ] - - # virtual/threaded variants of sub-directories and tests already skipped or marked as failing above. Bug(none) virtual/threaded/http/tests/devtools/ [ Skip ] Bug(none) virtual/threaded/fast/events/pinch/gesture-pinch-zoom-scroll-bubble.html [ Failure Crash ] @@ -1094,7 +1055,6 @@ crbug.com/738613 paint/invalidation/compositing/text-match-highlight.html [ Failure ] crbug.com/738613 paint/invalidation/compositing/updating-scrolling-container-and-content.html [ Failure ] crbug.com/738613 paint/invalidation/compositing/updating-scrolling-container.html [ Failure ] -crbug.com/738613 paint/invalidation/table/dynamic-table-vertical-alignment-change.html [ Failure ] crbug.com/738613 paint/invalidation/line-flow-with-floats-1.html [ Failure ] crbug.com/738613 paint/invalidation/line-flow-with-floats-10.html [ Failure ] crbug.com/738613 paint/invalidation/line-flow-with-floats-2.html [ Failure ] @@ -1107,8 +1067,6 @@ crbug.com/738613 paint/invalidation/line-flow-with-floats-9.html [ Failure ] crbug.com/738613 paint/invalidation/requestAnimation-translation-leave-traces.html [ Failure ] crbug.com/738613 paint/invalidation/overflow/resize-child-within-overflow.html [ Failure ] -crbug.com/738613 paint/invalidation/position/shift-relative-positioned-container-with-image-addition.html [ Failure ] -crbug.com/738613 paint/invalidation/position/shift-relative-positioned-container-with-image-removal.html [ Failure ] crbug.com/738613 paint/invalidation/table/table-shrink-row-repaint.html [ Failure ] crbug.com/738613 paint/invalidation/position/transform-absolute-in-positioned-container.html [ Failure ] crbug.com/738613 paint/invalidation/table/scroll-relative-table-inside-table-cell.html [ Failure ] @@ -1191,10 +1149,7 @@ Bug(none) paint/invalidation/scroll/overflow-scroll-delete.html [ Failure ] Bug(none) paint/invalidation/overflow/vertical-overflow-child.html [ Failure ] Bug(none) fast/forms/textarea/textarea-scrolled-mask.html [ Failure ] -Bug(none) fast/css/sticky/sticky-both-sides-top-left-constrained.html [ Failure ] Bug(none) fast/css/sticky/sticky-vertically-overconstrained.html [ Failure ] -Bug(none) fast/css/sticky/sticky-overflowing.html [ Failure ] -Bug(none) fast/sub-pixel/save-layer-bounds-should-snap.html [ Failure ] # Different layer tree about scrolling layer. Some may also have wrong invalidations. crbug.com/738613 compositing/iframes/connect-compositing-iframe-delayed.html [ Failure ] @@ -1219,14 +1174,6 @@ crbug.com/738613 paint/invalidation/scroll/repaint-composited-child-in-scrolled-container.html [ Failure ] crbug.com/738613 paint/invalidation/scroll/scroll-stacking-context-backface-visiblity-leaves-traces.html [ Failure ] -# Sticky positioned objects are not invalidated when scroll offset changes. -crbug.com/762098 compositing/overflow/composited-nested-sticky-table.html [ Failure ] -crbug.com/762098 compositing/overflow/mixed-composited-nested-sticky-overflow-scroller.html [ Failure ] -crbug.com/762098 compositing/overflow/composited-nested-sticky-left.html [ Failure ] -crbug.com/762098 compositing/overflow/composited-nested-sticky-deep.html [ Failure ] -crbug.com/762098 compositing/overflow/composited-nested-sticky-top.html [ Failure ] -crbug.com/762098 compositing/overflow/non-composited-sticky-element-in-main-thread-scrolled-composited-ancestor.html [ Failure ] - # Subsequence under-invalidation of scroller related to ScrollHitTest. crbug.com/738613 compositing/overflow/overflow-scroll-with-pointer-events-toggle.html [ Failure Crash ] # Null pointer in PaintArtifactCompositor::ScrollHitTestLayerForPendingLayer(). @@ -1242,47 +1189,13 @@ Bug(none) compositing/rendering-contexts.html [ Failure ] Bug(none) compositing/overflow-trumps-transform-style.html [ Failure ] -crbug.com/796768 fast/css/getComputedStyle/getComputedStyle-zoom-and-background-size.html [ Crash ] -crbug.com/796768 fast/multicol/composited-layer-will-change.html [ Failure ] -crbug.com/796768 fast/multicol/hit-test-gap-between-pages-flipped.html [ Crash ] -crbug.com/796768 fast/multicol/hit-test-gap-between-pages.html [ Crash ] -crbug.com/796768 fast/multicol/multicol-becomes-paged-fixed-height.html [ Crash ] -crbug.com/796768 fast/multicol/nested-with-composited-and-multicol-crash.html [ Crash ] -crbug.com/796768 fast/multicol/scrollable-basic.html [ Failure Crash ] -crbug.com/796768 fast/multicol/scrollbar-taller-than-content-box-freeze.html [ Crash ] -crbug.com/796768 fast/multicol/scrolling-column-rules.html [ Crash ] -crbug.com/796768 fast/overflow/hidden-html-paged-body.html [ Crash ] -crbug.com/796768 fast/overflow/scroll-html-paged-body.html [ Crash ] -crbug.com/796768 fast/pagination/auto-height-with-break.html [ Crash ] -crbug.com/796768 fast/pagination/break-in-paged-overflow.html [ Crash ] -crbug.com/796768 fast/pagination/caret-range-outside-paged-x-rtl-vertical-rl.html [ Crash ] -crbug.com/796768 fast/pagination/caret-range-outside-paged-x-rtl.html [ Crash ] -crbug.com/796768 fast/pagination/caret-range-outside-paged-x-vertical-rl.html [ Crash ] -crbug.com/796768 fast/pagination/caret-range-outside-paged-x.html [ Crash ] -crbug.com/796768 fast/pagination/caret-range-outside-paged-y-rtl-vertical-rl.html [ Crash ] -crbug.com/796768 fast/pagination/caret-range-outside-paged-y-rtl.html [ Crash ] -crbug.com/796768 fast/pagination/caret-range-outside-paged-y.html [ Crash ] -crbug.com/796768 fast/pagination/div-make-paginated.html [ Crash ] -crbug.com/796768 fast/pagination/div-x-horizontal-tb-ltr.html [ Crash ] -crbug.com/796768 fast/pagination/div-x-horizontal-tb-rtl.html [ Crash ] -crbug.com/796768 fast/pagination/div-x-vertical-lr-ltr.html [ Crash ] -crbug.com/796768 fast/pagination/div-x-vertical-lr-rtl.html [ Crash ] -crbug.com/796768 fast/pagination/div-x-vertical-rl-ltr.html [ Crash ] -crbug.com/796768 fast/pagination/div-x-vertical-rl-rtl.html [ Crash ] -crbug.com/796768 fast/pagination/div-y-horizontal-tb-ltr.html [ Crash ] -crbug.com/796768 fast/pagination/div-y-horizontal-tb-rtl.html [ Crash ] -crbug.com/796768 fast/pagination/div-y-vertical-lr-ltr.html [ Crash ] -crbug.com/796768 fast/pagination/div-y-vertical-lr-rtl.html [ Crash ] -crbug.com/796768 fast/pagination/div-y-vertical-rl-ltr.html [ Crash ] -crbug.com/796768 fast/pagination/div-y-vertical-rl-rtl.html [ Crash ] -crbug.com/796768 fast/pagination/multicol.html [ Crash ] -crbug.com/796768 fast/pagination/repeating-thead-tfoot-paged-x.html [ Failure ] -crbug.com/796768 fast/pagination/repeating-thead-tfoot-paged-y.html [ Failure ] -crbug.com/796768 fast/pagination/short-pages-tall-content.html [ Crash ] -crbug.com/796768 fast/text-autosizing/constrained-and-overflow-paged-x-ancestor.html [ Crash ] -crbug.com/796768 paint/clipath/change-mask-clip-path-multicol-crash.html [ Crash ] -crbug.com/796768 paint/invalidation/overflow/paged-with-overflowing-block-rl.html [ Failure ] -crbug.com/796768 paint/pagination/composited-paginated-outlined-box.html [ Failure ] +Bug(none) fast/multicol/composited-layer-will-change.html [ Failure ] +Bug(none) fast/pagination/multicol.html [ Crash ] +Bug(none) fast/pagination/repeating-thead-tfoot-paged-x.html [ Failure ] +Bug(none) fast/pagination/repeating-thead-tfoot-paged-y.html [ Failure ] +Bug(none) paint/clipath/change-mask-clip-path-multicol-crash.html [ Crash ] +Bug(none) paint/invalidation/overflow/paged-with-overflowing-block-rl.html [ Failure ] +Bug(none) paint/pagination/composited-paginated-outlined-box.html [ Failure ] Bug(none) css3/blending/mix-blend-mode-simple.html [ Pass Timeout ] Bug(none) css3/blending/mix-blend-mode-simple-text.html [ Pass Timeout ] @@ -1297,7 +1210,6 @@ crbug.com/882075 compositing/overflow/composited-sticky-element-with-non-integer-relative-position-to-container.html [ Failure ] # Failures accumulated during the bot was borrowed by spv175. -Bug(none) compositing/columns/geometry-map-paginated-assert.html [ Crash ] Bug(none) compositing/geometry/fixed-position-composited-page-scale-scroll.html [ Crash ] Bug(none) compositing/geometry/fixed-position-composited-page-scale-smaller-than-viewport.html [ Crash ] Bug(none) compositing/layer-creation/fixed-position-out-of-view-scaled-iframe-scroll.html [ Crash ] @@ -1332,23 +1244,6 @@ Bug(none) fast/events/touch/gesture/touch-gesture-scroll-div-scaled.html [ Crash ] Bug(none) fast/frames/iframe-double-scale-contents.html [ Crash ] Bug(none) fast/history/scroll-restoration/scroll-restoration-scale-not-impacted.html [ Crash ] -Bug(none) fast/pagination/body-make-paginated.html [ Crash ] -Bug(none) fast/pagination/html-make-paginated.html [ Crash ] -Bug(none) fast/pagination/paged-x-column-gap.html [ Crash ] -Bug(none) fast/pagination/paged-x-to-paged-y.html [ Crash ] -Bug(none) fast/pagination/paged-y-to-paged-x.html [ Crash ] -Bug(none) fast/pagination/viewport-x-horizontal-tb-ltr.html [ Crash ] -Bug(none) fast/pagination/viewport-x-horizontal-tb-rtl.html [ Crash ] -Bug(none) fast/pagination/viewport-x-vertical-lr-ltr.html [ Crash ] -Bug(none) fast/pagination/viewport-x-vertical-lr-rtl.html [ Crash ] -Bug(none) fast/pagination/viewport-x-vertical-rl-ltr.html [ Crash ] -Bug(none) fast/pagination/viewport-x-vertical-rl-rtl.html [ Crash ] -Bug(none) fast/pagination/viewport-y-horizontal-tb-ltr.html [ Crash ] -Bug(none) fast/pagination/viewport-y-horizontal-tb-rtl.html [ Crash ] -Bug(none) fast/pagination/viewport-y-vertical-lr-ltr.html [ Crash ] -Bug(none) fast/pagination/viewport-y-vertical-lr-rtl.html [ Crash ] -Bug(none) fast/pagination/viewport-y-vertical-rl-ltr.html [ Crash ] -Bug(none) fast/pagination/viewport-y-vertical-rl-rtl.html [ Crash ] Bug(none) fast/scrolling/editor-command-scroll-page-scale.html [ Crash ] Bug(none) fast/scrolling/keyboard-scroll-page-scale.html [ Crash ] Bug(none) fast/scrolling/same-page-navigate.html [ Crash ] @@ -1357,14 +1252,9 @@ Bug(none) images/server-side-imagemap.html [ Crash ] Bug(none) paint/invalidation/position/fixed-right-in-page-scale.html [ Crash ] Bug(none) svg/as-image/image-respects-pageScaleFactor-change.html [ Crash ] -Bug(none) compositing/fixed-background-composited-html.html [ Failure ] -Bug(none) compositing/fixed-background-negative-z-index-fixed.html [ Failure ] -Bug(none) compositing/layer-creation/iframe-background-attachment-fixed.html [ Failure ] Bug(none) compositing/overflow/ancestor-with-clip-path.html [ Failure ] Bug(none) compositing/overflow/descendant-with-clip-path.html [ Failure ] -Bug(none) compositing/overflow/mixed-composited-nested-sticky.html [ Failure ] Bug(none) fast/css/pseudo-element-selector-scrollbar-hover.html [ Failure ] -Bug(none) fast/css/sticky/sticky-clip-rel-child.html [ Failure ] Bug(none) fast/scrolling/custom-scrollbar-style-applied-with-overflow-attribute.html [ Failure ] Bug(none) paint/invalidation/media-audio-no-spurious-repaints.html [ Failure ] Bug(none) paint/invalidation/subpixel-shadow-included-in-invalidation.html [ Failure ] @@ -1376,12 +1266,8 @@ Bug(none) svg/transforms/text-with-mask-with-svg-transform.svg [ Failure ] crbug.com/833083 paint/invalidation/compositing/composited-layers-move-in-subpixels.html [ Failure ] -crbug.com/837467 paint/invalidation/compositing/end-of-opacity-transition.html [ Failure ] -crbug.com/857322 paint/invalidation/background/obscured-background-no-repaint.html [ Failure Crash ] Bug(none) compositing/squashing/frame-clip-squashed-scrolled.html [ Failure ] -Bug(none) fast/block/positioning/vertical-rl/002.html [ Failure ] -Bug(none) rootscroller/gesture-scroll-document-not-root-scroller.html [ Failure ] Bug(none) fast/scroll-snap/snap-scrolls-visual-viewport.html [ Crash ] Bug(none) paint/invalidation/vertical-align1.html [ Failure ] @@ -1390,11 +1276,6 @@ Bug(none) virtual/threaded/external/wpt/feature-policy/experimental-features/vertical-scroll-touch-action-manual.tentative.html [ Failure ] Bug(none) virtual/threaded/external/wpt/feature-policy/experimental-features/vertical-scroll-touch-block-manual.tentative.html [ Failure ] -Bug(none) virtual/threaded/fast/events/pinch/pinch-zoom-into-center.html [ Pass Failure Crash ] -Bug(none) virtual/threaded/fast/events/pinch/pinch-zoom-pan-position-fixed.html [ Pass Failure Crash ] -Bug(none) virtual/threaded/fast/events/pinch/pinch-zoom-pan-within-zoomed-viewport.html [ Pass Failure Crash ] -Bug(none) compositing/overflow/scrollbar-layer-placement-negative-z-index-child-positioned.html [ Failure ] - Bug(none) fast/events/touch/compositor-touch-hit-rects-svg.html [ Failure ] Bug(none) virtual/paint-touchaction-rects/fast/events/touch/compositor-touch-hit-rects-svg.html [ Failure ] Bug(none) fast/events/touch/compositor-touch-hit-rects-continuation.html [ Failure ] @@ -1409,7 +1290,6 @@ Bug(none) virtual/paint-touchaction-rects/fast/events/touch/compositor-touch-hit-rects-svg-text.html [ Failure ] Bug(none) fast/events/touch/compositor-touch-hit-rects-svg-foreign-object.html [ Failure ] Bug(none) virtual/paint-touchaction-rects/fast/events/touch/compositor-touch-hit-rects-svg-foreign-object.html [ Failure ] -Bug(none) paint/float/float-under-inline-self-painting-change.html [ Failure ] Bug(none) virtual/paint-touchaction-rects/fast/events/touch/compositor-touch-hit-rects-svg-image.html [ Failure ] Bug(none) fast/events/touch/compositor-touch-hit-rects-svg-image.html [ Failure ] Bug(none) fast/events/touch/compositor-touch-hit-rects-img-element.html [ Failure ] @@ -1418,4 +1298,14 @@ Bug(none) fast/events/touch/compositor-touch-hit-rects-svg-root.html [ Failure ] Bug(none) fast/events/touch/compositor-touch-hit-rects-table.html [ Failure ] Bug(none) virtual/paint-touchaction-rects/fast/events/touch/compositor-touch-hit-rects-table.html [ Failure ] + +Bug(none) virtual/threaded/fast/events/pinch/gesture-pinch-fake-mouse-wheel.html [ Pass Failure Crash ] +Bug(none) virtual/threaded/fast/events/pinch/pinch-zoom-into-center.html [ Pass Failure Crash ] +Bug(none) virtual/threaded/fast/events/pinch/pinch-zoom-pan-position-fixed.html [ Pass Failure Crash ] +Bug(none) virtual/threaded/fast/events/pinch/pinch-zoom-pan-within-zoomed-viewport.html [ Pass Failure Crash ] +Bug(none) compositing/overflow/scrollbar-layer-placement-negative-z-index-child-positioned.html [ Failure ] + +Bug(none) paint/float/float-under-inline-self-painting-change.html [ Failure ] Bug(none) compositing/overflow/overlap-testing-ancestor-scroller-high-dpi.html [ Failure ] +Bug(none) virtual/outofblink-cors-ns/http/tests/navigation/same-document-scroll-position-restore.html [ Timeout ] +Bug(none) virtual/threaded/external/wpt/css/css-scroll-snap/snap-at-user-scroll-end-manual.html [ Timeout ]
diff --git a/third_party/WebKit/LayoutTests/TestExpectations b/third_party/WebKit/LayoutTests/TestExpectations index d96a0413..5a5de79 100644 --- a/third_party/WebKit/LayoutTests/TestExpectations +++ b/third_party/WebKit/LayoutTests/TestExpectations
@@ -1770,6 +1770,8 @@ crbug.com/875235 virtual/layout_ng_experimental/fast/forms/fieldset/legend-after-margin-with-before-border-horizontal-mode.html [ Failure ] crbug.com/875235 virtual/layout_ng_experimental/fast/forms/fieldset/legend-small-after-margin-before-border-horizontal-mode.html [ Failure ] +crbug.com/894457 virtual/layout_ng_experimental/external/wpt/css/css-flexbox/dynamic-bsize-change.html [ Crash ] + # ====== LayoutNG-only failures until here ====== ### sheriff 2018-05-28
diff --git a/third_party/WebKit/LayoutTests/external/wpt/background-fetch/fetch.https.window-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/background-fetch/fetch.https.window-expected.txt index 2bfe0312..67f0b1e 100644 --- a/third_party/WebKit/LayoutTests/external/wpt/background-fetch/fetch.https.window-expected.txt +++ b/third_party/WebKit/LayoutTests/external/wpt/background-fetch/fetch.https.window-expected.txt
@@ -6,6 +6,7 @@ FAIL Requests with PUT method require CORS Preflight and succeed. assert_equals: expected "backgroundfetchsuccess" but got "backgroundfetchfail" FAIL Requests with text/json content type require CORS Preflight and succeed. assert_equals: expected "backgroundfetchsuccess" but got "backgroundfetchfail" PASS Using Background Fetch to successfully fetch a single resource +PASS Registration object gets updated values when a background fetch completes. PASS Background Fetch that exceeds the quota throws a QuotaExceededError FAIL Fetches can have requests with duplicate URLs promise_test: Unhandled rejection with value: object "TypeError: Fetches with duplicate requests are not yet supported. Consider adding query params to make the requests unique. For updates check http://crbug.com/871174" FAIL Fetches can have requests with a body promise_test: Unhandled rejection with value: object "TypeError: Requests with a body are not yet supported. For updates check http://crbug.com/774054"
diff --git a/third_party/WebKit/LayoutTests/external/wpt/background-fetch/fetch.https.window.js b/third_party/WebKit/LayoutTests/external/wpt/background-fetch/fetch.https.window.js index 7729718..9ed7e94 100644 --- a/third_party/WebKit/LayoutTests/external/wpt/background-fetch/fetch.https.window.js +++ b/third_party/WebKit/LayoutTests/external/wpt/background-fetch/fetch.https.window.js
@@ -147,6 +147,24 @@ backgroundFetchTest(async (test, backgroundFetch) => { const registrationId = uniqueId(); + const registration = + await backgroundFetch.fetch(registrationId, 'resources/feature-name.txt'); + + assert_equals(registration.result, ''); + assert_equals(registration.failureReason, ''); + + const {type, eventRegistration, results} = + await getMessageFromServiceWorker(); + assert_equals('backgroundfetchsuccess', type); + + assert_equals(eventRegistration.id, registration.id); + assert_equals(registration.result, 'success'); + assert_equals(registration.failureReason, ''); + +}, 'Registration object gets updated values when a background fetch completes.'); + +backgroundFetchTest(async (test, backgroundFetch) => { + const registrationId = uniqueId(); // Very large download total that will definitely exceed the quota. const options = {downloadTotal: Number.MAX_SAFE_INTEGER}; @@ -240,6 +258,9 @@ assert_equals(eventRegistration.result, 'failure'); assert_equals(eventRegistration.failureReason, 'bad-status'); + assert_equals(registration.result, 'failure'); + assert_equals(registration.failureReason, 'bad-status'); + }, 'Using Background Fetch to fetch a non-existent resource should fail.'); backgroundFetchTest(async (test, backgroundFetch) => {
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/color-space/canvas-createImageBitmap-linear-rgb.html b/third_party/WebKit/LayoutTests/fast/canvas/color-space/canvas-createImageBitmap-linear-rgb.html index 7a06cfac..d79ea788 100644 --- a/third_party/WebKit/LayoutTests/fast/canvas/color-space/canvas-createImageBitmap-linear-rgb.html +++ b/third_party/WebKit/LayoutTests/fast/canvas/color-space/canvas-createImageBitmap-linear-rgb.html
@@ -291,10 +291,6 @@ }, 'createImageBitmap in linear RGB from a transparent SRGB HTMLImageElement \ (BMP, ICO, PNG, WEBP) with resize.'); -// TODO(zakerinasab): crbug.com/668547 -// Add at least two more test scenarios for loading the image element from P3 -// and Rec2020 images. - //////////////////////////////////////////////////////////////////////////////// // SVG Image - SRGB @@ -308,10 +304,6 @@ }).then(testImageBitmapFromSVG); }, 'createImageBitmap in linear RGB from a SRGB SVG image with resize.'); -// TODO(zakerinasab): crbug.com/668547 -// Add at least two more tests for loading the image element from P3 and Rec2020 -// SVG images. - //////////////////////////////////////////////////////////////////////////////// // HTMLVideoElement - SRGB @@ -325,10 +317,6 @@ }).then(testImageBitmapVideoSource); }, 'createImageBitmap in linear RGB from a SRGB HTMLVideoElement with resize.'); -// TODO(zakerinasab): crbug.com/668547 -// Add at least two more tests for loading the video element from P3 and Rec2020 -// videos. - //////////////////////////////////////////////////////////////////////////////// // HTMLCanvasElement - Opaque SRGB @@ -383,7 +371,7 @@ //////////////////////////////////////////////////////////////////////////////// -// Blob - Opaque SRGB +// Blob from file - Opaque SRGB promise_test(function() { return new Promise((resolve, reject) => { var xhr = new XMLHttpRequest(); @@ -396,7 +384,7 @@ }).then(testImageBitmapOpaque); }, 'createImageBitmap in linear RGB from an opaque SRGB Blob with resize.'); -// Blob - Transparent SRGB +// Blob form file - Transparent SRGB promise_test(function() { return new Promise((resolve, reject) => { var xhr = new XMLHttpRequest(); @@ -409,8 +397,48 @@ }).then(testImageBitmapTransparent); }, 'createImageBitmap in linear RGB from a transparent SRGB Blob with resize.'); -// TODO(zakerinasab): crbug.com/668547 -// Add at least two more tests for loading the blob from P3 and Rec2020 images. +// Color managed blob from canvas +function testCreateImageBitmapFromColorManagedBlob(colorSpace, pixelFormat, + isTransparent) { + let canvasPixelFormat = '8-8-8-8'; + if (pixelFormat == 'uint16') + canvasPixelFormat = 'float16'; + var testCanvas; + if (isTransparent) + testCanvas = initializeTestCanvasTransparent('srgb', canvasPixelFormat); + else + testCanvas = initializeTestCanvas('srgb', canvasPixelFormat); + var encodeOptions = {}; + encodeOptions.quality = 1; + encodeOptions.type = 'image/png'; + encodeOptions.colorSpace = colorSpace; + encodeOptions.pixelFormat = pixelFormat; + + var t = async_test('createImageBitmap in linear RGB from color managed Blob' + + ' with resize. blobColorSpace: ' + colorSpace + ', blobPixelFormat: ' + + pixelFormat + ', transparency: ' + isTransparent); + testCanvas.convertToBlob(encodeOptions).then( + t.step_func_done(function(blob) { + if (isTransparent) + testImageBitmapTransparent(blob); + else + testImageBitmapOpaque(blob); + })); +} + +function runAllCreateImageBitmapFromColorManagedBlobTests() { + var blobColorSpaces = ['srgb', 'rec2020', 'display-p3']; + var blobPixelFormats = ['8-8-8-8', 'uint16']; + var transparencies = [false, true]; + for (var i = 0; i < blobColorSpaces.length; i++) + for (var j = 0; j < blobPixelFormats.length; j++) + for (var k = 0; k < transparencies.length; k++) { + testCreateImageBitmapFromColorManagedBlob(blobColorSpaces[i], + blobPixelFormats[j], transparencies[k]); + } +} + +runAllCreateImageBitmapFromColorManagedBlobTests(); ////////////////////////////////////////////////////////////////////////////////
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/color-space/canvas-createImageBitmap-p3.html b/third_party/WebKit/LayoutTests/fast/canvas/color-space/canvas-createImageBitmap-p3.html index 45ca3da..032adf3 100644 --- a/third_party/WebKit/LayoutTests/fast/canvas/color-space/canvas-createImageBitmap-p3.html +++ b/third_party/WebKit/LayoutTests/fast/canvas/color-space/canvas-createImageBitmap-p3.html
@@ -274,10 +274,6 @@ }, 'createImageBitmap in P3 from a transparent SRGB HTMLImageElement (BMP, \ ICO, PNG, WEBP) with resize.'); -// TODO(zakerinasab): crbug.com/668547 -// Add at least two more test scenarios for loading the image element from P3 -// and Rec2020 images. - //////////////////////////////////////////////////////////////////////////////// // SVG Image - SRGB @@ -291,10 +287,6 @@ }).then(testImageBitmapFromSVG); }, 'createImageBitmap in P3 from a SRGB SVG image with resize.'); -// TODO(zakerinasab): crbug.com/668547 -// Add at least two more tests for loading the image element from P3 and Rec2020 -// SVG images. - //////////////////////////////////////////////////////////////////////////////// // HTMLVideoElement - SRGB @@ -308,10 +300,6 @@ }).then(testImageBitmapFromVideo); }, 'createImageBitmap in P3 from a SRGB HTMLVideoElement with resize.'); -// TODO(zakerinasab): crbug.com/668547 -// Add at least two more tests for loading the video element from P3 and Rec2020 -// videos. - //////////////////////////////////////////////////////////////////////////////// // HTMLCanvasElement - Opaque SRGB @@ -366,7 +354,7 @@ //////////////////////////////////////////////////////////////////////////////// -// Blob - Opaque SRGB +// Blob from file - Opaque SRGB promise_test(function() { return new Promise((resolve, reject) => { var xhr = new XMLHttpRequest(); @@ -379,7 +367,7 @@ }).then(testImageBitmapOpaque); }, 'createImageBitmap in P3 from an opaque SRGB Blob with resize.'); -// Blob - Transparent SRGB +// Blob from file - Transparent SRGB promise_test(function() { return new Promise((resolve, reject) => { var xhr = new XMLHttpRequest(); @@ -392,8 +380,48 @@ }).then(testImageBitmapTransparent); }, 'createImageBitmap in P3 from a transparent SRGB Blob with resize.'); -// TODO(zakerinasab): crbug.com/668547 -// Add at least two more tests for loading the blob from P3 and Rec2020 images. +// Color managed blob from canvas +function testCreateImageBitmapFromColorManagedBlob(colorSpace, pixelFormat, + isTransparent) { + let canvasPixelFormat = '8-8-8-8'; + if (pixelFormat == 'uint16') + canvasPixelFormat = 'float16'; + var testCanvas; + if (isTransparent) + testCanvas = initializeTestCanvasTransparent('srgb', canvasPixelFormat); + else + testCanvas = initializeTestCanvas('srgb', canvasPixelFormat); + var encodeOptions = {}; + encodeOptions.quality = 1; + encodeOptions.type = 'image/png'; + encodeOptions.colorSpace = colorSpace; + encodeOptions.pixelFormat = pixelFormat; + + var t = async_test('createImageBitmap in P3 from color managed Blob' + + ' with resize. blobColorSpace: ' + colorSpace + ', blobPixelFormat: ' + + pixelFormat + ', transparency: ' + isTransparent); + testCanvas.convertToBlob(encodeOptions).then( + t.step_func_done(function(blob) { + if (isTransparent) + testImageBitmapTransparent(blob); + else + testImageBitmapOpaque(blob); + })); +} + +function runAllCreateImageBitmapFromColorManagedBlobTests() { + var blobColorSpaces = ['srgb', 'rec2020', 'display-p3']; + var blobPixelFormats = ['8-8-8-8', 'uint16']; + var transparencies = [false, true]; + for (var i = 0; i < blobColorSpaces.length; i++) + for (var j = 0; j < blobPixelFormats.length; j++) + for (var k = 0; k < transparencies.length; k++) { + testCreateImageBitmapFromColorManagedBlob(blobColorSpaces[i], + blobPixelFormats[j], transparencies[k]); + } +} + +runAllCreateImageBitmapFromColorManagedBlobTests(); ////////////////////////////////////////////////////////////////////////////////
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/color-space/canvas-createImageBitmap-rec2020.html b/third_party/WebKit/LayoutTests/fast/canvas/color-space/canvas-createImageBitmap-rec2020.html index 66cf1dd..a5b1584 100644 --- a/third_party/WebKit/LayoutTests/fast/canvas/color-space/canvas-createImageBitmap-rec2020.html +++ b/third_party/WebKit/LayoutTests/fast/canvas/color-space/canvas-createImageBitmap-rec2020.html
@@ -288,10 +288,6 @@ }, 'createImageBitmap in Rec2020 from a transparent SRGB HTMLImageElement (BMP, \ ICO, PNG, WEBP) with resize.'); -// TODO(zakerinasab): crbug.com/668547 -// Add at least two more test scenarios for loading the image element from P3 -// and Rec2020 images. - //////////////////////////////////////////////////////////////////////////////// // SVG Image - SRGB @@ -305,10 +301,6 @@ }).then(testImageBitmapFromSVG); }, 'createImageBitmap in Rec2020 from a SRGB SVG image with resize.'); -// TODO(zakerinasab): crbug.com/668547 -// Add at least two more tests for loading the image element from P3 and Rec2020 -// SVG images. - //////////////////////////////////////////////////////////////////////////////// // HTMLVideoElement - SRGB @@ -322,10 +314,6 @@ }).then(testImageBitmapFromVideo); }, 'createImageBitmap in Rec2020 from a SRGB HTMLVideoElement with resize.'); -// TODO(zakerinasab): crbug.com/668547 -// Add at least two more tests for loading the video element from P3 and Rec2020 -// videos. - //////////////////////////////////////////////////////////////////////////////// // HTMLCanvasElement - Opaque SRGB @@ -380,7 +368,7 @@ //////////////////////////////////////////////////////////////////////////////// -// Blob - Opaque SRGB +// Blob from file - Opaque SRGB promise_test(function() { return new Promise((resolve, reject) => { var xhr = new XMLHttpRequest(); @@ -393,7 +381,7 @@ }).then(testImageBitmapOpaque); }, 'createImageBitmap in Rec2020 from an opaque SRGB Blob with resize.'); -// Blob - Transparent SRGB +// Blob from file - Transparent SRGB promise_test(function() { return new Promise((resolve, reject) => { var xhr = new XMLHttpRequest(); @@ -406,8 +394,48 @@ }).then(testImageBitmapTransparent); }, 'createImageBitmap in Rec2020 from a transparent SRGB Blob with resize.'); -// TODO(zakerinasab): crbug.com/668547 -// Add at least two more tests for loading the blob from P3 and Rec2020 images. +// Color managed blob from canvas +function testCreateImageBitmapFromColorManagedBlob(colorSpace, pixelFormat, + isTransparent) { + let canvasPixelFormat = '8-8-8-8'; + if (pixelFormat == 'uint16') + canvasPixelFormat = 'float16'; + var testCanvas; + if (isTransparent) + testCanvas = initializeTestCanvasTransparent('srgb', canvasPixelFormat); + else + testCanvas = initializeTestCanvas('srgb', canvasPixelFormat); + var encodeOptions = {}; + encodeOptions.quality = 1; + encodeOptions.type = 'image/png'; + encodeOptions.colorSpace = colorSpace; + encodeOptions.pixelFormat = pixelFormat; + + var t = async_test('createImageBitmap in Rec2020 from color managed Blob' + + ' with resize. blobColorSpace: ' + colorSpace + ', blobPixelFormat: ' + + pixelFormat + ', transparency: ' + isTransparent); + testCanvas.convertToBlob(encodeOptions).then( + t.step_func_done(function(blob) { + if (isTransparent) + testImageBitmapTransparent(blob); + else + testImageBitmapOpaque(blob); + })); +} + +function runAllCreateImageBitmapFromColorManagedBlobTests() { + var blobColorSpaces = ['srgb', 'rec2020', 'display-p3']; + var blobPixelFormats = ['8-8-8-8', 'uint16']; + var transparencies = [false, true]; + for (var i = 0; i < blobColorSpaces.length; i++) + for (var j = 0; j < blobPixelFormats.length; j++) + for (var k = 0; k < transparencies.length; k++) { + testCreateImageBitmapFromColorManagedBlob(blobColorSpaces[i], + blobPixelFormats[j], transparencies[k]); + } +} + +runAllCreateImageBitmapFromColorManagedBlobTests(); ////////////////////////////////////////////////////////////////////////////////
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/color-space/high-bit-depth-images.html b/third_party/WebKit/LayoutTests/fast/canvas/color-space/draw-high-bit-depth-images.html similarity index 100% rename from third_party/WebKit/LayoutTests/fast/canvas/color-space/high-bit-depth-images.html rename to third_party/WebKit/LayoutTests/fast/canvas/color-space/draw-high-bit-depth-images.html
diff --git a/third_party/WebKit/LayoutTests/fast/css/CSSStyleSheet-constructable.html b/third_party/WebKit/LayoutTests/fast/css/CSSStyleSheet-constructable.html index bb45ad32..bc47187 100644 --- a/third_party/WebKit/LayoutTests/fast/css/CSSStyleSheet-constructable.html +++ b/third_party/WebKit/LayoutTests/fast/css/CSSStyleSheet-constructable.html
@@ -397,4 +397,38 @@ assert_throws('NotAllowedError', () => { document.adoptedStyleSheets = new StyleSheetList([iframeStyleSheet]); }); assert_equals(getComputedStyle(iframeDiv).color, "rgb(0, 0, 0)"); }, 'Adding non-constructed stylesheet to AdoptedStyleSheets is not allowed when the owner document of the stylesheet and the AdoptedStyleSheets are in different document trees'); + + +test(() => { + const sheet = document.createCSSStyleSheetSync(redStyleTexts[0], {title: "Red", disabled: true, media: "screen, print"}); + assert_equals(sheet.title, "Red"); + assert_equals(sheet.ownerNode, null); + assert_equals(sheet.ownerRule, null); + assert_equals(sheet.media.length, 2); + assert_equals(sheet.media.item(0), "screen"); + assert_equals(sheet.media.item(1), "print"); + assert_true(sheet.disabled); + assert_equals(sheet.cssRules.length, 1); + assert_equals(sheet.cssRules[0].cssText, redStyleTexts[0]); + + sheet.insertRule(redStyleTexts[1]); + assert_equals(sheet.cssRules.length, 2); + assert_equals(sheet.cssRules[0].cssText, redStyleTexts[1]); +}, "Document.createCSSStyleSheetSync creates stylesheets synchronously"); + +const import_text = '@import url("constructable-import.css");'; +test(() => { + assert_throws("NotAllowedError", () => { document.createCSSStyleSheetSync(import_text) }); +}, "Document.createCSSStyleSheetSync throws exception when there is import rule inside"); + + +promise_test(() => { + const sheet_promise = document.createCSSStyleSheet(import_text); + return sheet_promise.then(function(sheet) { + assert_equals(sheet.cssRules.length, 1); + assert_equals(sheet.cssRules[0].cssText, import_text); + }); +}, "Document.createCSSStyleSheet throws allows import rule inside"); + </script> +
diff --git a/third_party/WebKit/LayoutTests/fast/css/constructable-import.css b/third_party/WebKit/LayoutTests/fast/css/constructable-import.css new file mode 100644 index 0000000..60f1eab9 --- /dev/null +++ b/third_party/WebKit/LayoutTests/fast/css/constructable-import.css
@@ -0,0 +1,3 @@ +body { + color: red; +}
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/fast/text/midword-break-before-surrogate-pair-expected.png b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/fast/text/midword-break-before-surrogate-pair-expected.png index 5a5eaaa5..12edf86 100644 --- a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/fast/text/midword-break-before-surrogate-pair-expected.png +++ b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/fast/text/midword-break-before-surrogate-pair-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/fast/borders/border-radius-mask-video-expected.png b/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/fast/borders/border-radius-mask-video-expected.png index 4bce27f..7435b7ddc 100644 --- a/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/fast/borders/border-radius-mask-video-expected.png +++ b/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/fast/borders/border-radius-mask-video-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/fast/table/backgr_border-table-quirks-expected.png b/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/fast/table/backgr_border-table-quirks-expected.png new file mode 100644 index 0000000..429d54e8 --- /dev/null +++ b/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/fast/table/backgr_border-table-quirks-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/paint/invalidation/css-grid-layout/align-items-change-from-baseline-expected.txt b/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/paint/invalidation/css-grid-layout/align-items-change-from-baseline-expected.txt new file mode 100644 index 0000000..541b9f81 --- /dev/null +++ b/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/paint/invalidation/css-grid-layout/align-items-change-from-baseline-expected.txt
@@ -0,0 +1,33 @@ +{ + "layers": [ + { + "name": "LayoutView #document", + "bounds": [800, 600], + "contentsOpaque": true, + "backgroundColor": "#FFFFFF", + "paintInvalidations": [ + { + "object": "LayoutBlockFlow DIV class='item2'", + "rect": [50, 77, 50, 50], + "reason": "geometry" + }, + { + "object": "LayoutBlockFlow DIV class='item2'", + "rect": [50, 52, 50, 50], + "reason": "geometry" + }, + { + "object": "LayoutBlockFlow DIV class='item1'", + "rect": [0, 77, 50, 25], + "reason": "geometry" + }, + { + "object": "LayoutBlockFlow DIV class='item1'", + "rect": [0, 52, 50, 25], + "reason": "geometry" + } + ] + } + ] +} +
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/paint/invalidation/css-grid-layout/align-items-change-to-baseline-expected.txt b/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/paint/invalidation/css-grid-layout/align-items-change-to-baseline-expected.txt new file mode 100644 index 0000000..541b9f81 --- /dev/null +++ b/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/paint/invalidation/css-grid-layout/align-items-change-to-baseline-expected.txt
@@ -0,0 +1,33 @@ +{ + "layers": [ + { + "name": "LayoutView #document", + "bounds": [800, 600], + "contentsOpaque": true, + "backgroundColor": "#FFFFFF", + "paintInvalidations": [ + { + "object": "LayoutBlockFlow DIV class='item2'", + "rect": [50, 77, 50, 50], + "reason": "geometry" + }, + { + "object": "LayoutBlockFlow DIV class='item2'", + "rect": [50, 52, 50, 50], + "reason": "geometry" + }, + { + "object": "LayoutBlockFlow DIV class='item1'", + "rect": [0, 77, 50, 25], + "reason": "geometry" + }, + { + "object": "LayoutBlockFlow DIV class='item1'", + "rect": [0, 52, 50, 25], + "reason": "geometry" + } + ] + } + ] +} +
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/paint/invalidation/css-grid-layout/align-self-change-from-baseline-expected.txt b/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/paint/invalidation/css-grid-layout/align-self-change-from-baseline-expected.txt new file mode 100644 index 0000000..53a1886 --- /dev/null +++ b/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/paint/invalidation/css-grid-layout/align-self-change-from-baseline-expected.txt
@@ -0,0 +1,33 @@ +{ + "layers": [ + { + "name": "LayoutView #document", + "bounds": [800, 600], + "contentsOpaque": true, + "backgroundColor": "#FFFFFF", + "paintInvalidations": [ + { + "object": "LayoutBlockFlow DIV class='item2'", + "rect": [50, 77, 50, 50], + "reason": "geometry" + }, + { + "object": "LayoutBlockFlow DIV class='item2'", + "rect": [50, 52, 50, 50], + "reason": "geometry" + }, + { + "object": "LayoutBlockFlow DIV class='item1'", + "rect": [0, 127, 50, 25], + "reason": "geometry" + }, + { + "object": "LayoutBlockFlow DIV class='item1'", + "rect": [0, 77, 50, 25], + "reason": "geometry" + } + ] + } + ] +} +
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/paint/invalidation/css-grid-layout/align-self-change-to-baseline-expected.txt b/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/paint/invalidation/css-grid-layout/align-self-change-to-baseline-expected.txt new file mode 100644 index 0000000..53a1886 --- /dev/null +++ b/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/paint/invalidation/css-grid-layout/align-self-change-to-baseline-expected.txt
@@ -0,0 +1,33 @@ +{ + "layers": [ + { + "name": "LayoutView #document", + "bounds": [800, 600], + "contentsOpaque": true, + "backgroundColor": "#FFFFFF", + "paintInvalidations": [ + { + "object": "LayoutBlockFlow DIV class='item2'", + "rect": [50, 77, 50, 50], + "reason": "geometry" + }, + { + "object": "LayoutBlockFlow DIV class='item2'", + "rect": [50, 52, 50, 50], + "reason": "geometry" + }, + { + "object": "LayoutBlockFlow DIV class='item1'", + "rect": [0, 127, 50, 25], + "reason": "geometry" + }, + { + "object": "LayoutBlockFlow DIV class='item1'", + "rect": [0, 77, 50, 25], + "reason": "geometry" + } + ] + } + ] +} +
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/paint/invalidation/forms/details-marker-color-change-expected.txt b/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/paint/invalidation/forms/details-marker-color-change-expected.txt new file mode 100644 index 0000000..428787f --- /dev/null +++ b/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/paint/invalidation/forms/details-marker-color-change-expected.txt
@@ -0,0 +1,23 @@ +{ + "layers": [ + { + "name": "LayoutView #document", + "bounds": [800, 600], + "contentsOpaque": true, + "backgroundColor": "#FFFFFF", + "paintInvalidations": [ + { + "object": "InlineTextBox 'Details'", + "rect": [24, 8, 45, 19], + "reason": "style change" + }, + { + "object": "LayoutDetailsMarker DIV id='details-marker'", + "rect": [8, 12, 11, 11], + "reason": "style change" + } + ] + } + ] +} +
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/paint/invalidation/selection/selection-partial-invalidation-between-blocks-expected.png b/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/paint/invalidation/selection/selection-partial-invalidation-between-blocks-expected.png deleted file mode 100644 index 95d9b53..0000000 --- a/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/paint/invalidation/selection/selection-partial-invalidation-between-blocks-expected.png +++ /dev/null Binary files differ
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/paint/invalidation/svg/filter-reference-change-expected.txt b/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/paint/invalidation/svg/filter-reference-change-expected.txt new file mode 100644 index 0000000..3fafee4d --- /dev/null +++ b/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/paint/invalidation/svg/filter-reference-change-expected.txt
@@ -0,0 +1,18 @@ +{ + "layers": [ + { + "name": "LayoutView #document", + "bounds": [800, 600], + "contentsOpaque": true, + "backgroundColor": "#FFFFFF", + "paintInvalidations": [ + { + "object": "LayoutSVGRect rect", + "rect": [8, 8, 110, 110], + "reason": "style change" + } + ] + } + ] +} +
diff --git a/third_party/WebKit/LayoutTests/http/tests/origin_trials/webexposed/backgroundfetch-origin-trial-interfaces.html b/third_party/WebKit/LayoutTests/http/tests/origin_trials/webexposed/backgroundfetch-origin-trial-interfaces.html new file mode 100644 index 0000000..8cedcb9 --- /dev/null +++ b/third_party/WebKit/LayoutTests/http/tests/origin_trials/webexposed/backgroundfetch-origin-trial-interfaces.html
@@ -0,0 +1,31 @@ +<!DOCTYPE html> +<meta charset="utf-8"> +<!-- Generate token with the command: +generate_token.py http://127.0.0.1:8000 BackgroundFetch --expire-timestamp=2000000000 +--> + +<meta http-equiv="origin-trial" content="AtDl/AukAuUX0Sw7KRz+mrV2vpSYrfDyVS4vdO3I1clqoNgKGqCX5Np5KIhlC6oQl8XcULXJz5bc9Y4CcYj9xA4AAABXeyJvcmlnaW4iOiAiaHR0cDovLzEyNy4wLjAuMTo4MDAwIiwgImZlYXR1cmUiOiAiQmFja2dyb3VuZEZldGNoIiwgImV4cGlyeSI6IDIwMDAwMDAwMDB9" /> +<title>Background Fetch API - interfaces exposed by origin trial</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/resources/origin-trials-helper.js"></script> +<script src="/serviceworker/resources/test-helpers.js"></script> +<script> + +test(t => { + OriginTrialsHelper.check_properties(this, { + 'BackgroundFetchManager': ['fetch', 'get', 'getIds'], + 'BackgroundFetchUpdateUIEvent': ['updateUI'], + 'BackgroundFetchFetch': ['request'], + 'BackgroundFetchRegistration': ['id', 'uploadTotal', 'uploaded', + 'downloadTotal', 'downloaded', 'result', + 'failureReason', 'recordsAvailable', + 'onprogress'], + 'ServiceWorkerRegistration': ['backgroundFetch'], + }); +}, 'BackgroundFetch API interfaces and properties in Origin-Trial enabled document.'); + +fetch_tests_from_worker(new Worker('resources/backgroundfetch-origin-trial-interfaces-worker.js')); + + +</script>
diff --git a/third_party/WebKit/LayoutTests/http/tests/origin_trials/webexposed/resources/backgroundfetch-origin-trial-interfaces-worker.js b/third_party/WebKit/LayoutTests/http/tests/origin_trials/webexposed/resources/backgroundfetch-origin-trial-interfaces-worker.js new file mode 100644 index 0000000..6a65225 --- /dev/null +++ b/third_party/WebKit/LayoutTests/http/tests/origin_trials/webexposed/resources/backgroundfetch-origin-trial-interfaces-worker.js
@@ -0,0 +1,17 @@ +importScripts('/resources/testharness.js', + '/resources/origin-trials-helper.js'); + +test(t => { + + OriginTrialsHelper.check_properties(this, { + 'ServiceWorkerRegistration': ['backgroundFetch'], + 'BackgroundFetchFetch': ['request'], + 'BackgroundFetchManager': ['fetch', 'get', 'getIds'], + 'BackgroundFetchRegistration': ['id', 'uploadTotal', 'uploaded', + 'downloadTotal', 'downloaded', 'result', + 'failureReason', 'recordsAvailable', + 'onprogress'], + }); +}, 'Background Fetch API interfaces and properties in Origin-Trial enabled worker.'); + +done();
diff --git a/third_party/WebKit/LayoutTests/images/resources/png-16bit/2x2_16bit_e-sRGB_opaque.png b/third_party/WebKit/LayoutTests/images/resources/png-16bit/2x2_16bit_e-sRGB_opaque.png index 557e947..1c72bad 100644 --- a/third_party/WebKit/LayoutTests/images/resources/png-16bit/2x2_16bit_e-sRGB_opaque.png +++ b/third_party/WebKit/LayoutTests/images/resources/png-16bit/2x2_16bit_e-sRGB_opaque.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/images/resources/png-16bit/2x2_16bit_e-sRGB_transparent.png b/third_party/WebKit/LayoutTests/images/resources/png-16bit/2x2_16bit_e-sRGB_transparent.png index b9a7806..b7ed23c2 100644 --- a/third_party/WebKit/LayoutTests/images/resources/png-16bit/2x2_16bit_e-sRGB_transparent.png +++ b/third_party/WebKit/LayoutTests/images/resources/png-16bit/2x2_16bit_e-sRGB_transparent.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/images/resources/png-16bit/2x2_16bit_interlaced_e-sRGB_opaque.png b/third_party/WebKit/LayoutTests/images/resources/png-16bit/2x2_16bit_interlaced_e-sRGB_opaque.png index 6763c036..1c72bad 100644 --- a/third_party/WebKit/LayoutTests/images/resources/png-16bit/2x2_16bit_interlaced_e-sRGB_opaque.png +++ b/third_party/WebKit/LayoutTests/images/resources/png-16bit/2x2_16bit_interlaced_e-sRGB_opaque.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/images/resources/png-16bit/2x2_16bit_interlaced_e-sRGB_transparent.png b/third_party/WebKit/LayoutTests/images/resources/png-16bit/2x2_16bit_interlaced_e-sRGB_transparent.png index 05aa36e..b7ed23c2 100644 --- a/third_party/WebKit/LayoutTests/images/resources/png-16bit/2x2_16bit_interlaced_e-sRGB_transparent.png +++ b/third_party/WebKit/LayoutTests/images/resources/png-16bit/2x2_16bit_interlaced_e-sRGB_transparent.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/fast/table/backgr_border-table-quirks-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/fast/table/backgr_border-table-quirks-expected.txt deleted file mode 100644 index 668bf420..0000000 --- a/third_party/WebKit/LayoutTests/platform/linux/fast/table/backgr_border-table-quirks-expected.txt +++ /dev/null
@@ -1,77 +0,0 @@ -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 [color=#00FF00] [bgcolor=#333333] - LayoutBlockFlow {H3} at (0,0) size 784x17 - LayoutText {#text} at (0,0) size 342x17 - text run at (0,0) width 342: "crbug.com/35679: Background on 'table'" - LayoutBlockFlow {P} at (0,32.20) size 784x16 - LayoutText {#text} at (0,0) size 656x16 - text run at (0,0) width 656: "There should be three aqua stripes just inside the bottom and right table borders." - LayoutTable {TABLE} at (0,61.20) size 626x459 [color=#FFFFFF] [bgcolor=#000000] [border: (5px dotted #FFFFFF)] - LayoutBlockFlow {CAPTION} at (0,0) size 626x23 - LayoutText {#text} at (167,0) size 292x22 - text run at (167,0) width 292: "With 'border-collapse: separate'" - LayoutTableCol {COLGROUP} at (0,0) size 0x0 - LayoutTableCol {COL} at (0,0) size 0x0 - LayoutTableCol {COL} at (0,0) size 0x0 - LayoutTableCol {COL} at (0,0) size 0x0 - LayoutTableCol {COLGROUP} at (0,0) size 0x0 - LayoutTableCol {COL} at (0,0) size 0x0 - LayoutTableSection {THEAD} at (5,28) size 616x110 - LayoutTableRow {TR} at (0,7) size 616x96 - LayoutTableCell {TH} at (7,41) size 130x27 [border: (1px dotted #FFFFFF)] [r=0 c=0 rs=1 cs=1] - LayoutText {#text} at (42,2) size 46x22 - text run at (42,2) width 46: "TH A" - LayoutTableCell {TH} at (144,29) size 220x51 [border: (13px dotted #FFFFFF)] [r=0 c=1 rs=1 cs=1] - LayoutText {#text} at (87,14) size 46x22 - text run at (87,14) width 46: "TH B" - LayoutTableCell {TH} at (371,41) size 118x27 [border: (1px dotted #FFFFFF)] [r=0 c=2 rs=1 cs=1] - LayoutText {#text} at (36,2) size 46x22 - text run at (36,2) width 46: "TH C" - LayoutTableCell {TH} at (496,41) size 113x27 [border: (1px dotted #FFFFFF)] [r=0 c=3 rs=1 cs=1] - LayoutText {#text} at (34,2) size 45x22 - text run at (34,2) width 45: "TH D" - LayoutTableSection {TBODY} at (5,138) size 616x198 - LayoutTableRow {TR} at (0,0) size 616x104 - LayoutTableCell {TD} at (7,70) size 130x51 [border: (13px dotted #FFFFFF)] [r=0 c=0 rs=2 cs=1] - LayoutText {#text} at (14,14) size 44x22 - text run at (14,14) width 44: "TD E" - LayoutTableCell {TD} at (144,38) size 220x27 [border: (1px dotted #FFFFFF)] [r=0 c=1 rs=1 cs=1] - LayoutText {#text} at (2,2) size 43x22 - text run at (2,2) width 43: "TD F" - LayoutTableCell {TD} at (371,38) size 118x27 [border: (1px dotted #FFFFFF)] [r=0 c=2 rs=1 cs=1] - LayoutText {#text} at (2,2) size 46x22 - text run at (2,2) width 46: "TD G" - LayoutTableCell {TD} at (496,38) size 113x27 [border: (1px dotted #FFFFFF)] [r=0 c=3 rs=1 cs=1] - LayoutText {#text} at (2,2) size 45x22 - text run at (2,2) width 45: "TD H" - LayoutTableRow {TR} at (0,111) size 616x80 - LayoutTableCell {TD} at (144,137) size 220x27 [border: (1px dotted #FFFFFF)] [r=1 c=1 rs=1 cs=1] - LayoutText {#text} at (2,2) size 42x22 - text run at (2,2) width 42: "TD J" - LayoutTableCell {TD} at (371,137) size 118x27 [border: (1px dotted #FFFFFF)] [r=1 c=2 rs=1 cs=1] - LayoutText {#text} at (2,2) size 45x22 - text run at (2,2) width 45: "TD K" - LayoutTableCell {TD} at (496,137) size 113x27 [border: (1px dotted #FFFFFF)] [r=1 c=3 rs=1 cs=1] - LayoutText {#text} at (2,2) size 43x22 - text run at (2,2) width 43: "TD L" - LayoutTableSection {TFOOT} at (5,336) size 616x118 - LayoutTableRow {TR} at (0,0) size 616x111 - LayoutTableCell {TD} at (7,42) size 357x27 [border: (1px dotted #FFFFFF)] [r=0 c=0 rs=1 cs=2] - LayoutText {#text} at (2,2) size 47x22 - text run at (2,2) width 47: "TD M" - LayoutTableCell {TD} at (371,42) size 118x27 [border: (1px dotted #FFFFFF)] [r=0 c=2 rs=1 cs=1] - LayoutText {#text} at (2,2) size 46x22 - text run at (2,2) width 46: "TD O" - LayoutTableCell {TD} at (496,42) size 113x27 [border: (1px dotted #FFFFFF)] [r=0 c=3 rs=1 cs=1] - LayoutText {#text} at (2,2) size 44x22 - text run at (2,2) width 44: "TD P" - LayoutBlockFlow {DIV} at (0,520.20) size 784x31 - LayoutInline {A} at (0,0) size 88x16 [color=#FFFF00] - LayoutImage {IMG} at (0,0) size 88x31 - LayoutText {#text} at (0,0) size 0x0 - LayoutBlockFlow {ADDRESS} at (0,551.20) size 784x17 - LayoutText {#text} at (0,0) size 704x17 - text run at (0,0) width 704: "CSS2 Table Backgrounds Test Suite designed and written by fantasai <fantasai@escape.com>"
diff --git a/third_party/WebKit/LayoutTests/platform/mac/fast/table/backgr_border-table-quirks-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/fast/table/backgr_border-table-quirks-expected.txt deleted file mode 100644 index 489cd78..0000000 --- a/third_party/WebKit/LayoutTests/platform/mac/fast/table/backgr_border-table-quirks-expected.txt +++ /dev/null
@@ -1,77 +0,0 @@ -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 [color=#00FF00] [bgcolor=#333333] - LayoutBlockFlow {H3} at (0,0) size 784x17 - LayoutText {#text} at (0,0) size 347x17 - text run at (0,0) width 347: "crbug.com/35679: Background on 'table'" - LayoutBlockFlow {P} at (0,32.20) size 784x15 - LayoutText {#text} at (0,0) size 640x15 - text run at (0,0) width 640: "There should be three aqua stripes just inside the bottom and right table borders." - LayoutTable {TABLE} at (0,60.20) size 626x458 [color=#FFFFFF] [bgcolor=#000000] [border: (5px dotted #FFFFFF)] - LayoutBlockFlow {CAPTION} at (0,0) size 626x22 - LayoutText {#text} at (167,0) size 292x22 - text run at (167,0) width 292: "With 'border-collapse: separate'" - LayoutTableCol {COLGROUP} at (0,0) size 0x0 - LayoutTableCol {COL} at (0,0) size 0x0 - LayoutTableCol {COL} at (0,0) size 0x0 - LayoutTableCol {COL} at (0,0) size 0x0 - LayoutTableCol {COLGROUP} at (0,0) size 0x0 - LayoutTableCol {COL} at (0,0) size 0x0 - LayoutTableSection {THEAD} at (5,27) size 616x110 - LayoutTableRow {TR} at (0,7) size 616x96 - LayoutTableCell {TH} at (7,42) size 130x26 [border: (1px dotted #FFFFFF)] [r=0 c=0 rs=1 cs=1] - LayoutText {#text} at (42,2) size 46x22 - text run at (42,2) width 46: "TH A" - LayoutTableCell {TH} at (144,30) size 220x50 [border: (13px dotted #FFFFFF)] [r=0 c=1 rs=1 cs=1] - LayoutText {#text} at (87,14) size 46x22 - text run at (87,14) width 46: "TH B" - LayoutTableCell {TH} at (371,42) size 118x26 [border: (1px dotted #FFFFFF)] [r=0 c=2 rs=1 cs=1] - LayoutText {#text} at (36,2) size 46x22 - text run at (36,2) width 46: "TH C" - LayoutTableCell {TH} at (496,42) size 113x26 [border: (1px dotted #FFFFFF)] [r=0 c=3 rs=1 cs=1] - LayoutText {#text} at (34,2) size 45x22 - text run at (34,2) width 45: "TH D" - LayoutTableSection {TBODY} at (5,137) size 616x198 - LayoutTableRow {TR} at (0,0) size 616x104 - LayoutTableCell {TD} at (7,70) size 130x50 [border: (13px dotted #FFFFFF)] [r=0 c=0 rs=2 cs=1] - LayoutText {#text} at (14,14) size 44x22 - text run at (14,14) width 44: "TD E" - LayoutTableCell {TD} at (144,39) size 220x26 [border: (1px dotted #FFFFFF)] [r=0 c=1 rs=1 cs=1] - LayoutText {#text} at (2,2) size 43x22 - text run at (2,2) width 43: "TD F" - LayoutTableCell {TD} at (371,39) size 118x26 [border: (1px dotted #FFFFFF)] [r=0 c=2 rs=1 cs=1] - LayoutText {#text} at (2,2) size 46x22 - text run at (2,2) width 46: "TD G" - LayoutTableCell {TD} at (496,39) size 113x26 [border: (1px dotted #FFFFFF)] [r=0 c=3 rs=1 cs=1] - LayoutText {#text} at (2,2) size 45x22 - text run at (2,2) width 45: "TD H" - LayoutTableRow {TR} at (0,111) size 616x80 - LayoutTableCell {TD} at (144,138) size 220x26 [border: (1px dotted #FFFFFF)] [r=1 c=1 rs=1 cs=1] - LayoutText {#text} at (2,2) size 42x22 - text run at (2,2) width 42: "TD J" - LayoutTableCell {TD} at (371,138) size 118x26 [border: (1px dotted #FFFFFF)] [r=1 c=2 rs=1 cs=1] - LayoutText {#text} at (2,2) size 45x22 - text run at (2,2) width 45: "TD K" - LayoutTableCell {TD} at (496,138) size 113x26 [border: (1px dotted #FFFFFF)] [r=1 c=3 rs=1 cs=1] - LayoutText {#text} at (2,2) size 43x22 - text run at (2,2) width 43: "TD L" - LayoutTableSection {TFOOT} at (5,335) size 616x118 - LayoutTableRow {TR} at (0,0) size 616x111 - LayoutTableCell {TD} at (7,42) size 357x26 [border: (1px dotted #FFFFFF)] [r=0 c=0 rs=1 cs=2] - LayoutText {#text} at (2,2) size 47x22 - text run at (2,2) width 47: "TD M" - LayoutTableCell {TD} at (371,42) size 118x26 [border: (1px dotted #FFFFFF)] [r=0 c=2 rs=1 cs=1] - LayoutText {#text} at (2,2) size 46x22 - text run at (2,2) width 46: "TD O" - LayoutTableCell {TD} at (496,42) size 113x26 [border: (1px dotted #FFFFFF)] [r=0 c=3 rs=1 cs=1] - LayoutText {#text} at (2,2) size 44x22 - text run at (2,2) width 44: "TD P" - LayoutBlockFlow {DIV} at (0,518.20) size 784x31 - LayoutInline {A} at (0,0) size 88x15 [color=#FFFF00] - LayoutImage {IMG} at (0,0) size 88x31 - LayoutText {#text} at (0,0) size 0x0 - LayoutBlockFlow {ADDRESS} at (0,549.20) size 784x15 - LayoutText {#text} at (0,0) size 687x15 - text run at (0,0) width 687: "CSS2 Table Backgrounds Test Suite designed and written by fantasai <fantasai@escape.com>"
diff --git a/third_party/WebKit/LayoutTests/platform/win/fast/table/backgr_border-table-quirks-expected.txt b/third_party/WebKit/LayoutTests/platform/win/fast/table/backgr_border-table-quirks-expected.txt deleted file mode 100644 index dec8cd5..0000000 --- a/third_party/WebKit/LayoutTests/platform/win/fast/table/backgr_border-table-quirks-expected.txt +++ /dev/null
@@ -1,77 +0,0 @@ -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 [color=#00FF00] [bgcolor=#333333] - LayoutBlockFlow {H3} at (0,0) size 784x17 - LayoutText {#text} at (0,0) size 342x17 - text run at (0,0) width 342: "crbug.com/35679: Background on 'table'" - LayoutBlockFlow {P} at (0,32.20) size 784x16 - LayoutText {#text} at (0,0) size 656x16 - text run at (0,0) width 656: "There should be three aqua stripes just inside the bottom and right table borders." - LayoutTable {TABLE} at (0,61.20) size 626x463 [color=#FFFFFF] [bgcolor=#000000] [border: (5px dotted #FFFFFF)] - LayoutBlockFlow {CAPTION} at (0,0) size 626x27 - LayoutText {#text} at (147,0) size 332x27 - text run at (147,0) width 332: "With 'border-collapse: separate'" - LayoutTableCol {COLGROUP} at (0,0) size 0x0 - LayoutTableCol {COL} at (0,0) size 0x0 - LayoutTableCol {COL} at (0,0) size 0x0 - LayoutTableCol {COL} at (0,0) size 0x0 - LayoutTableCol {COLGROUP} at (0,0) size 0x0 - LayoutTableCol {COL} at (0,0) size 0x0 - LayoutTableSection {THEAD} at (5,32) size 616x110 - LayoutTableRow {TR} at (0,7) size 616x96 - LayoutTableCell {TH} at (7,41) size 130x27 [border: (1px dotted #FFFFFF)] [r=0 c=0 rs=1 cs=1] - LayoutText {#text} at (43,2) size 44x22 - text run at (43,2) width 44: "TH A" - LayoutTableCell {TH} at (144,29) size 220x51 [border: (13px dotted #FFFFFF)] [r=0 c=1 rs=1 cs=1] - LayoutText {#text} at (87,14) size 46x22 - text run at (87,14) width 46: "TH B" - LayoutTableCell {TH} at (371,41) size 118x27 [border: (1px dotted #FFFFFF)] [r=0 c=2 rs=1 cs=1] - LayoutText {#text} at (36,2) size 46x22 - text run at (36,2) width 46: "TH C" - LayoutTableCell {TH} at (496,41) size 113x27 [border: (1px dotted #FFFFFF)] [r=0 c=3 rs=1 cs=1] - LayoutText {#text} at (34,2) size 45x22 - text run at (34,2) width 45: "TH D" - LayoutTableSection {TBODY} at (5,142) size 616x198 - LayoutTableRow {TR} at (0,0) size 616x104 - LayoutTableCell {TD} at (7,68) size 130x55 [border: (13px dotted #FFFFFF)] [r=0 c=0 rs=2 cs=1] - LayoutText {#text} at (14,14) size 49x27 - text run at (14,14) width 49: "TD E" - LayoutTableCell {TD} at (144,36) size 220x31 [border: (1px dotted #FFFFFF)] [r=0 c=1 rs=1 cs=1] - LayoutText {#text} at (2,2) size 48x27 - text run at (2,2) width 48: "TD F" - LayoutTableCell {TD} at (371,36) size 118x31 [border: (1px dotted #FFFFFF)] [r=0 c=2 rs=1 cs=1] - LayoutText {#text} at (2,2) size 51x27 - text run at (2,2) width 51: "TD G" - LayoutTableCell {TD} at (496,36) size 113x31 [border: (1px dotted #FFFFFF)] [r=0 c=3 rs=1 cs=1] - LayoutText {#text} at (2,2) size 51x27 - text run at (2,2) width 51: "TD H" - LayoutTableRow {TR} at (0,111) size 616x80 - LayoutTableCell {TD} at (144,135) size 220x31 [border: (1px dotted #FFFFFF)] [r=1 c=1 rs=1 cs=1] - LayoutText {#text} at (2,2) size 48x27 - text run at (2,2) width 48: "TD J" - LayoutTableCell {TD} at (371,135) size 118x31 [border: (1px dotted #FFFFFF)] [r=1 c=2 rs=1 cs=1] - LayoutText {#text} at (2,2) size 51x27 - text run at (2,2) width 51: "TD K" - LayoutTableCell {TD} at (496,135) size 113x31 [border: (1px dotted #FFFFFF)] [r=1 c=3 rs=1 cs=1] - LayoutText {#text} at (2,2) size 48x27 - text run at (2,2) width 48: "TD L" - LayoutTableSection {TFOOT} at (5,340) size 616x118 - LayoutTableRow {TR} at (0,0) size 616x111 - LayoutTableCell {TD} at (7,40) size 357x31 [border: (1px dotted #FFFFFF)] [r=0 c=0 rs=1 cs=2] - LayoutText {#text} at (2,2) size 53x27 - text run at (2,2) width 53: "TD M" - LayoutTableCell {TD} at (371,40) size 118x31 [border: (1px dotted #FFFFFF)] [r=0 c=2 rs=1 cs=1] - LayoutText {#text} at (2,2) size 51x27 - text run at (2,2) width 51: "TD O" - LayoutTableCell {TD} at (496,40) size 113x31 [border: (1px dotted #FFFFFF)] [r=0 c=3 rs=1 cs=1] - LayoutText {#text} at (2,2) size 49x27 - text run at (2,2) width 49: "TD P" - LayoutBlockFlow {DIV} at (0,524.20) size 784x31 - LayoutInline {A} at (0,0) size 88x16 [color=#FFFF00] - LayoutImage {IMG} at (0,0) size 88x31 - LayoutText {#text} at (0,0) size 0x0 - LayoutBlockFlow {ADDRESS} at (0,555.20) size 784x17 - LayoutText {#text} at (0,0) size 704x17 - text run at (0,0) width 704: "CSS2 Table Backgrounds Test Suite designed and written by fantasai <fantasai@escape.com>"
diff --git a/third_party/WebKit/LayoutTests/platform/win7/fast/table/backgr_border-table-quirks-expected.txt b/third_party/WebKit/LayoutTests/platform/win7/fast/table/backgr_border-table-quirks-expected.txt deleted file mode 100644 index 75b4bed..0000000 --- a/third_party/WebKit/LayoutTests/platform/win7/fast/table/backgr_border-table-quirks-expected.txt +++ /dev/null
@@ -1,77 +0,0 @@ -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 [color=#00FF00] [bgcolor=#333333] - LayoutBlockFlow {H3} at (0,0) size 784x17 - LayoutText {#text} at (0,0) size 342x17 - text run at (0,0) width 342: "crbug.com/35679: Background on 'table'" - LayoutBlockFlow {P} at (0,32.20) size 784x16 - LayoutText {#text} at (0,0) size 656x16 - text run at (0,0) width 656: "There should be three aqua stripes just inside the bottom and right table borders." - LayoutTable {TABLE} at (0,61.20) size 626x463 [color=#FFFFFF] [bgcolor=#000000] [border: (5px dotted #FFFFFF)] - LayoutBlockFlow {CAPTION} at (0,0) size 626x27 - LayoutText {#text} at (148,0) size 330x27 - text run at (148,0) width 330: "With 'border-collapse: separate'" - LayoutTableCol {COLGROUP} at (0,0) size 0x0 - LayoutTableCol {COL} at (0,0) size 0x0 - LayoutTableCol {COL} at (0,0) size 0x0 - LayoutTableCol {COL} at (0,0) size 0x0 - LayoutTableCol {COLGROUP} at (0,0) size 0x0 - LayoutTableCol {COL} at (0,0) size 0x0 - LayoutTableSection {THEAD} at (5,32) size 616x110 - LayoutTableRow {TR} at (0,7) size 616x96 - LayoutTableCell {TH} at (7,41) size 130x27 [border: (1px dotted #FFFFFF)] [r=0 c=0 rs=1 cs=1] - LayoutText {#text} at (43,2) size 44x22 - text run at (43,2) width 44: "TH A" - LayoutTableCell {TH} at (144,29) size 220x51 [border: (13px dotted #FFFFFF)] [r=0 c=1 rs=1 cs=1] - LayoutText {#text} at (87,14) size 46x22 - text run at (87,14) width 46: "TH B" - LayoutTableCell {TH} at (371,41) size 118x27 [border: (1px dotted #FFFFFF)] [r=0 c=2 rs=1 cs=1] - LayoutText {#text} at (36,2) size 46x22 - text run at (36,2) width 46: "TH C" - LayoutTableCell {TH} at (496,41) size 113x27 [border: (1px dotted #FFFFFF)] [r=0 c=3 rs=1 cs=1] - LayoutText {#text} at (34,2) size 45x22 - text run at (34,2) width 45: "TH D" - LayoutTableSection {TBODY} at (5,142) size 616x198 - LayoutTableRow {TR} at (0,0) size 616x104 - LayoutTableCell {TD} at (7,68) size 130x55 [border: (13px dotted #FFFFFF)] [r=0 c=0 rs=2 cs=1] - LayoutText {#text} at (14,14) size 49x27 - text run at (14,14) width 49: "TD E" - LayoutTableCell {TD} at (144,36) size 220x31 [border: (1px dotted #FFFFFF)] [r=0 c=1 rs=1 cs=1] - LayoutText {#text} at (2,2) size 48x27 - text run at (2,2) width 48: "TD F" - LayoutTableCell {TD} at (371,36) size 118x31 [border: (1px dotted #FFFFFF)] [r=0 c=2 rs=1 cs=1] - LayoutText {#text} at (2,2) size 51x27 - text run at (2,2) width 51: "TD G" - LayoutTableCell {TD} at (496,36) size 113x31 [border: (1px dotted #FFFFFF)] [r=0 c=3 rs=1 cs=1] - LayoutText {#text} at (2,2) size 51x27 - text run at (2,2) width 51: "TD H" - LayoutTableRow {TR} at (0,111) size 616x80 - LayoutTableCell {TD} at (144,135) size 220x31 [border: (1px dotted #FFFFFF)] [r=1 c=1 rs=1 cs=1] - LayoutText {#text} at (2,2) size 48x27 - text run at (2,2) width 48: "TD J" - LayoutTableCell {TD} at (371,135) size 118x31 [border: (1px dotted #FFFFFF)] [r=1 c=2 rs=1 cs=1] - LayoutText {#text} at (2,2) size 51x27 - text run at (2,2) width 51: "TD K" - LayoutTableCell {TD} at (496,135) size 113x31 [border: (1px dotted #FFFFFF)] [r=1 c=3 rs=1 cs=1] - LayoutText {#text} at (2,2) size 48x27 - text run at (2,2) width 48: "TD L" - LayoutTableSection {TFOOT} at (5,340) size 616x118 - LayoutTableRow {TR} at (0,0) size 616x111 - LayoutTableCell {TD} at (7,40) size 357x31 [border: (1px dotted #FFFFFF)] [r=0 c=0 rs=1 cs=2] - LayoutText {#text} at (2,2) size 53x27 - text run at (2,2) width 53: "TD M" - LayoutTableCell {TD} at (371,40) size 118x31 [border: (1px dotted #FFFFFF)] [r=0 c=2 rs=1 cs=1] - LayoutText {#text} at (2,2) size 51x27 - text run at (2,2) width 51: "TD O" - LayoutTableCell {TD} at (496,40) size 113x31 [border: (1px dotted #FFFFFF)] [r=0 c=3 rs=1 cs=1] - LayoutText {#text} at (2,2) size 49x27 - text run at (2,2) width 49: "TD P" - LayoutBlockFlow {DIV} at (0,524.20) size 784x31 - LayoutInline {A} at (0,0) size 88x16 [color=#FFFF00] - LayoutImage {IMG} at (0,0) size 88x31 - LayoutText {#text} at (0,0) size 0x0 - LayoutBlockFlow {ADDRESS} at (0,555.20) size 784x17 - LayoutText {#text} at (0,0) size 704x17 - text run at (0,0) width 704: "CSS2 Table Backgrounds Test Suite designed and written by fantasai <fantasai@escape.com>"
diff --git a/third_party/WebKit/LayoutTests/svg/zoom/page/zoom-svg-doc-no-svg-docelm-expected.svg b/third_party/WebKit/LayoutTests/svg/zoom/page/zoom-svg-doc-no-svg-docelm-expected.svg new file mode 100644 index 0000000..0352c6a --- /dev/null +++ b/third_party/WebKit/LayoutTests/svg/zoom/page/zoom-svg-doc-no-svg-docelm-expected.svg
@@ -0,0 +1,4 @@ +<?xml version="1.0"?> +<html xmlns="http://www.w3.org/1999/xhtml"> + <div style="width: 100px; height: 100px; background-color: green"></div> +</html>
diff --git a/third_party/WebKit/LayoutTests/svg/zoom/page/zoom-svg-doc-no-svg-docelm.svg b/third_party/WebKit/LayoutTests/svg/zoom/page/zoom-svg-doc-no-svg-docelm.svg new file mode 100644 index 0000000..bc7ef29 --- /dev/null +++ b/third_party/WebKit/LayoutTests/svg/zoom/page/zoom-svg-doc-no-svg-docelm.svg
@@ -0,0 +1,10 @@ +<?xml version="1.0"?> +<html xmlns="http://www.w3.org/1999/xhtml"> + <script src="../../../resources/run-after-layout-and-paint.js"/> + <div style="width: 50px; height: 50px; background-color: green"/> + <script> + runAfterLayoutAndPaint(function() { + eventSender.setPageZoomFactor(2); + }, true); + </script> +</html>
diff --git a/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-expected.txt b/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-expected.txt index 2e8b314..598c34de 100644 --- a/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-expected.txt +++ b/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-expected.txt
@@ -1638,6 +1638,7 @@ method createAttributeNS method createCDATASection method createCSSStyleSheet + method createCSSStyleSheetSync method createComment method createDocumentFragment method createElement
diff --git a/third_party/blink/public/platform/DEPS b/third_party/blink/public/platform/DEPS index efa764a..a10dc67 100644 --- a/third_party/blink/public/platform/DEPS +++ b/third_party/blink/public/platform/DEPS
@@ -25,6 +25,7 @@ "+net/http", "+services/network/public/cpp/cors/cors_error_status.h", "+services/network/public/cpp/cors/preflight_result.h", + "+services/network/public/cpp/cors/preflight_timing_info.h", "+services/network/public/cpp/shared_url_loader_factory.h", # Enforce to use mojom-shared.h in blink/public so that it can compile
diff --git a/third_party/blink/public/platform/modules/background_fetch/background_fetch.mojom b/third_party/blink/public/platform/modules/background_fetch/background_fetch.mojom index 3e3b635..3e78d8b 100644 --- a/third_party/blink/public/platform/modules/background_fetch/background_fetch.mojom +++ b/third_party/blink/public/platform/modules/background_fetch/background_fetch.mojom
@@ -103,7 +103,9 @@ OnProgress(uint64 upload_total, uint64 uploaded, uint64 download_total, - uint64 downloaded); + uint64 downloaded, + BackgroundFetchResult result, + BackgroundFetchFailureReason failure_reason); // Notifies the BackgroundFetchRegistration that the data for the associated // fetch is no longer available. The mojo connection will be closed after
diff --git a/third_party/blink/public/platform/web_feature.mojom b/third_party/blink/public/platform/web_feature.mojom index 2bc098f..627fe7b 100644 --- a/third_party/blink/public/platform/web_feature.mojom +++ b/third_party/blink/public/platform/web_feature.mojom
@@ -2041,6 +2041,7 @@ kGetComputedStyleForWebkitAppearance = 2588, kCursorImageLE32x32 = 2589, kCursorImageGT32x32 = 2590, + kRTCPeerConnectionComplexPlanBSdpUsingDefaultSdpSemantics = 2591, // Add new features immediately above this line. Don't change assigned // numbers of any item, and don't reuse removed slots.
diff --git a/third_party/blink/public/platform/web_url_loader_client.h b/third_party/blink/public/platform/web_url_loader_client.h index f1e64d8..04d2885 100644 --- a/third_party/blink/public/platform/web_url_loader_client.h +++ b/third_party/blink/public/platform/web_url_loader_client.h
@@ -34,6 +34,7 @@ #include <memory> #include "base/time/time.h" #include "mojo/public/cpp/system/data_pipe.h" +#include "services/network/public/cpp/cors/preflight_timing_info.h" #include "third_party/blink/public/platform/web_common.h" #include "third_party/blink/public/platform/web_data_consumer_handle.h" #include "third_party/blink/public/platform/web_referrer_policy.h" @@ -107,11 +108,13 @@ // will be generated in devtools console if this flag is set to true. // TODO(crbug.com/798625): use different callback for subresources // with responses blocked due to document protection. - virtual void DidFinishLoading(base::TimeTicks finish_time, - int64_t total_encoded_data_length, - int64_t total_encoded_body_length, - int64_t total_decoded_body_length, - bool should_report_corb_blocking) {} + virtual void DidFinishLoading( + base::TimeTicks finish_time, + int64_t total_encoded_data_length, + int64_t total_encoded_body_length, + int64_t total_decoded_body_length, + bool should_report_corb_blocking, + const std::vector<network::cors::PreflightTimingInfo>&) {} // Called when the load completes with an error. // |total_encoded_data_length| may be equal to kUnknownEncodedDataLength.
diff --git a/third_party/blink/renderer/bindings/core/v8/binding_security.cc b/third_party/blink/renderer/bindings/core/v8/binding_security.cc index ddc0dda9..62c993e 100644 --- a/third_party/blink/renderer/bindings/core/v8/binding_security.cc +++ b/third_party/blink/renderer/bindings/core/v8/binding_security.cc
@@ -41,7 +41,6 @@ #include "third_party/blink/renderer/core/frame/settings.h" #include "third_party/blink/renderer/core/frame/use_counter.h" #include "third_party/blink/renderer/core/html/html_frame_element_base.h" -#include "third_party/blink/renderer/core/workers/main_thread_worklet_global_scope.h" #include "third_party/blink/renderer/platform/bindings/exception_state.h" #include "third_party/blink/renderer/platform/bindings/wrapper_creation_security_check.h" #include "third_party/blink/renderer/platform/weborigin/security_origin.h"
diff --git a/third_party/blink/renderer/bindings/core/v8/js_event_handler.cc b/third_party/blink/renderer/bindings/core/v8/js_event_handler.cc index bb71bea..42b029d 100644 --- a/third_party/blink/renderer/bindings/core/v8/js_event_handler.cc +++ b/third_party/blink/renderer/bindings/core/v8/js_event_handler.cc
@@ -25,6 +25,8 @@ v8::Local<v8::Function> listener, const V8PrivateProperty::Symbol& property) { DCHECK(!HasCompiledHandler()); + v8::Context::BackupIncumbentScope backup_incumbent_scope( + script_state->GetContext()); event_handler_ = V8EventHandlerNonNull::Create(listener); Attach(script_state, listener, property, this); }
diff --git a/third_party/blink/renderer/bindings/core/v8/js_event_handler_for_content_attribute.cc b/third_party/blink/renderer/bindings/core/v8/js_event_handler_for_content_attribute.cc index de79b9b..cc79a175 100644 --- a/third_party/blink/renderer/bindings/core/v8/js_event_handler_for_content_attribute.cc +++ b/third_party/blink/renderer/bindings/core/v8/js_event_handler_for_content_attribute.cc
@@ -197,7 +197,6 @@ std::unique_ptr<SourceLocation> JSEventHandlerForContentAttribute::GetSourceLocation(EventTarget& target) { - v8::HandleScope(GetIsolate()); auto source_location = JSEventHandler::GetSourceLocation(target); if (source_location) return source_location;
diff --git a/third_party/blink/renderer/bindings/core/v8/script_streamer_test.cc b/third_party/blink/renderer/bindings/core/v8/script_streamer_test.cc index 09013e6..7d033b09 100644 --- a/third_party/blink/renderer/bindings/core/v8/script_streamer_test.cc +++ b/third_party/blink/renderer/bindings/core/v8/script_streamer_test.cc
@@ -116,7 +116,9 @@ void AppendPadding() { AppendPadding(GetResource()); } void Finish() { - GetResource()->Loader()->DidFinishLoading(TimeTicks(), 0, 0, 0, false); + GetResource()->Loader()->DidFinishLoading( + TimeTicks(), 0, 0, 0, false, + std::vector<network::cors::PreflightTimingInfo>()); GetResource()->SetStatus(ResourceStatus::kCached); }
diff --git a/third_party/blink/renderer/bindings/core/v8/worker_or_worklet_script_controller.h b/third_party/blink/renderer/bindings/core/v8/worker_or_worklet_script_controller.h index 4d7a66f..0f01f1c 100644 --- a/third_party/blink/renderer/bindings/core/v8/worker_or_worklet_script_controller.h +++ b/third_party/blink/renderer/bindings/core/v8/worker_or_worklet_script_controller.h
@@ -71,10 +71,10 @@ // Used by WorkerThread. Returns true if the context is successfully // initialized or already initialized. - // For WorkerGlobalScope and ThreadedWorkletGlobalScope, |url_for_debugger| is - // and should be used only for setting name/origin that appears in DevTools. - // For other global scopes, |human_readable_name| is used for setting - // DOMWrapperWorld's human readable name. + // For WorkerGlobalScope and threaded WorkletGlobalScope, |url_for_debugger| + // is and should be used only for setting name/origin that appears in + // DevTools. For other global scopes, |human_readable_name| is used for + // setting DOMWrapperWorld's human readable name. bool InitializeContextIfNeeded(const String& human_readable_name, const KURL& url_for_debugger);
diff --git a/third_party/blink/renderer/core/css/css_style_sheet.cc b/third_party/blink/renderer/core/css/css_style_sheet.cc index 222a3086..b564ea1 100644 --- a/third_party/blink/renderer/core/css/css_style_sheet.cc +++ b/third_party/blink/renderer/core/css/css_style_sheet.cc
@@ -28,6 +28,7 @@ #include "third_party/blink/renderer/core/css/media_list.h" #include "third_party/blink/renderer/core/css/parser/css_parser.h" #include "third_party/blink/renderer/core/css/parser/css_parser_context.h" +#include "third_party/blink/renderer/core/css/parser/css_parser_impl.h" #include "third_party/blink/renderer/core/css/style_engine.h" #include "third_party/blink/renderer/core/css/style_rule.h" #include "third_party/blink/renderer/core/css/style_sheet_contents.h" @@ -527,12 +528,19 @@ contents_->ClientLoadStarted(this); } -void CSSStyleSheet::SetText(const String& text) { +void CSSStyleSheet::SetText(const String& text, + bool allow_import_rules, + ExceptionState& exception_state) { child_rule_cssom_wrappers_.clear(); CSSStyleSheet::RuleMutationScope mutation_scope(this); contents_->ClearRules(); - contents_->ParseString(text); + if (contents_->ParseString(text, allow_import_rules) == + ParseSheetResult::kHasUnallowedImportRule) { + exception_state.ThrowDOMException(DOMExceptionCode::kNotAllowedError, + "@import rules are not allowed when " + "creating stylesheet synchronously."); + } } void CSSStyleSheet::SetAlternateFromConstructor(
diff --git a/third_party/blink/renderer/core/css/css_style_sheet.h b/third_party/blink/renderer/core/css/css_style_sheet.h index 7dcf15e..dcafec0c 100644 --- a/third_party/blink/renderer/core/css/css_style_sheet.h +++ b/third_party/blink/renderer/core/css/css_style_sheet.h
@@ -184,7 +184,7 @@ bool SheetLoaded(); bool LoadCompleted() const { return load_completed_; } void StartLoadingDynamicSheet(); - void SetText(const String&); + void SetText(const String&, bool allow_import_rules, ExceptionState&); void SetMedia(MediaList*); void SetAlternateFromConstructor(bool); bool IsAlternate() const; @@ -235,6 +235,7 @@ // For other CSSStyleSheet, consult the alternate attribute. bool alternate_from_constructor_ = false; bool enable_rule_access_for_inspector_ = false; + String title_; scoped_refptr<MediaQuerySet> media_queries_; MediaQueryResultList viewport_dependent_media_query_results_;
diff --git a/third_party/blink/renderer/core/css/parser/css_parser.cc b/third_party/blink/renderer/core/css/parser/css_parser.cc index a753f3f..9f354dd 100644 --- a/third_party/blink/renderer/core/css/parser/css_parser.cc +++ b/third_party/blink/renderer/core/css/parser/css_parser.cc
@@ -65,12 +65,14 @@ CSSParserImpl::kAllowImportRules); } -void CSSParser::ParseSheet(const CSSParserContext* context, - StyleSheetContents* style_sheet, - const String& text, - CSSDeferPropertyParsing defer_property_parsing) { - return CSSParserImpl::ParseStyleSheet(text, context, style_sheet, - defer_property_parsing); +ParseSheetResult CSSParser::ParseSheet( + const CSSParserContext* context, + StyleSheetContents* style_sheet, + const String& text, + CSSDeferPropertyParsing defer_property_parsing, + bool allow_import_rules) { + return CSSParserImpl::ParseStyleSheet( + text, context, style_sheet, defer_property_parsing, allow_import_rules); } void CSSParser::ParseSheetForInspector(const CSSParserContext* context,
diff --git a/third_party/blink/renderer/core/css/parser/css_parser.h b/third_party/blink/renderer/core/css/parser/css_parser.h index 40471cc4..118bb97 100644 --- a/third_party/blink/renderer/core/css/parser/css_parser.h +++ b/third_party/blink/renderer/core/css/parser/css_parser.h
@@ -22,6 +22,7 @@ class StyleRuleKeyframe; class StyleSheetContents; class CSSValue; +enum class ParseSheetResult; enum class SecureContextMode; // This class serves as the public API for the css/parser subsystem @@ -34,11 +35,13 @@ StyleSheetContents*, const String&); - static void ParseSheet(const CSSParserContext*, - StyleSheetContents*, - const String&, - CSSDeferPropertyParsing defer_property_parsing = - CSSDeferPropertyParsing::kNo); + static ParseSheetResult ParseSheet( + const CSSParserContext*, + StyleSheetContents*, + const String&, + CSSDeferPropertyParsing defer_property_parsing = + CSSDeferPropertyParsing::kNo, + bool allow_import_rules = true); static CSSSelectorList ParseSelector(const CSSParserContext*, StyleSheetContents*, const String&);
diff --git a/third_party/blink/renderer/core/css/parser/css_parser_impl.cc b/third_party/blink/renderer/core/css/parser/css_parser_impl.cc index 3e2de46a..a38daa0 100644 --- a/third_party/blink/renderer/core/css/parser/css_parser_impl.cc +++ b/third_party/blink/renderer/core/css/parser/css_parser_impl.cc
@@ -242,11 +242,12 @@ return rule; } -void CSSParserImpl::ParseStyleSheet( +ParseSheetResult CSSParserImpl::ParseStyleSheet( const String& string, const CSSParserContext* context, StyleSheetContents* style_sheet, - CSSDeferPropertyParsing defer_property_parsing) { + CSSDeferPropertyParsing defer_property_parsing, + bool allow_import_rules) { TRACE_EVENT_BEGIN2("blink,blink_style", "CSSParserImpl::parseStyleSheet", "baseUrl", context->BaseURL().GetString().Utf8(), "mode", context->Mode()); @@ -260,10 +261,16 @@ parser.lazy_state_ = new CSSLazyParsingState(context, string, parser.style_sheet_); } + ParseSheetResult result = ParseSheetResult::kSucceeded; bool first_rule_valid = parser.ConsumeRuleList( - stream, kTopLevelRuleList, [&style_sheet](StyleRuleBase* rule) { + stream, kTopLevelRuleList, + [&style_sheet, &result, allow_import_rules](StyleRuleBase* rule) { if (rule->IsCharsetRule()) return; + if (rule->IsImportRule() && !allow_import_rules) { + result = ParseSheetResult::kHasUnallowedImportRule; + return; + } style_sheet->ParserAppendRule(rule); }); style_sheet->SetHasSyntacticallyValidCSSHeader(first_rule_valid); @@ -272,6 +279,7 @@ TRACE_EVENT_END2("blink,blink_style", "CSSParserImpl::parseStyleSheet", "tokenCount", tokenizer.TokenCount(), "length", string.length()); + return result; } CSSSelectorList CSSParserImpl::ParsePageSelector(
diff --git a/third_party/blink/renderer/core/css/parser/css_parser_impl.h b/third_party/blink/renderer/core/css/parser/css_parser_impl.h index e53aa95..37bf28a0 100644 --- a/third_party/blink/renderer/core/css/parser/css_parser_impl.h +++ b/third_party/blink/renderer/core/css/parser/css_parser_impl.h
@@ -38,6 +38,11 @@ class StyleSheetContents; class Element; +enum class ParseSheetResult { + kSucceeded, + kHasUnallowedImportRule, +}; + class CSSParserImpl { STACK_ALLOCATED(); @@ -95,11 +100,12 @@ const CSSParserContext*, StyleSheetContents*, AllowedRulesType); - static void ParseStyleSheet( + static ParseSheetResult ParseStyleSheet( const String&, const CSSParserContext*, StyleSheetContents*, - CSSDeferPropertyParsing = CSSDeferPropertyParsing::kNo); + CSSDeferPropertyParsing = CSSDeferPropertyParsing::kNo, + bool allow_import_rules = true); static CSSSelectorList ParsePageSelector(CSSParserTokenRange, StyleSheetContents*);
diff --git a/third_party/blink/renderer/core/css/style_sheet_contents.cc b/third_party/blink/renderer/core/css/style_sheet_contents.cc index 2ec89e30..0725d4d7 100644 --- a/third_party/blink/renderer/core/css/style_sheet_contents.cc +++ b/third_party/blink/renderer/core/css/style_sheet_contents.cc
@@ -377,16 +377,21 @@ parse_histogram.CountMicroseconds(parse_duration); } -void StyleSheetContents::ParseString(const String& sheet_text) { - ParseStringAtPosition(sheet_text, TextPosition::MinimumPosition()); +ParseSheetResult StyleSheetContents::ParseString(const String& sheet_text, + bool allow_import_rules) { + return ParseStringAtPosition(sheet_text, TextPosition::MinimumPosition(), + allow_import_rules); } -void StyleSheetContents::ParseStringAtPosition( +ParseSheetResult StyleSheetContents::ParseStringAtPosition( const String& sheet_text, - const TextPosition& start_position) { + const TextPosition& start_position, + bool allow_import_rules) { const CSSParserContext* context = CSSParserContext::CreateWithStyleSheetContents(ParserContext(), this); - CSSParser::ParseSheet(context, this, sheet_text); + return CSSParser::ParseSheet(context, this, sheet_text, + CSSDeferPropertyParsing::kNo, + allow_import_rules); } bool StyleSheetContents::IsLoading() const {
diff --git a/third_party/blink/renderer/core/css/style_sheet_contents.h b/third_party/blink/renderer/core/css/style_sheet_contents.h index 2d0ebf2bd..acf6156 100644 --- a/third_party/blink/renderer/core/css/style_sheet_contents.h +++ b/third_party/blink/renderer/core/css/style_sheet_contents.h
@@ -44,6 +44,7 @@ class StyleRuleFontFace; class StyleRuleImport; class StyleRuleNamespace; +enum class ParseSheetResult; class CORE_EXPORT StyleSheetContents : public GarbageCollectedFinalized<StyleSheetContents> { @@ -72,8 +73,10 @@ void ParseAuthorStyleSheet(const CSSStyleSheetResource*, const SecurityOrigin*); - void ParseString(const String&); - void ParseStringAtPosition(const String&, const TextPosition&); + ParseSheetResult ParseString(const String&, bool allow_import_rules = true); + ParseSheetResult ParseStringAtPosition(const String&, + const TextPosition&, + bool allow_import_rules = true); bool IsCacheableForResource() const; bool IsCacheableForStyleElement() const;
diff --git a/third_party/blink/renderer/core/dom/document.cc b/third_party/blink/renderer/core/dom/document.cc index 882a1f35..4ee3c52b 100644 --- a/third_party/blink/renderer/core/dom/document.cc +++ b/third_party/blink/renderer/core/dom/document.cc
@@ -1143,12 +1143,33 @@ // at once here because CSS parsing is done synchronously on the main thread. // TODO(rakina): Find a way to improve this. CSSStyleSheet* sheet = CSSStyleSheet::Create(*this, options, exception_state); - sheet->SetText(text); + sheet->SetText(text, true /* allow_import_rules */, exception_state); sheet->SetAssociatedDocument(this); return ScriptPromise::Cast(script_state, ScriptValue::From(script_state, sheet)); } +CSSStyleSheet* Document::createCSSStyleSheetSync( + ScriptState* script_state, + const String& text, + ExceptionState& exception_state) { + return Document::createCSSStyleSheetSync( + script_state, text, CSSStyleSheetInit(), exception_state); +} + +CSSStyleSheet* Document::createCSSStyleSheetSync( + ScriptState* script_state, + const String& text, + const CSSStyleSheetInit& options, + ExceptionState& exception_state) { + CSSStyleSheet* sheet = CSSStyleSheet::Create(*this, options, exception_state); + sheet->SetText(text, false /* allow_import_rules */, exception_state); + if (exception_state.HadException()) + return nullptr; + sheet->SetAssociatedDocument(this); + return sheet; +} + CSSStyleSheet* Document::createEmptyCSSStyleSheet( ScriptState* script_state, const CSSStyleSheetInit& options,
diff --git a/third_party/blink/renderer/core/dom/document.h b/third_party/blink/renderer/core/dom/document.h index a78b81b..e5e5704 100644 --- a/third_party/blink/renderer/core/dom/document.h +++ b/third_party/blink/renderer/core/dom/document.h
@@ -377,6 +377,15 @@ const CSSStyleSheetInit&, ExceptionState&); + CSSStyleSheet* createCSSStyleSheetSync(ScriptState*, + const String&, + const CSSStyleSheetInit&, + ExceptionState&); + + CSSStyleSheet* createCSSStyleSheetSync(ScriptState*, + const String&, + ExceptionState&); + Element* ElementFromPoint(double x, double y) const; HeapVector<Member<Element>> ElementsFromPoint(double x, double y) const; Range* caretRangeFromPoint(int x, int y);
diff --git a/third_party/blink/renderer/core/dom/document.idl b/third_party/blink/renderer/core/dom/document.idl index b822ea1..83d8beb 100644 --- a/third_party/blink/renderer/core/dom/document.idl +++ b/third_party/blink/renderer/core/dom/document.idl
@@ -75,6 +75,7 @@ [NewObject] Range createRange(); [CallWith=ScriptState, NewObject, RaisesException, RuntimeEnabled=ConstructableStylesheets] Promise<CSSStyleSheet> createCSSStyleSheet(DOMString text, optional CSSStyleSheetInit options); + [CallWith=ScriptState, NewObject, RaisesException, RuntimeEnabled=ConstructableStylesheets] CSSStyleSheet createCSSStyleSheetSync(DOMString text, optional CSSStyleSheetInit options); [CallWith=ScriptState, NewObject, RaisesException, RuntimeEnabled=ConstructableStylesheets] CSSStyleSheet createEmptyCSSStyleSheet(optional CSSStyleSheetInit options);
diff --git a/third_party/blink/renderer/core/frame/ad_tracker.cc b/third_party/blink/renderer/core/frame/ad_tracker.cc index e42b890..89f672f 100644 --- a/third_party/blink/renderer/core/frame/ad_tracker.cc +++ b/third_party/blink/renderer/core/frame/ad_tracker.cc
@@ -9,13 +9,29 @@ #include "third_party/blink/renderer/bindings/core/v8/source_location.h" #include "third_party/blink/renderer/bindings/core/v8/v8_binding_for_core.h" #include "third_party/blink/renderer/core/core_probe_sink.h" +#include "third_party/blink/renderer/core/dom/document.h" #include "third_party/blink/renderer/core/frame/local_frame.h" #include "third_party/blink/renderer/core/probe/core_probes.h" #include "third_party/blink/renderer/platform/loader/fetch/resource_request.h" #include "third_party/blink/renderer/platform/weborigin/kurl.h" +#include "third_party/blink/renderer/platform/wtf/casting.h" namespace blink { +namespace { + +bool IsKnownAdExecutionContext(ExecutionContext* execution_context) { + // TODO(jkarlin): Do the same check for worker contexts. + if (auto* document = DynamicTo<Document>(execution_context)) { + LocalFrame* frame = document->GetFrame(); + if (frame && frame->IsAdSubframe()) + return true; + } + return false; +} + +} // namespace + AdTracker::AdTracker(LocalFrame* local_root) : local_root_(local_root) { local_root_->GetProbeSink()->addAdTracker(this); } @@ -110,6 +126,11 @@ if (!execution_context) return false; + // If we're in an ad context, then no matter what the executing script is it's + // considered an ad. + if (IsKnownAdExecutionContext(execution_context)) + return true; + // The pseudo-stack contains entry points into the stack (e.g., when v8 is // executed) but not the entire stack. It's cheap to retrieve the top of the // stack so scan that as well. @@ -131,6 +152,12 @@ if (!execution_context) return false; + // TODO(jkarlin): Minor memory optimization, stop tracking known ad scripts in + // ad contexts. This will reduce the size of executing_scripts_. Note that + // this is a minor win, as the strings are already ref-counted. + if (IsKnownAdExecutionContext(execution_context)) + return true; + auto it = known_ad_scripts_.find(execution_context); if (it == known_ad_scripts_.end()) return false;
diff --git a/third_party/blink/renderer/core/frame/ad_tracker_test.cc b/third_party/blink/renderer/core/frame/ad_tracker_test.cc index 8ff1084..c253444f 100644 --- a/third_party/blink/renderer/core/frame/ad_tracker_test.cc +++ b/third_party/blink/renderer/core/frame/ad_tracker_test.cc
@@ -211,6 +211,65 @@ EXPECT_TRUE(ad_tracker_->RequestWithUrlTaggedAsAd(kVanillaUrl)); } +// Unknown script running in an ad context should be labeled as ad script. +TEST_F(AdTrackerSimTest, ScriptDetectedByContext) { + const char kAdScriptUrl[] = "https://example.com/ad_script.js"; + SimRequest ad_script(kAdScriptUrl, "text/javascript"); + + ad_tracker_->SetAdSuffix("ad_script.js"); + + // Create an iframe that's considered an ad. + main_resource_->Complete("<body><script src='ad_script.js'></script></body>"); + ad_script.Complete(R"SCRIPT( + frame = document.createElement("iframe"); + document.body.appendChild(frame); + )SCRIPT"); + + // The child frame should be an ad subframe. + LocalFrame* child_frame = + ToLocalFrame(GetDocument().GetFrame()->Tree().FirstChild()); + EXPECT_TRUE(child_frame->IsAdSubframe()); + + // Now run unknown script in the child's context. It should be considered an + // ad based on context alone. + ad_tracker_->SetExecutionContext(child_frame->GetDocument()); + ad_tracker_->SetScriptAtTopOfStack("foo.js"); + EXPECT_TRUE(ad_tracker_->IsAdScriptInStack()); +} + +// When inline script in an ad frame inserts an iframe into a non-ad frame, the +// new frame should be considered an ad. +TEST_F(AdTrackerSimTest, InlineAdScriptRunningInNonAdContext) { + SimRequest ad_script("https://example.com/ad_script.js", "text/javascript"); + SimRequest ad_iframe("https://example.com/ad_frame.html", "text/html"); + ad_tracker_->SetAdSuffix("ad_script.js"); + + main_resource_->Complete("<body><script src='ad_script.js'></script></body>"); + ad_script.Complete(R"SCRIPT( + frame = document.createElement("iframe"); + frame.src = "ad_frame.html"; + document.body.appendChild(frame); + )SCRIPT"); + + // Verify that the new frame is an ad frame. + EXPECT_TRUE(ToLocalFrame(GetDocument().GetFrame()->Tree().FirstChild()) + ->IsAdSubframe()); + + // Create a new sibling frame to the ad frame. The ad context calls the non-ad + // context's (top frame) appendChild. + ad_iframe.Complete(R"HTML( + <script> + frame = document.createElement("iframe"); + frame.name = "ad_sibling"; + parent.document.body.appendChild(frame); + </script> + )HTML"); + + // The new sibling frame should also be identified as an ad. + EXPECT_TRUE(ToLocalFrame(GetDocument().GetFrame()->Tree().Find("ad_sibling")) + ->IsAdSubframe()); +} + // Image loaded by ad script is tagged as ad. TEST_F(AdTrackerSimTest, ImageLoadedWhileExecutingAdScript) { const char kAdUrl[] = "https://example.com/ad_script.js";
diff --git a/third_party/blink/renderer/core/frame/deprecation.cc b/third_party/blink/renderer/core/frame/deprecation.cc index de328b1b..9c7cffd 100644 --- a/third_party/blink/renderer/core/frame/deprecation.cc +++ b/third_party/blink/renderer/core/frame/deprecation.cc
@@ -609,6 +609,19 @@ WillBeRemoved("Cache.addAll() with duplicate requests", kM72, "5622587912617984")}; + case WebFeature::kRTCPeerConnectionComplexPlanBSdpUsingDefaultSdpSemantics: + return {"RTCPeerConnectionComplexPlanBSdpUsingDefaultSdpSemantics", kM72, + String::Format( + "\"Complex\" Plan B SDP detected! Chrome will switch the " + "default sdpSemantics in %s from 'plan-b' to the " + "standardized 'unified-plan' format and this peer connection " + "is relying on the default sdpSemantics. This SDP is not " + "compatible with Unified Plan and will be rejected by " + "clients expecting Unified Plan. For more information about " + "how to prepare for the switch, see " + "https://webrtc.org/web-apis/chrome/unified-plan/.", + MilestoneString(kM72))}; + // Features that aren't deprecated don't have a deprecation message. default: return {"NotDeprecated", kUnknown, ""};
diff --git a/third_party/blink/renderer/core/frame/local_frame.cc b/third_party/blink/renderer/core/frame/local_frame.cc index 2bd4094..339d96d 100644 --- a/third_party/blink/renderer/core/frame/local_frame.cc +++ b/third_party/blink/renderer/core/frame/local_frame.cc
@@ -58,6 +58,7 @@ #include "third_party/blink/renderer/core/editing/serializers/serialization.h" #include "third_party/blink/renderer/core/editing/spellcheck/spell_checker.h" #include "third_party/blink/renderer/core/editing/suggestion/text_suggestion_controller.h" +#include "third_party/blink/renderer/core/events/current_input_event.h" #include "third_party/blink/renderer/core/exported/web_plugin_container_impl.h" #include "third_party/blink/renderer/core/frame/ad_tracker.h" #include "third_party/blink/renderer/core/frame/content_settings_client.h" @@ -458,6 +459,9 @@ nullptr, loader_.ResourceRequestForReload(load_type, client_redirect_policy)); request.SetClientRedirect(client_redirect_policy); + if (const WebInputEvent* input_event = CurrentInputEvent::Get()) { + request.SetInputStartTime(input_event->TimeStamp()); + } loader_.StartNavigation(request, load_type); } else { DCHECK_EQ(WebFrameLoadType::kReload, load_type);
diff --git a/third_party/blink/renderer/core/frame/use_counter_test.cc b/third_party/blink/renderer/core/frame/use_counter_test.cc index 7670a6c4b..abdd32b 100644 --- a/third_party/blink/renderer/core/frame/use_counter_test.cc +++ b/third_party/blink/renderer/core/frame/use_counter_test.cc
@@ -321,6 +321,46 @@ EXPECT_TRUE(UseCounter::IsCounted(document, feature)); } +TEST_F(UseCounterTest, CSSFlexibleBox) { + std::unique_ptr<DummyPageHolder> dummy_page_holder = + DummyPageHolder::Create(IntSize(800, 600)); + Page::InsertOrdinaryPageForTesting(&dummy_page_holder->GetPage()); + Document& document = dummy_page_holder->GetDocument(); + WebFeature feature = WebFeature::kCSSFlexibleBox; + EXPECT_FALSE(UseCounter::IsCounted(document, feature)); + document.documentElement()->SetInnerHTMLFromString( + "<div style='display: flex;'>flexbox</div>"); + document.View()->UpdateAllLifecyclePhases(); + EXPECT_TRUE(UseCounter::IsCounted(document, feature)); +} + +TEST_F(UseCounterTest, CSSFlexibleBoxInline) { + std::unique_ptr<DummyPageHolder> dummy_page_holder = + DummyPageHolder::Create(IntSize(800, 600)); + Page::InsertOrdinaryPageForTesting(&dummy_page_holder->GetPage()); + Document& document = dummy_page_holder->GetDocument(); + WebFeature feature = WebFeature::kCSSFlexibleBox; + EXPECT_FALSE(UseCounter::IsCounted(document, feature)); + document.documentElement()->SetInnerHTMLFromString( + "<div style='display: inline-flex;'>flexbox</div>"); + document.View()->UpdateAllLifecyclePhases(); + EXPECT_TRUE(UseCounter::IsCounted(document, feature)); +} + +TEST_F(UseCounterTest, CSSFlexibleBoxButton) { + // LayoutButton is a subclass of LayoutFlexibleBox, however we don't want it + // to be counted as usage of flexboxes as it's an implementation detail. + std::unique_ptr<DummyPageHolder> dummy_page_holder = + DummyPageHolder::Create(IntSize(800, 600)); + Page::InsertOrdinaryPageForTesting(&dummy_page_holder->GetPage()); + Document& document = dummy_page_holder->GetDocument(); + WebFeature feature = WebFeature::kCSSFlexibleBox; + EXPECT_FALSE(UseCounter::IsCounted(document, feature)); + document.documentElement()->SetInnerHTMLFromString("<button>button</button>"); + document.View()->UpdateAllLifecyclePhases(); + EXPECT_FALSE(UseCounter::IsCounted(document, feature)); +} + class DeprecationTest : public testing::Test { public: DeprecationTest()
diff --git a/third_party/blink/renderer/core/html/canvas/text_metrics.cc b/third_party/blink/renderer/core/html/canvas/text_metrics.cc index 008ee9d..1be8a7e 100644 --- a/third_party/blink/renderer/core/html/canvas/text_metrics.cc +++ b/third_party/blink/renderer/core/html/canvas/text_metrics.cc
@@ -13,40 +13,23 @@ float TextMetrics::GetFontBaseline(const TextBaseline& text_baseline, const SimpleFontData& font_data) { FontMetrics font_metrics = font_data.GetFontMetrics(); - // If the font is so tiny that the lroundf operations result in two - // different types of text baselines to return the same baseline, use - // floating point metrics (crbug.com/338908). - // If you changed the heuristic here, for consistency please also change it - // in SimpleFontData::platformInit(). - bool use_float_ascent_descent = font_data.EmHeightAscent().ToInt() < 4; switch (text_baseline) { case kTopTextBaseline: - return use_float_ascent_descent - ? font_data.EmHeightAscent().ToFloat() - : lround(font_data.EmHeightAscent().ToFloat()); + return font_data.EmHeightAscent().ToFloat(); case kHangingTextBaseline: // According to // http://wiki.apache.org/xmlgraphics-fop/LineLayout/AlignmentHandling // "FOP (Formatting Objects Processor) puts the hanging baseline at 80% of // the ascender height" - return use_float_ascent_descent - ? font_metrics.FloatAscent() * kHangingAsPercentOfAscent / 100 - : font_metrics.Ascent() * kHangingAsPercentOfAscent / 100; + return font_metrics.FloatAscent() * kHangingAsPercentOfAscent / 100.0; case kIdeographicTextBaseline: - return use_float_ascent_descent ? -font_metrics.FloatDescent() - : -font_metrics.Descent(); + return -font_metrics.FloatDescent(); case kBottomTextBaseline: - return use_float_ascent_descent - ? -font_data.EmHeightDescent().ToFloat() - : -lround(font_data.EmHeightDescent().ToFloat()); + return -font_data.EmHeightDescent().ToFloat(); case kMiddleTextBaseline: - return use_float_ascent_descent - ? (-font_data.EmHeightDescent() + font_data.EmHeightAscent()) - .ToFloat() / - 2.0f - : (-lround(font_data.EmHeightDescent().ToFloat()) + - lround(font_data.EmHeightAscent().ToFloat())) / - 2; + return (font_data.EmHeightAscent().ToFloat() - + font_data.EmHeightDescent().ToFloat()) / + 2.0f; case kAlphabeticTextBaseline: default: // Do nothing.
diff --git a/third_party/blink/renderer/core/inspector/inspector_style_sheet.cc b/third_party/blink/renderer/core/inspector/inspector_style_sheet.cc index a2e86069..7426bd9 100644 --- a/third_party/blink/renderer/core/inspector/inspector_style_sheet.cc +++ b/third_party/blink/renderer/core/inspector/inspector_style_sheet.cc
@@ -1005,9 +1005,11 @@ return url.IsEmpty() ? document_url_ : url; } -bool InspectorStyleSheet::SetText(const String& text, ExceptionState&) { +bool InspectorStyleSheet::SetText(const String& text, + ExceptionState& exception_state) { InnerSetText(text, true); - page_style_sheet_->SetText(text); + page_style_sheet_->SetText(text, true /* allow_import_rules */, + exception_state); OnStyleSheetTextChanged(); return true; }
diff --git a/third_party/blink/renderer/core/inspector/main_thread_debugger.cc b/third_party/blink/renderer/core/inspector/main_thread_debugger.cc index a6db1eb..1af591c7 100644 --- a/third_party/blink/renderer/core/inspector/main_thread_debugger.cc +++ b/third_party/blink/renderer/core/inspector/main_thread_debugger.cc
@@ -60,7 +60,7 @@ #include "third_party/blink/renderer/core/loader/document_loader.h" #include "third_party/blink/renderer/core/page/page.h" #include "third_party/blink/renderer/core/timing/memory_info.h" -#include "third_party/blink/renderer/core/workers/main_thread_worklet_global_scope.h" +#include "third_party/blink/renderer/core/workers/worklet_global_scope.h" #include "third_party/blink/renderer/core/xml/xpath_evaluator.h" #include "third_party/blink/renderer/core/xml/xpath_result.h" #include "third_party/blink/renderer/platform/bindings/dom_wrapper_world.h" @@ -82,7 +82,7 @@ if (auto* document = DynamicTo<Document>(context)) return document->GetFrame(); if (context->IsMainThreadWorkletGlobalScope()) - return ToMainThreadWorkletGlobalScope(context)->GetFrame(); + return ToWorkletGlobalScope(context)->GetFrame(); return nullptr; } } @@ -179,12 +179,11 @@ script_state = event->World() ? ToScriptState(frame, *event->World()) : nullptr; } else if (context->IsMainThreadWorkletGlobalScope()) { - frame = ToMainThreadWorkletGlobalScope(context)->GetFrame(); + frame = ToWorkletGlobalScope(context)->GetFrame(); if (!frame) return; - script_state = ToMainThreadWorkletGlobalScope(context) - ->ScriptController() - ->GetScriptState(); + script_state = + ToWorkletGlobalScope(context)->ScriptController()->GetScriptState(); } else { NOTREACHED(); }
diff --git a/third_party/blink/renderer/core/inspector/worker_thread_debugger.cc b/third_party/blink/renderer/core/inspector/worker_thread_debugger.cc index 55ea1c13c..32c028f 100644 --- a/third_party/blink/renderer/core/inspector/worker_thread_debugger.cc +++ b/third_party/blink/renderer/core/inspector/worker_thread_debugger.cc
@@ -39,7 +39,6 @@ #include "third_party/blink/renderer/core/inspector/identifiers_factory.h" #include "third_party/blink/renderer/core/inspector/v8_inspector_string.h" #include "third_party/blink/renderer/core/inspector/worker_inspector_controller.h" -#include "third_party/blink/renderer/core/workers/threaded_worklet_global_scope.h" #include "third_party/blink/renderer/core/workers/worker_global_scope.h" #include "third_party/blink/renderer/core/workers/worker_reporting_proxy.h" #include "third_party/blink/renderer/core/workers/worker_thread.h"
diff --git a/third_party/blink/renderer/core/layout/custom/css_layout_definition.cc b/third_party/blink/renderer/core/layout/custom/css_layout_definition.cc index e4ae9b6e..e94d9fc 100644 --- a/third_party/blink/renderer/core/layout/custom/css_layout_definition.cc +++ b/third_party/blink/renderer/core/layout/custom/css_layout_definition.cc
@@ -66,7 +66,7 @@ CSSLayoutDefinition::~CSSLayoutDefinition() = default; CSSLayoutDefinition::Instance::Instance(CSSLayoutDefinition* definition, - v8::Local<v8::Object> instance) + v8::Local<v8::Value> instance) : definition_(definition), instance_(definition->script_state_->GetIsolate(), instance) {} @@ -84,7 +84,7 @@ ScriptState::Scope scope(script_state); v8::Isolate* isolate = script_state->GetIsolate(); - v8::Local<v8::Object> instance = instance_.NewLocal(isolate); + v8::Local<v8::Value> instance = instance_.NewLocal(isolate); v8::Local<v8::Context> context = script_state->GetContext(); v8::Local<v8::Function> layout = definition_->layout_.NewLocal(isolate); @@ -310,8 +310,9 @@ v8::Local<v8::Function> constructor = constructor_.NewLocal(isolate); DCHECK(!IsUndefinedOrNull(constructor)); - v8::Local<v8::Object> layout_instance; - if (V8ObjectConstructor::NewInstance(isolate, constructor) + v8::Local<v8::Value> layout_instance; + if (V8ScriptRunner::CallAsConstructor( + isolate, constructor, ExecutionContext::From(script_state_), 0, {}) .ToLocal(&layout_instance)) { instance = new Instance(this, layout_instance); } else {
diff --git a/third_party/blink/renderer/core/layout/custom/css_layout_definition.h b/third_party/blink/renderer/core/layout/custom/css_layout_definition.h index ffba10e7..bec75b9 100644 --- a/third_party/blink/renderer/core/layout/custom/css_layout_definition.h +++ b/third_party/blink/renderer/core/layout/custom/css_layout_definition.h
@@ -43,7 +43,7 @@ // CSSLayoutDefinition. class Instance final : public GarbageCollectedFinalized<Instance> { public: - Instance(CSSLayoutDefinition*, v8::Local<v8::Object> instance); + Instance(CSSLayoutDefinition*, v8::Local<v8::Value> instance); // Runs the web developer defined layout, returns true if everything // succeeded. It populates the FragmentResultOptions dictionary, and @@ -58,7 +58,7 @@ void ReportException(ExceptionState*); Member<CSSLayoutDefinition> definition_; - ScopedPersistent<v8::Object> instance_; + ScopedPersistent<v8::Value> instance_; }; // Creates an instance of the web developer defined class. May return a
diff --git a/third_party/blink/renderer/core/layout/custom/layout_worklet_global_scope.cc b/third_party/blink/renderer/core/layout/custom/layout_worklet_global_scope.cc index b5dde5c3..01d4e46d 100644 --- a/third_party/blink/renderer/core/layout/custom/layout_worklet_global_scope.cc +++ b/third_party/blink/renderer/core/layout/custom/layout_worklet_global_scope.cc
@@ -44,9 +44,7 @@ std::unique_ptr<GlobalScopeCreationParams> creation_params, WorkerReportingProxy& reporting_proxy, PendingLayoutRegistry* pending_layout_registry) - : MainThreadWorkletGlobalScope(frame, - std::move(creation_params), - reporting_proxy), + : WorkletGlobalScope(std::move(creation_params), reporting_proxy, frame), pending_layout_registry_(pending_layout_registry) {} LayoutWorkletGlobalScope::~LayoutWorkletGlobalScope() = default; @@ -55,7 +53,7 @@ MainThreadDebugger::Instance()->ContextWillBeDestroyed( ScriptController()->GetScriptState()); - MainThreadWorkletGlobalScope::Dispose(); + WorkletGlobalScope::Dispose(); } // https://drafts.css-houdini.org/css-layout-api/#dom-layoutworkletglobalscope-registerlayout @@ -161,7 +159,7 @@ void LayoutWorkletGlobalScope::Trace(blink::Visitor* visitor) { visitor->Trace(layout_definitions_); visitor->Trace(pending_layout_registry_); - MainThreadWorkletGlobalScope::Trace(visitor); + WorkletGlobalScope::Trace(visitor); } } // namespace blink
diff --git a/third_party/blink/renderer/core/layout/custom/layout_worklet_global_scope.h b/third_party/blink/renderer/core/layout/custom/layout_worklet_global_scope.h index a351858..b66123b3 100644 --- a/third_party/blink/renderer/core/layout/custom/layout_worklet_global_scope.h +++ b/third_party/blink/renderer/core/layout/custom/layout_worklet_global_scope.h
@@ -9,7 +9,7 @@ #include "third_party/blink/renderer/core/core_export.h" #include "third_party/blink/renderer/core/execution_context/execution_context.h" #include "third_party/blink/renderer/core/layout/custom/pending_layout_registry.h" -#include "third_party/blink/renderer/core/workers/main_thread_worklet_global_scope.h" +#include "third_party/blink/renderer/core/workers/worklet_global_scope.h" #include "third_party/blink/renderer/platform/bindings/script_wrappable.h" namespace blink { @@ -17,8 +17,7 @@ class CSSLayoutDefinition; class WorkerReportingProxy; -class CORE_EXPORT LayoutWorkletGlobalScope final - : public MainThreadWorkletGlobalScope { +class CORE_EXPORT LayoutWorkletGlobalScope final : public WorkletGlobalScope { DEFINE_WRAPPERTYPEINFO(); USING_GARBAGE_COLLECTED_MIXIN(LayoutWorkletGlobalScope);
diff --git a/third_party/blink/renderer/core/layout/layout_flexible_box.cc b/third_party/blink/renderer/core/layout/layout_flexible_box.cc index 0922fc49..6fdc8c1 100644 --- a/third_party/blink/renderer/core/layout/layout_flexible_box.cc +++ b/third_party/blink/renderer/core/layout/layout_flexible_box.cc
@@ -60,8 +60,6 @@ has_definite_height_(SizeDefiniteness::kUnknown), in_layout_(false) { DCHECK(!ChildrenInline()); - if (!IsAnonymous()) - UseCounter::Count(GetDocument(), WebFeature::kCSSFlexibleBox); } LayoutFlexibleBox::~LayoutFlexibleBox() = default;
diff --git a/third_party/blink/renderer/core/layout/layout_grid.cc b/third_party/blink/renderer/core/layout/layout_grid.cc index d5e2450..5b944636 100644 --- a/third_party/blink/renderer/core/layout/layout_grid.cc +++ b/third_party/blink/renderer/core/layout/layout_grid.cc
@@ -49,8 +49,6 @@ grid_(Grid::Create(this)), track_sizing_algorithm_(this, *grid_) { DCHECK(!ChildrenInline()); - if (!IsAnonymous()) - UseCounter::Count(GetDocument(), WebFeature::kCSSGridLayout); } LayoutGrid::~LayoutGrid() = default;
diff --git a/third_party/blink/renderer/core/layout/layout_object.cc b/third_party/blink/renderer/core/layout/layout_object.cc index 34be920..8c557fe 100644 --- a/third_party/blink/renderer/core/layout/layout_object.cc +++ b/third_party/blink/renderer/core/layout/layout_object.cc
@@ -268,9 +268,11 @@ return new LayoutDeprecatedFlexibleBox(*element); case EDisplay::kFlex: case EDisplay::kInlineFlex: + UseCounter::Count(element->GetDocument(), WebFeature::kCSSFlexibleBox); return LayoutObjectFactory::CreateFlexibleBox(*element, style); case EDisplay::kGrid: case EDisplay::kInlineGrid: + UseCounter::Count(element->GetDocument(), WebFeature::kCSSGridLayout); return new LayoutGrid(element); case EDisplay::kLayoutCustom: case EDisplay::kInlineLayoutCustom:
diff --git a/third_party/blink/renderer/core/loader/modulescript/module_script_loader.cc b/third_party/blink/renderer/core/loader/modulescript/module_script_loader.cc index f5f7541..6c178a27 100644 --- a/third_party/blink/renderer/core/loader/modulescript/module_script_loader.cc +++ b/third_party/blink/renderer/core/loader/modulescript/module_script_loader.cc
@@ -11,7 +11,6 @@ #include "third_party/blink/renderer/core/loader/modulescript/module_script_loader_registry.h" #include "third_party/blink/renderer/core/script/modulator.h" #include "third_party/blink/renderer/core/script/module_script.h" -#include "third_party/blink/renderer/core/workers/main_thread_worklet_global_scope.h" #include "third_party/blink/renderer/platform/loader/fetch/fetch_client_settings_object_snapshot.h" #include "third_party/blink/renderer/platform/loader/fetch/resource.h" #include "third_party/blink/renderer/platform/loader/fetch/resource_loader_options.h"
diff --git a/third_party/blink/renderer/core/loader/modulescript/module_script_loader_test.cc b/third_party/blink/renderer/core/loader/modulescript/module_script_loader_test.cc index 546a991..d2c856f 100644 --- a/third_party/blink/renderer/core/loader/modulescript/module_script_loader_test.cc +++ b/third_party/blink/renderer/core/loader/modulescript/module_script_loader_test.cc
@@ -23,8 +23,8 @@ #include "third_party/blink/renderer/core/testing/dummy_modulator.h" #include "third_party/blink/renderer/core/testing/page_test_base.h" #include "third_party/blink/renderer/core/workers/global_scope_creation_params.h" -#include "third_party/blink/renderer/core/workers/main_thread_worklet_global_scope.h" #include "third_party/blink/renderer/core/workers/main_thread_worklet_reporting_proxy.h" +#include "third_party/blink/renderer/core/workers/worklet_global_scope.h" #include "third_party/blink/renderer/core/workers/worklet_module_responses_map.h" #include "third_party/blink/renderer/platform/heap/handle.h" #include "third_party/blink/renderer/platform/loader/fetch/fetch_client_settings_object_snapshot.h" @@ -157,7 +157,7 @@ ScopedTestingPlatformSupport<FetchTestingPlatformSupport> platform_; std::unique_ptr<MainThreadWorkletReportingProxy> reporting_proxy_; Persistent<ModuleScriptLoaderTestModulator> modulator_; - Persistent<MainThreadWorkletGlobalScope> global_scope_; + Persistent<WorkletGlobalScope> global_scope_; }; void ModuleScriptLoaderTest::SetUp() { @@ -191,8 +191,8 @@ OriginTrialContext::GetTokens(&GetDocument()).get(), base::UnguessableToken::Create(), nullptr /* worker_settings */, kV8CacheOptionsDefault, new WorkletModuleResponsesMap); - global_scope_ = new MainThreadWorkletGlobalScope( - &GetFrame(), std::move(creation_params), *reporting_proxy_); + global_scope_ = new WorkletGlobalScope(std::move(creation_params), + *reporting_proxy_, &GetFrame()); global_scope_->ScriptController()->InitializeContextIfNeeded("Dummy Context", NullURL()); modulator_ = new ModuleScriptLoaderTestModulator(
diff --git a/third_party/blink/renderer/core/loader/resource/image_resource.cc b/third_party/blink/renderer/core/loader/resource/image_resource.cc index fc163ab88..24a6612 100644 --- a/third_party/blink/renderer/core/loader/resource/image_resource.cc +++ b/third_party/blink/renderer/core/loader/resource/image_resource.cc
@@ -399,7 +399,9 @@ if (!all_data_received && Loader()) { // Observers are notified via ImageResource::finish(). // TODO(hiroshige): Do not call didFinishLoading() directly. - Loader()->DidFinishLoading(CurrentTimeTicks(), size, size, size, false); + Loader()->DidFinishLoading( + CurrentTimeTicks(), size, size, size, false, + std::vector<network::cors::PreflightTimingInfo>()); } else { auto result = GetContent()->UpdateImage( nullptr, GetStatus(),
diff --git a/third_party/blink/renderer/core/loader/resource/image_resource_test.cc b/third_party/blink/renderer/core/loader/resource/image_resource_test.cc index 740aecd..d2b51d1f 100644 --- a/third_party/blink/renderer/core/loader/resource/image_resource_test.cc +++ b/third_party/blink/renderer/core/loader/resource/image_resource_test.cc
@@ -226,8 +226,9 @@ image_resource->Loader()->DidReceiveResponse( WrappedResourceResponse(resource_response)); image_resource->Loader()->DidReceiveData(data, kDataLength); - image_resource->Loader()->DidFinishLoading(TimeTicks(), kDataLength, - kDataLength, kDataLength, false); + image_resource->Loader()->DidFinishLoading( + TimeTicks(), kDataLength, kDataLength, kDataLength, false, + std::vector<network::cors::PreflightTimingInfo>()); // Checks |imageResource|'s status after reloading. EXPECT_EQ(ResourceStatus::kCached, image_resource->GetStatus()); @@ -285,7 +286,8 @@ image_resource->Loader()->DidFinishLoading( TimeTicks(), kJpegImageSubrangeWithDimensionsLength, kJpegImageSubrangeWithDimensionsLength, - kJpegImageSubrangeWithDimensionsLength, false); + kJpegImageSubrangeWithDimensionsLength, false, + std::vector<network::cors::PreflightTimingInfo>()); // Checks that |imageResource| is successfully loaded, showing a placeholder. EXPECT_EQ(ResourceStatus::kCached, image_resource->GetStatus()); @@ -325,9 +327,9 @@ WrappedResourceResponse(resource_response)); image_resource->Loader()->DidReceiveData( reinterpret_cast<const char*>(kJpegImage), sizeof(kJpegImage)); - image_resource->Loader()->DidFinishLoading(TimeTicks(), sizeof(kJpegImage), - sizeof(kJpegImage), - sizeof(kJpegImage), false); + image_resource->Loader()->DidFinishLoading( + TimeTicks(), sizeof(kJpegImage), sizeof(kJpegImage), sizeof(kJpegImage), + false, std::vector<network::cors::PreflightTimingInfo>()); // Checks that |imageResource| is successfully loaded, // showing a non-placeholder image. @@ -421,7 +423,9 @@ // This part finishes. The image is created, callbacks are sent, and the data // buffer is cleared. - image_resource->Loader()->DidFinishLoading(TimeTicks(), 0, 0, 0, false); + image_resource->Loader()->DidFinishLoading( + TimeTicks(), 0, 0, 0, false, + std::vector<network::cors::PreflightTimingInfo>()); EXPECT_TRUE(image_resource->ResourceBuffer()); EXPECT_FALSE(image_resource->ErrorOccurred()); ASSERT_TRUE(image_resource->GetContent()->HasImage()); @@ -464,7 +468,9 @@ image_resource->AppendData(reinterpret_cast<const char*>(kJpegImage), sizeof(kJpegImage)); image_resource->AppendData(kBoundary, strlen(kBoundary)); - image_resource->Loader()->DidFinishLoading(TimeTicks(), 0, 0, 0, false); + image_resource->Loader()->DidFinishLoading( + TimeTicks(), 0, 0, 0, false, + std::vector<network::cors::PreflightTimingInfo>()); EXPECT_TRUE(image_resource->GetContent()->HasImage()); EXPECT_TRUE(image_resource->GetContent()->GetImage()->IsBitmapImage()); EXPECT_TRUE(image_resource->GetContent() @@ -811,9 +817,9 @@ WrappedResourceResponse(resource_response)); image_resource->Loader()->DidReceiveData( reinterpret_cast<const char*>(kJpegImage), sizeof(kJpegImage)); - image_resource->Loader()->DidFinishLoading(TimeTicks(), sizeof(kJpegImage), - sizeof(kJpegImage), - sizeof(kJpegImage), false); + image_resource->Loader()->DidFinishLoading( + TimeTicks(), sizeof(kJpegImage), sizeof(kJpegImage), sizeof(kJpegImage), + false, std::vector<network::cors::PreflightTimingInfo>()); EXPECT_TRUE(observer->ImageNotifyFinishedCalled()); EXPECT_EQ(image_resource, fetcher->CachedResource(test_url)); @@ -1315,7 +1321,9 @@ EXPECT_FALSE(observer->ImageNotifyFinishedCalled()); EXPECT_EQ(0, observer->ImageChangedCount()); - image_resource->Loader()->DidFinishLoading(TimeTicks(), 0, 0, 0, false); + image_resource->Loader()->DidFinishLoading( + TimeTicks(), 0, 0, 0, false, + std::vector<network::cors::PreflightTimingInfo>()); EXPECT_EQ(ResourceStatus::kDecodeError, image_resource->GetStatus()); EXPECT_TRUE(observer->ImageNotifyFinishedCalled()); @@ -1362,7 +1370,8 @@ image_resource->Loader()->DidFinishLoading( TimeTicks(), kJpegImageSubrangeWithoutDimensionsLength, kJpegImageSubrangeWithoutDimensionsLength, - kJpegImageSubrangeWithoutDimensionsLength, false); + kJpegImageSubrangeWithoutDimensionsLength, false, + std::vector<network::cors::PreflightTimingInfo>()); EXPECT_EQ(ResourceStatus::kDecodeError, image_resource->GetStatus()); EXPECT_TRUE(observer->ImageNotifyFinishedCalled()); @@ -1592,7 +1601,8 @@ image_resource->Loader()->DidFinishLoading( TimeTicks(), kJpegImageSubrangeWithoutDimensionsLength, kJpegImageSubrangeWithoutDimensionsLength, - kJpegImageSubrangeWithoutDimensionsLength, false); + kJpegImageSubrangeWithoutDimensionsLength, false, + std::vector<network::cors::PreflightTimingInfo>()); EXPECT_FALSE(observer->ImageNotifyFinishedCalled()); EXPECT_EQ(2, observer->ImageChangedCount()); @@ -1731,9 +1741,9 @@ WrappedResourceResponse(resource_response)); image_resource->Loader()->DidReceiveData( reinterpret_cast<const char*>(kJpegImage), sizeof(kJpegImage)); - image_resource->Loader()->DidFinishLoading(TimeTicks(), sizeof(kJpegImage), - sizeof(kJpegImage), - sizeof(kJpegImage), false); + image_resource->Loader()->DidFinishLoading( + TimeTicks(), sizeof(kJpegImage), sizeof(kJpegImage), sizeof(kJpegImage), + false, std::vector<network::cors::PreflightTimingInfo>()); EXPECT_EQ(ResourceStatus::kCached, image_resource->GetStatus()); EXPECT_EQ(sizeof(kJpegImage), image_resource->EncodedSize());
diff --git a/third_party/blink/renderer/core/page/create_window.cc b/third_party/blink/renderer/core/page/create_window.cc index 3d3f5683..94645c02 100644 --- a/third_party/blink/renderer/core/page/create_window.cc +++ b/third_party/blink/renderer/core/page/create_window.cc
@@ -493,6 +493,9 @@ // TODO(japhet): Form submissions on RemoteFrames don't work yet. FrameLoadRequest new_request(nullptr, request.GetResourceRequest()); new_request.SetForm(request.Form()); + if (const WebInputEvent* input_event = CurrentInputEvent::Get()) { + new_request.SetInputStartTime(input_event->TimeStamp()); + } auto blob_url_token = request.GetBlobURLToken(); if (blob_url_token) new_request.SetBlobURLToken(std::move(blob_url_token));
diff --git a/third_party/blink/renderer/core/paint/image_paint_timing_detector.cc b/third_party/blink/renderer/core/paint/image_paint_timing_detector.cc index 491ca9b..fdeee5f 100644 --- a/third_party/blink/renderer/core/paint/image_paint_timing_detector.cc +++ b/third_party/blink/renderer/core/paint/image_paint_timing_detector.cc
@@ -20,7 +20,7 @@ // Set a big enough limit for the number of nodes to ensure memory usage is // capped. Exceeding such limit will deactivate the algorithm. -constexpr size_t kNodeNumberLimit = 5000; +constexpr size_t kImageNodeNumberLimit = 5000; static bool LargeImageOnTop(const base::WeakPtr<ImageRecord>& a, const base::WeakPtr<ImageRecord>& b) { @@ -197,7 +197,7 @@ const LayoutImage* image = ToLayoutImage(&object); if (!id_record_map_.Contains(node_id)) { recorded_node_count_++; - if (recorded_node_count_ < kNodeNumberLimit) { + if (recorded_node_count_ < kImageNodeNumberLimit) { LayoutRect invalidated_rect = image->FirstFragment().VisualRect(); // Do not record first size until invalidated_rect's size becomes // non-empty. @@ -226,7 +226,7 @@ latest_image_heap_.push(record->AsWeakPtr()); id_record_map_.insert(node_id, std::move(record)); } else { - // for assessing whether kNodeNumberLimit is large enough for all + // for assessing whether kImageNodeNumberLimit is large enough for all // normal cases TRACE_EVENT_INSTANT1("loading", "ImagePaintTimingDetector::OverNodeLimit", TRACE_EVENT_SCOPE_THREAD, "recorded_node_count",
diff --git a/third_party/blink/renderer/core/paint/text_paint_timing_detector.cc b/third_party/blink/renderer/core/paint/text_paint_timing_detector.cc index 06c99469..6d0cd0b 100644 --- a/third_party/blink/renderer/core/paint/text_paint_timing_detector.cc +++ b/third_party/blink/renderer/core/paint/text_paint_timing_detector.cc
@@ -20,7 +20,7 @@ // Calculate metrics candidate every 1 second after the first text pre-paint. static constexpr TimeDelta kTimerDelay = TimeDelta::FromSeconds(1); -constexpr size_t kNodeNumberLimit = 5000; +constexpr size_t kTextNodeNumberLimit = 5000; static bool LargeTextOnTop(const std::unique_ptr<TextRecord>& a, const std::unique_ptr<TextRecord>& b) { @@ -164,8 +164,8 @@ // We deactivate the algorithm if the number of nodes exceeds limitation. recorded_node_count_++; - if (recorded_node_count_ > kNodeNumberLimit) { - // for assessing whether kNodeNumberLimit is large enough for all + if (recorded_node_count_ > kTextNodeNumberLimit) { + // for assessing whether kTextNodeNumberLimit is large enough for all // normal cases TRACE_EVENT_INSTANT1("loading", "TextPaintTimingDetector::OverNodeLimit", TRACE_EVENT_SCOPE_THREAD, "recorded_node_count",
diff --git a/third_party/blink/renderer/core/style/computed_style.cc b/third_party/blink/renderer/core/style/computed_style.cc index 3d23acb..a948d68 100644 --- a/third_party/blink/renderer/core/style/computed_style.cc +++ b/third_party/blink/renderer/core/style/computed_style.cc
@@ -1558,37 +1558,6 @@ return *TransitionsInternal(); } -const Font& ComputedStyle::GetFont() const { - return FontInternal(); -} -const FontDescription& ComputedStyle::GetFontDescription() const { - return FontInternal().GetFontDescription(); -} -float ComputedStyle::SpecifiedFontSize() const { - return GetFontDescription().SpecifiedSize(); -} -float ComputedStyle::ComputedFontSize() const { - return GetFontDescription().ComputedSize(); -} -LayoutUnit ComputedStyle::ComputedFontSizeAsFixed() const { - return LayoutUnit::FromFloatRound(GetFontDescription().ComputedSize()); -} -int ComputedStyle::FontSize() const { - return GetFontDescription().ComputedPixelSize(); -} -float ComputedStyle::FontSizeAdjust() const { - return GetFontDescription().SizeAdjust(); -} -bool ComputedStyle::HasFontSizeAdjust() const { - return GetFontDescription().HasSizeAdjust(); -} -FontSelectionValue ComputedStyle::GetFontWeight() const { - return GetFontDescription().Weight(); -} -FontSelectionValue ComputedStyle::GetFontStretch() const { - return GetFontDescription().Stretch(); -} - FontBaseline ComputedStyle::GetFontBaseline() const { // TODO(kojii): Incorporate 'dominant-baseline' when we support it. // https://www.w3.org/TR/css-inline-3/#dominant-baseline-property @@ -1731,13 +1700,6 @@ return GetRegisteredVariable(name, true); } -float ComputedStyle::WordSpacing() const { - return GetFontDescription().WordSpacing(); -} -float ComputedStyle::LetterSpacing() const { - return GetFontDescription().LetterSpacing(); -} - bool ComputedStyle::SetFontDescription(const FontDescription& v) { if (FontInternal().GetFontDescription() != v) { SetFontInternal(Font(v)); @@ -1746,10 +1708,6 @@ return false; } -void ComputedStyle::SetFont(const Font& font) { - SetFontInternal(font); -} - bool ComputedStyle::HasIdenticalAscentDescentAndLineGap( const ComputedStyle& other) const { const SimpleFontData* font_data = GetFont().PrimaryFont(); @@ -1759,10 +1717,6 @@ other_font_data->GetFontMetrics()); } -const Length& ComputedStyle::SpecifiedLineHeight() const { - return LineHeightInternal(); -} - Length ComputedStyle::LineHeight() const { const Length& lh = LineHeightInternal(); // Unlike getFontDescription().computedSize() and hence fontSize(), this is
diff --git a/third_party/blink/renderer/core/style/computed_style.h b/third_party/blink/renderer/core/style/computed_style.h index 31420083..ce17d0e5 100644 --- a/third_party/blink/renderer/core/style/computed_style.h +++ b/third_party/blink/renderer/core/style/computed_style.h
@@ -899,27 +899,41 @@ } // Font properties. - CORE_EXPORT const Font& GetFont() const; - CORE_EXPORT void SetFont(const Font&); - CORE_EXPORT const FontDescription& GetFontDescription() const; + CORE_EXPORT const Font& GetFont() const { return FontInternal(); } + CORE_EXPORT void SetFont(const Font& font) { SetFontInternal(font); } + CORE_EXPORT const FontDescription& GetFontDescription() const { + return FontInternal().GetFontDescription(); + } CORE_EXPORT bool SetFontDescription(const FontDescription&); bool HasIdenticalAscentDescentAndLineGap(const ComputedStyle& other) const; // font-size - int FontSize() const; - CORE_EXPORT float SpecifiedFontSize() const; - CORE_EXPORT float ComputedFontSize() const; - LayoutUnit ComputedFontSizeAsFixed() const; + int FontSize() const { return GetFontDescription().ComputedPixelSize(); } + CORE_EXPORT float SpecifiedFontSize() const { + return GetFontDescription().SpecifiedSize(); + } + CORE_EXPORT float ComputedFontSize() const { + return GetFontDescription().ComputedSize(); + } + LayoutUnit ComputedFontSizeAsFixed() const { + return LayoutUnit::FromFloatRound(GetFontDescription().ComputedSize()); + } // font-size-adjust - float FontSizeAdjust() const; - bool HasFontSizeAdjust() const; + float FontSizeAdjust() const { return GetFontDescription().SizeAdjust(); } + bool HasFontSizeAdjust() const { + return GetFontDescription().HasSizeAdjust(); + } // font-weight - CORE_EXPORT FontSelectionValue GetFontWeight() const; + CORE_EXPORT FontSelectionValue GetFontWeight() const { + return GetFontDescription().Weight(); + } // font-stretch - FontSelectionValue GetFontStretch() const; + FontSelectionValue GetFontStretch() const { + return GetFontDescription().Stretch(); + } // Child is aligned to the parent by matching the parent’s dominant baseline // to the same baseline in the child. @@ -933,7 +947,7 @@ // FIXME: Remove letter-spacing/word-spacing and replace them with respective // FontBuilder calls. letter-spacing - float LetterSpacing() const; + float LetterSpacing() const { return GetFontDescription().LetterSpacing(); } void SetLetterSpacing(float); // tab-size @@ -949,7 +963,7 @@ } // word-spacing - float WordSpacing() const; + float WordSpacing() const { return GetFontDescription().WordSpacing(); } void SetWordSpacing(float); // orphans @@ -1327,7 +1341,7 @@ void ApplyTextTransform(String*, UChar previous_character = ' ') const; // Line-height utility functions. - const Length& SpecifiedLineHeight() const; + const Length& SpecifiedLineHeight() const { return LineHeightInternal(); } int ComputedLineHeight() const; LayoutUnit ComputedLineHeightAsFixed() const;
diff --git a/third_party/blink/renderer/core/svg/svg_document_extensions.cc b/third_party/blink/renderer/core/svg/svg_document_extensions.cc index 7c1efbc..3283831 100644 --- a/third_party/blink/renderer/core/svg/svg_document_extensions.cc +++ b/third_party/blink/renderer/core/svg/svg_document_extensions.cc
@@ -140,9 +140,8 @@ } bool SVGDocumentExtensions::ZoomAndPanEnabled() const { - if (SVGSVGElement* svg = rootElement(*document_)) - return svg->ZoomAndPanEnabled(); - return false; + SVGSVGElement* svg = rootElement(*document_); + return !svg || svg->ZoomAndPanEnabled(); } void SVGDocumentExtensions::StartPan(const FloatPoint& start) {
diff --git a/third_party/blink/renderer/core/testing/data/png-16bit/2x2_16bit_e-sRGB_opaque.png b/third_party/blink/renderer/core/testing/data/png-16bit/2x2_16bit_e-sRGB_opaque.png index 557e947..1c72bad 100644 --- a/third_party/blink/renderer/core/testing/data/png-16bit/2x2_16bit_e-sRGB_opaque.png +++ b/third_party/blink/renderer/core/testing/data/png-16bit/2x2_16bit_e-sRGB_opaque.png Binary files differ
diff --git a/third_party/blink/renderer/core/testing/data/png-16bit/2x2_16bit_e-sRGB_transparent.png b/third_party/blink/renderer/core/testing/data/png-16bit/2x2_16bit_e-sRGB_transparent.png index b9a7806..b7ed23c2 100644 --- a/third_party/blink/renderer/core/testing/data/png-16bit/2x2_16bit_e-sRGB_transparent.png +++ b/third_party/blink/renderer/core/testing/data/png-16bit/2x2_16bit_e-sRGB_transparent.png Binary files differ
diff --git a/third_party/blink/renderer/core/testing/data/png-16bit/2x2_16bit_interlaced_e-sRGB_opaque.png b/third_party/blink/renderer/core/testing/data/png-16bit/2x2_16bit_interlaced_e-sRGB_opaque.png index 6763c036..1c72bad 100644 --- a/third_party/blink/renderer/core/testing/data/png-16bit/2x2_16bit_interlaced_e-sRGB_opaque.png +++ b/third_party/blink/renderer/core/testing/data/png-16bit/2x2_16bit_interlaced_e-sRGB_opaque.png Binary files differ
diff --git a/third_party/blink/renderer/core/testing/data/png-16bit/2x2_16bit_interlaced_e-sRGB_transparent.png b/third_party/blink/renderer/core/testing/data/png-16bit/2x2_16bit_interlaced_e-sRGB_transparent.png index 05aa36e..b7ed23c2 100644 --- a/third_party/blink/renderer/core/testing/data/png-16bit/2x2_16bit_interlaced_e-sRGB_transparent.png +++ b/third_party/blink/renderer/core/testing/data/png-16bit/2x2_16bit_interlaced_e-sRGB_transparent.png Binary files differ
diff --git a/third_party/blink/renderer/core/testing/sim/sim_network.cc b/third_party/blink/renderer/core/testing/sim/sim_network.cc index ad25aa1..45df1df 100644 --- a/third_party/blink/renderer/core/testing/sim/sim_network.cc +++ b/third_party/blink/renderer/core/testing/sim/sim_network.cc
@@ -79,7 +79,8 @@ if (!current_request_) { client->DidFinishLoading(finish_time, total_encoded_data_length, total_encoded_body_length, - total_decoded_body_length, false); + total_decoded_body_length, false, + std::vector<network::cors::PreflightTimingInfo>()); return; } current_request_ = nullptr;
diff --git a/third_party/blink/renderer/core/testing/sim/sim_request.cc b/third_party/blink/renderer/core/testing/sim/sim_request.cc index e6ff8a79..29db248 100644 --- a/third_party/blink/renderer/core/testing/sim/sim_request.cc +++ b/third_party/blink/renderer/core/testing/sim/sim_request.cc
@@ -68,9 +68,10 @@ total_encoded_data_length_, total_encoded_data_length_); } else { // TODO(esprehn): Is claiming a request time of 0 okay for tests? - client_->DidFinishLoading(TimeTicks(), total_encoded_data_length_, - total_encoded_data_length_, - total_encoded_data_length_, false); + client_->DidFinishLoading( + TimeTicks(), total_encoded_data_length_, total_encoded_data_length_, + total_encoded_data_length_, false, + std::vector<network::cors::PreflightTimingInfo>()); } Reset(); }
diff --git a/third_party/blink/renderer/core/workers/BUILD.gn b/third_party/blink/renderer/core/workers/BUILD.gn index d0c15c1..3c36f4d 100644 --- a/third_party/blink/renderer/core/workers/BUILD.gn +++ b/third_party/blink/renderer/core/workers/BUILD.gn
@@ -30,8 +30,6 @@ "global_scope_creation_params.h", "installed_scripts_manager.cc", "installed_scripts_manager.h", - "main_thread_worklet_global_scope.cc", - "main_thread_worklet_global_scope.h", "main_thread_worklet_reporting_proxy.cc", "main_thread_worklet_reporting_proxy.h", "parent_execution_context_task_runners.cc", @@ -51,8 +49,6 @@ "threaded_messaging_proxy_base.h", "threaded_object_proxy_base.cc", "threaded_object_proxy_base.h", - "threaded_worklet_global_scope.cc", - "threaded_worklet_global_scope.h", "threaded_worklet_messaging_proxy.cc", "threaded_worklet_messaging_proxy.h", "threaded_worklet_object_proxy.cc",
diff --git a/third_party/blink/renderer/core/workers/README.md b/third_party/blink/renderer/core/workers/README.md index 06723ad..067971989 100644 --- a/third_party/blink/renderer/core/workers/README.md +++ b/third_party/blink/renderer/core/workers/README.md
@@ -18,7 +18,7 @@ - `WorkerOrWorklet` prefix: Classes commonly used for workers and worklets (e.g., `WorkerOrWorkletGlobalScope`). - `Worker` / `Worklet` prefix: Classes used for workers or worklets (e.g., `WorkerGlobalScope`). - `Threaded` prefix: Classes used for workers and threaded worklets (e.g., `ThreadedMessagingProxyBase`). -- `MainThreadWorklet` prefix: Classes used for main thread worklets (e.g., `MainThreadWorkletGlobalScope`). +- `MainThreadWorklet` prefix: Classes used for main thread worklets (e.g., `MainThreadWorkletReportingProxy`). Thread hopping between the main (parent) thread and a worker thread is handled by proxy classes.
diff --git a/third_party/blink/renderer/core/workers/main_thread_worklet_global_scope.cc b/third_party/blink/renderer/core/workers/main_thread_worklet_global_scope.cc deleted file mode 100644 index 55cf44e7..0000000 --- a/third_party/blink/renderer/core/workers/main_thread_worklet_global_scope.cc +++ /dev/null
@@ -1,64 +0,0 @@ -// Copyright 2016 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "third_party/blink/renderer/core/workers/main_thread_worklet_global_scope.h" - -#include "third_party/blink/renderer/bindings/core/v8/v8_binding_for_core.h" -#include "third_party/blink/renderer/bindings/core/v8/worker_or_worklet_script_controller.h" -#include "third_party/blink/renderer/core/dom/document.h" -#include "third_party/blink/renderer/core/frame/deprecation.h" -#include "third_party/blink/renderer/core/frame/frame_console.h" -#include "third_party/blink/renderer/core/frame/local_frame.h" -#include "third_party/blink/renderer/core/inspector/main_thread_debugger.h" -#include "third_party/blink/renderer/core/probe/core_probes.h" -#include "third_party/blink/renderer/core/workers/global_scope_creation_params.h" - -namespace blink { - -MainThreadWorkletGlobalScope::MainThreadWorkletGlobalScope( - LocalFrame* frame, - std::unique_ptr<GlobalScopeCreationParams> creation_params, - WorkerReportingProxy& reporting_proxy) - : WorkletGlobalScope(std::move(creation_params), - ToIsolate(frame), - reporting_proxy), - ContextClient(frame) { - BindContentSecurityPolicyToExecutionContext(); -} - -MainThreadWorkletGlobalScope::~MainThreadWorkletGlobalScope() = default; - -WorkerThread* MainThreadWorkletGlobalScope::GetThread() const { - NOTREACHED(); - return nullptr; -} - -scoped_refptr<base::SingleThreadTaskRunner> -MainThreadWorkletGlobalScope::GetTaskRunner(TaskType type) { - DCHECK(IsContextThread()); - // MainThreadWorkletGlobalScope lives on the main thread and its GetThread() - // doesn't return a valid worker thread. Instead, retrieve a task runner - // from the frame. - return GetFrame()->GetFrameScheduler()->GetTaskRunner(type); -} - -void MainThreadWorkletGlobalScope::AddConsoleMessage( - ConsoleMessage* console_message) { - GetFrame()->Console().AddMessage(console_message); -} - -void MainThreadWorkletGlobalScope::ExceptionThrown(ErrorEvent* event) { - MainThreadDebugger::Instance()->ExceptionThrown(this, event); -} - -CoreProbeSink* MainThreadWorkletGlobalScope::GetProbeSink() { - return probe::ToCoreProbeSink(GetFrame()); -} - -void MainThreadWorkletGlobalScope::Trace(blink::Visitor* visitor) { - WorkletGlobalScope::Trace(visitor); - ContextClient::Trace(visitor); -} - -} // namespace blink
diff --git a/third_party/blink/renderer/core/workers/main_thread_worklet_global_scope.h b/third_party/blink/renderer/core/workers/main_thread_worklet_global_scope.h deleted file mode 100644 index 2b78ae1..0000000 --- a/third_party/blink/renderer/core/workers/main_thread_worklet_global_scope.h +++ /dev/null
@@ -1,53 +0,0 @@ -// Copyright 2016 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_WORKERS_MAIN_THREAD_WORKLET_GLOBAL_SCOPE_H_ -#define THIRD_PARTY_BLINK_RENDERER_CORE_WORKERS_MAIN_THREAD_WORKLET_GLOBAL_SCOPE_H_ - -#include "base/single_thread_task_runner.h" -#include "third_party/blink/renderer/core/core_export.h" -#include "third_party/blink/renderer/core/dom/context_lifecycle_observer.h" -#include "third_party/blink/renderer/core/execution_context/execution_context.h" -#include "third_party/blink/renderer/core/workers/worklet_global_scope.h" - -namespace blink { - -class ConsoleMessage; -class LocalFrame; -class WorkerReportingProxy; - -class CORE_EXPORT MainThreadWorkletGlobalScope - : public WorkletGlobalScope, - public ContextClient { - USING_GARBAGE_COLLECTED_MIXIN(MainThreadWorkletGlobalScope); - - public: - MainThreadWorkletGlobalScope(LocalFrame*, - std::unique_ptr<GlobalScopeCreationParams>, - WorkerReportingProxy&); - ~MainThreadWorkletGlobalScope() override; - - bool IsMainThreadWorkletGlobalScope() const final { return true; } - - // WorkerOrWorkletGlobalScope - WorkerThread* GetThread() const final; - scoped_refptr<base::SingleThreadTaskRunner> GetTaskRunner(TaskType) override; - - // ExecutionContext - void AddConsoleMessage(ConsoleMessage*) final; - void ExceptionThrown(ErrorEvent*) final; - CoreProbeSink* GetProbeSink() final; - - void Trace(blink::Visitor*) override; -}; - -DEFINE_TYPE_CASTS(MainThreadWorkletGlobalScope, - ExecutionContext, - context, - context->IsMainThreadWorkletGlobalScope(), - context.IsMainThreadWorkletGlobalScope()); - -} // namespace blink - -#endif // THIRD_PARTY_BLINK_RENDERER_CORE_WORKERS_MAIN_THREAD_WORKLET_GLOBAL_SCOPE_H_
diff --git a/third_party/blink/renderer/core/workers/main_thread_worklet_test.cc b/third_party/blink/renderer/core/workers/main_thread_worklet_test.cc index 9393910..6771bef6 100644 --- a/third_party/blink/renderer/core/workers/main_thread_worklet_test.cc +++ b/third_party/blink/renderer/core/workers/main_thread_worklet_test.cc
@@ -11,8 +11,8 @@ #include "third_party/blink/renderer/core/script/script.h" #include "third_party/blink/renderer/core/testing/page_test_base.h" #include "third_party/blink/renderer/core/workers/global_scope_creation_params.h" -#include "third_party/blink/renderer/core/workers/main_thread_worklet_global_scope.h" #include "third_party/blink/renderer/core/workers/main_thread_worklet_reporting_proxy.h" +#include "third_party/blink/renderer/core/workers/worklet_global_scope.h" #include "third_party/blink/renderer/core/workers/worklet_module_responses_map.h" #include "third_party/blink/renderer/platform/weborigin/security_origin.h" @@ -72,15 +72,17 @@ OriginTrialContext::GetTokens(document).get(), base::UnguessableToken::Create(), nullptr /* worker_settings */, kV8CacheOptionsDefault, new WorkletModuleResponsesMap); - global_scope_ = new MainThreadWorkletGlobalScope( - &GetFrame(), std::move(creation_params), *reporting_proxy_); + global_scope_ = new WorkletGlobalScope(std::move(creation_params), + *reporting_proxy_, &GetFrame()); + EXPECT_TRUE(global_scope_->IsMainThreadWorkletGlobalScope()); + EXPECT_FALSE(global_scope_->IsThreadedWorkletGlobalScope()); } void TearDown() override { global_scope_->Dispose(); } protected: std::unique_ptr<MainThreadWorkletReportingProxyForTest> reporting_proxy_; - Persistent<MainThreadWorkletGlobalScope> global_scope_; + Persistent<WorkletGlobalScope> global_scope_; }; class MainThreadWorkletInvalidCSPTest : public MainThreadWorkletTest { @@ -117,7 +119,7 @@ // This feature is randomly selected. const WebFeature kFeature1 = WebFeature::kRequestFileSystem; - // API use on the MainThreadWorkletGlobalScope should be recorded in + // API use on WorkletGlobalScope for the main thread should be recorded in // UseCounter on the Document. EXPECT_FALSE(UseCounter::IsCounted(GetDocument(), kFeature1)); UseCounter::Count(global_scope_, kFeature1); @@ -130,8 +132,8 @@ // This feature is randomly selected from Deprecation::deprecationMessage(). const WebFeature kFeature2 = WebFeature::kPrefixedStorageInfo; - // Deprecated API use on the MainThreadWorkletGlobalScope should be recorded - // in UseCounter on the Document. + // Deprecated API use on WorkletGlobalScope for the main thread should be + // recorded in UseCounter on the Document. EXPECT_FALSE(UseCounter::IsCounted(GetDocument(), kFeature2)); Deprecation::CountDeprecation(global_scope_, kFeature2); EXPECT_TRUE(UseCounter::IsCounted(GetDocument(), kFeature2));
diff --git a/third_party/blink/renderer/core/workers/threaded_worklet_global_scope.cc b/third_party/blink/renderer/core/workers/threaded_worklet_global_scope.cc deleted file mode 100644 index 41f9b198..0000000 --- a/third_party/blink/renderer/core/workers/threaded_worklet_global_scope.cc +++ /dev/null
@@ -1,63 +0,0 @@ -// Copyright 2016 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "third_party/blink/renderer/core/workers/threaded_worklet_global_scope.h" - -#include "base/memory/scoped_refptr.h" -#include "third_party/blink/public/platform/platform.h" -#include "third_party/blink/renderer/core/inspector/console_message.h" -#include "third_party/blink/renderer/core/inspector/console_message_storage.h" -#include "third_party/blink/renderer/core/inspector/worker_thread_debugger.h" -#include "third_party/blink/renderer/core/workers/global_scope_creation_params.h" -#include "third_party/blink/renderer/core/workers/worker_reporting_proxy.h" -#include "third_party/blink/renderer/core/workers/worker_thread.h" -#include "third_party/blink/renderer/platform/weborigin/kurl.h" -#include "third_party/blink/renderer/platform/weborigin/security_origin.h" -#include "third_party/blink/renderer/platform/wtf/assertions.h" - -namespace blink { - -ThreadedWorkletGlobalScope::ThreadedWorkletGlobalScope( - std::unique_ptr<GlobalScopeCreationParams> creation_params, - v8::Isolate* isolate, - WorkerThread* thread) - : WorkletGlobalScope(std::move(creation_params), - isolate, - thread->GetWorkerReportingProxy()), - thread_(thread) { - BindContentSecurityPolicyToExecutionContext(); -} - -ThreadedWorkletGlobalScope::~ThreadedWorkletGlobalScope() { - DCHECK(!thread_); -} - -void ThreadedWorkletGlobalScope::Dispose() { - DCHECK(IsContextThread()); - WorkletGlobalScope::Dispose(); - thread_ = nullptr; -} - -bool ThreadedWorkletGlobalScope::IsContextThread() const { - return GetThread()->IsCurrentThread(); -} - -void ThreadedWorkletGlobalScope::AddConsoleMessage( - ConsoleMessage* console_message) { - DCHECK(IsContextThread()); - GetThread()->GetWorkerReportingProxy().ReportConsoleMessage( - console_message->Source(), console_message->Level(), - console_message->Message(), console_message->Location()); - GetThread()->GetConsoleMessageStorage()->AddConsoleMessage(this, - console_message); -} - -void ThreadedWorkletGlobalScope::ExceptionThrown(ErrorEvent* error_event) { - DCHECK(IsContextThread()); - if (WorkerThreadDebugger* debugger = - WorkerThreadDebugger::From(GetThread()->GetIsolate())) - debugger->ExceptionThrown(thread_, error_event); -} - -} // namespace blink
diff --git a/third_party/blink/renderer/core/workers/threaded_worklet_global_scope.h b/third_party/blink/renderer/core/workers/threaded_worklet_global_scope.h deleted file mode 100644 index 1755998..0000000 --- a/third_party/blink/renderer/core/workers/threaded_worklet_global_scope.h +++ /dev/null
@@ -1,48 +0,0 @@ -// Copyright 2016 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_WORKERS_THREADED_WORKLET_GLOBAL_SCOPE_H_ -#define THIRD_PARTY_BLINK_RENDERER_CORE_WORKERS_THREADED_WORKLET_GLOBAL_SCOPE_H_ - -#include "third_party/blink/renderer/core/core_export.h" -#include "third_party/blink/renderer/core/workers/worklet_global_scope.h" - -namespace blink { - -class WorkerThread; -struct GlobalScopeCreationParams; - -class CORE_EXPORT ThreadedWorkletGlobalScope : public WorkletGlobalScope { - public: - ~ThreadedWorkletGlobalScope() override; - void Dispose() override; - - // ExecutionContext - bool IsThreadedWorkletGlobalScope() const final { return true; } - bool IsContextThread() const final; - void AddConsoleMessage(ConsoleMessage*) final; - void ExceptionThrown(ErrorEvent*) final; - - WorkerThread* GetThread() const override { return thread_; } - - protected: - ThreadedWorkletGlobalScope(std::unique_ptr<GlobalScopeCreationParams>, - v8::Isolate*, - WorkerThread*); - - private: - friend class ThreadedWorkletThreadForTest; - - WorkerThread* thread_; -}; - -DEFINE_TYPE_CASTS(ThreadedWorkletGlobalScope, - ExecutionContext, - context, - context->IsThreadedWorkletGlobalScope(), - context.IsThreadedWorkletGlobalScope()); - -} // namespace blink - -#endif // THIRD_PARTY_BLINK_RENDERER_CORE_WORKERS_THREADED_WORKLET_GLOBAL_SCOPE_H_
diff --git a/third_party/blink/renderer/core/workers/threaded_worklet_object_proxy.cc b/third_party/blink/renderer/core/workers/threaded_worklet_object_proxy.cc index 7dbe518..b98c1b5f 100644 --- a/third_party/blink/renderer/core/workers/threaded_worklet_object_proxy.cc +++ b/third_party/blink/renderer/core/workers/threaded_worklet_object_proxy.cc
@@ -8,9 +8,9 @@ #include <utility> #include "base/memory/ptr_util.h" -#include "third_party/blink/renderer/core/workers/threaded_worklet_global_scope.h" #include "third_party/blink/renderer/core/workers/threaded_worklet_messaging_proxy.h" #include "third_party/blink/renderer/core/workers/worker_thread.h" +#include "third_party/blink/renderer/core/workers/worklet_global_scope.h" #include "third_party/blink/renderer/platform/loader/fetch/fetch_client_settings_object_snapshot.h" namespace blink { @@ -33,8 +33,8 @@ scoped_refptr<base::SingleThreadTaskRunner> outside_settings_task_runner, WorkletPendingTasks* pending_tasks, WorkerThread* worker_thread) { - ThreadedWorkletGlobalScope* global_scope = - ToThreadedWorkletGlobalScope(worker_thread->GlobalScope()); + WorkletGlobalScope* global_scope = + ToWorkletGlobalScope(worker_thread->GlobalScope()); global_scope->FetchAndInvokeScript( module_url_record, credentials_mode, new FetchClientSettingsObjectSnapshot(std::move(outside_settings_object)),
diff --git a/third_party/blink/renderer/core/workers/threaded_worklet_test.cc b/third_party/blink/renderer/core/workers/threaded_worklet_test.cc index abb4481..4b9d485 100644 --- a/third_party/blink/renderer/core/workers/threaded_worklet_test.cc +++ b/third_party/blink/renderer/core/workers/threaded_worklet_test.cc
@@ -12,11 +12,11 @@ #include "third_party/blink/renderer/core/script/script.h" #include "third_party/blink/renderer/core/testing/dummy_page_holder.h" #include "third_party/blink/renderer/core/workers/global_scope_creation_params.h" -#include "third_party/blink/renderer/core/workers/threaded_worklet_global_scope.h" #include "third_party/blink/renderer/core/workers/threaded_worklet_messaging_proxy.h" #include "third_party/blink/renderer/core/workers/threaded_worklet_object_proxy.h" #include "third_party/blink/renderer/core/workers/worker_thread.h" #include "third_party/blink/renderer/core/workers/worker_thread_test_helper.h" +#include "third_party/blink/renderer/core/workers/worklet_global_scope.h" #include "third_party/blink/renderer/core/workers/worklet_module_responses_map.h" #include "third_party/blink/renderer/core/workers/worklet_thread_holder.h" #include "third_party/blink/renderer/platform/cross_thread_functional.h" @@ -133,7 +133,7 @@ FROM_HERE, CrossThreadBind(&test::ExitRunLoop)); } - // Emulates API use on ThreadedWorkletGlobalScope. + // Emulates API use on threaded WorkletGlobalScope. void CountFeature(WebFeature feature) { EXPECT_TRUE(IsCurrentThread()); GlobalScope()->CountFeature(feature); @@ -142,7 +142,7 @@ FROM_HERE, CrossThreadBind(&test::ExitRunLoop)); } - // Emulates deprecated API use on ThreadedWorkletGlobalScope. + // Emulates deprecated API use on threaded WorkletGlobalScope. void CountDeprecation(WebFeature feature) { EXPECT_TRUE(IsCurrentThread()); GlobalScope()->CountDeprecation(feature); @@ -170,8 +170,11 @@ private: WorkerOrWorkletGlobalScope* CreateWorkerGlobalScope( std::unique_ptr<GlobalScopeCreationParams> creation_params) final { - return new ThreadedWorkletGlobalScope(std::move(creation_params), - GetIsolate(), this); + auto* global_scope = new WorkletGlobalScope( + std::move(creation_params), GetWorkerReportingProxy(), this); + EXPECT_FALSE(global_scope->IsMainThreadWorkletGlobalScope()); + EXPECT_TRUE(global_scope->IsThreadedWorkletGlobalScope()); + return global_scope; } bool IsOwningBackingThread() const final { return false; } @@ -306,7 +309,7 @@ // This feature is randomly selected. const WebFeature kFeature1 = WebFeature::kRequestFileSystem; - // API use on the ThreadedWorkletGlobalScope should be recorded in UseCounter + // API use on the threaded WorkletGlobalScope should be recorded in UseCounter // on the Document. EXPECT_FALSE(UseCounter::IsCounted(GetDocument(), kFeature1)); PostCrossThreadTask( @@ -317,7 +320,7 @@ EXPECT_TRUE(UseCounter::IsCounted(GetDocument(), kFeature1)); // API use should be reported to the Document only one time. See comments in - // ThreadedWorkletGlobalScopeForTest::CountFeature. + // ThreadedWorkletObjectProxyForTest::CountFeature. PostCrossThreadTask( *GetWorkerThread()->GetTaskRunner(TaskType::kInternalTest), FROM_HERE, CrossThreadBind(&ThreadedWorkletThreadForTest::CountFeature, @@ -327,7 +330,7 @@ // This feature is randomly selected from Deprecation::deprecationMessage(). const WebFeature kFeature2 = WebFeature::kPrefixedStorageInfo; - // Deprecated API use on the ThreadedWorkletGlobalScope should be recorded in + // Deprecated API use on the threaded WorkletGlobalScope should be recorded in // UseCounter on the Document. EXPECT_FALSE(UseCounter::IsCounted(GetDocument(), kFeature2)); PostCrossThreadTask( @@ -338,7 +341,7 @@ EXPECT_TRUE(UseCounter::IsCounted(GetDocument(), kFeature2)); // API use should be reported to the Document only one time. See comments in - // ThreadedWorkletGlobalScopeForTest::CountDeprecation. + // ThreadedWorkletObjectProxyForTest::CountDeprecation. PostCrossThreadTask( *GetWorkerThread()->GetTaskRunner(TaskType::kInternalTest), FROM_HERE, CrossThreadBind(&ThreadedWorkletThreadForTest::CountDeprecation,
diff --git a/third_party/blink/renderer/core/workers/worker_or_worklet_global_scope.cc b/third_party/blink/renderer/core/workers/worker_or_worklet_global_scope.cc index b4fa359..5a0ccabb 100644 --- a/third_party/blink/renderer/core/workers/worker_or_worklet_global_scope.cc +++ b/third_party/blink/renderer/core/workers/worker_or_worklet_global_scope.cc
@@ -12,7 +12,6 @@ #include "third_party/blink/renderer/core/loader/modulescript/module_script_fetch_request.h" #include "third_party/blink/renderer/core/loader/worker_fetch_context.h" #include "third_party/blink/renderer/core/probe/core_probes.h" -#include "third_party/blink/renderer/core/workers/main_thread_worklet_global_scope.h" #include "third_party/blink/renderer/core/workers/worker_reporting_proxy.h" #include "third_party/blink/renderer/core/workers/worker_thread.h" #include "third_party/blink/renderer/platform/cross_thread_functional.h"
diff --git a/third_party/blink/renderer/core/workers/worker_or_worklet_global_scope.h b/third_party/blink/renderer/core/workers/worker_or_worklet_global_scope.h index db87f55d..afc993d 100644 --- a/third_party/blink/renderer/core/workers/worker_or_worklet_global_scope.h +++ b/third_party/blink/renderer/core/workers/worker_or_worklet_global_scope.h
@@ -83,7 +83,7 @@ void CountDeprecation(WebFeature); // May return nullptr if this global scope is not threaded (i.e., - // MainThreadWorkletGlobalScope) or after dispose() is called. + // WorkletGlobalScope for the main thread) or after Dispose() is called. virtual WorkerThread* GetThread() const = 0; ResourceFetcher* Fetcher() const override;
diff --git a/third_party/blink/renderer/core/workers/worker_thread.cc b/third_party/blink/renderer/core/workers/worker_thread.cc index 37d2c551..a231d07 100644 --- a/third_party/blink/renderer/core/workers/worker_thread.cc +++ b/third_party/blink/renderer/core/workers/worker_thread.cc
@@ -40,7 +40,6 @@ #include "third_party/blink/renderer/core/inspector/worker_thread_debugger.h" #include "third_party/blink/renderer/core/probe/core_probes.h" #include "third_party/blink/renderer/core/workers/global_scope_creation_params.h" -#include "third_party/blink/renderer/core/workers/threaded_worklet_global_scope.h" #include "third_party/blink/renderer/core/workers/worker_backing_thread.h" #include "third_party/blink/renderer/core/workers/worker_clients.h" #include "third_party/blink/renderer/core/workers/worker_global_scope.h"
diff --git a/third_party/blink/renderer/core/workers/worklet_global_scope.cc b/third_party/blink/renderer/core/workers/worklet_global_scope.cc index aea0f978..fb879e4 100644 --- a/third_party/blink/renderer/core/workers/worklet_global_scope.cc +++ b/third_party/blink/renderer/core/workers/worklet_global_scope.cc
@@ -9,12 +9,18 @@ #include "third_party/blink/renderer/bindings/core/v8/script_source_code.h" #include "third_party/blink/renderer/bindings/core/v8/source_location.h" #include "third_party/blink/renderer/bindings/core/v8/worker_or_worklet_script_controller.h" +#include "third_party/blink/renderer/core/frame/frame_console.h" +#include "third_party/blink/renderer/core/frame/local_frame.h" +#include "third_party/blink/renderer/core/inspector/console_message.h" +#include "third_party/blink/renderer/core/inspector/console_message_storage.h" #include "third_party/blink/renderer/core/inspector/main_thread_debugger.h" +#include "third_party/blink/renderer/core/inspector/worker_thread_debugger.h" #include "third_party/blink/renderer/core/origin_trials/origin_trial_context.h" #include "third_party/blink/renderer/core/probe/core_probes.h" #include "third_party/blink/renderer/core/script/modulator.h" #include "third_party/blink/renderer/core/workers/global_scope_creation_params.h" #include "third_party/blink/renderer/core/workers/worker_reporting_proxy.h" +#include "third_party/blink/renderer/core/workers/worker_thread.h" #include "third_party/blink/renderer/core/workers/worklet_module_responses_map.h" #include "third_party/blink/renderer/core/workers/worklet_module_tree_client.h" #include "third_party/blink/renderer/core/workers/worklet_pending_tasks.h" @@ -23,13 +29,38 @@ namespace blink { +WorkletGlobalScope::WorkletGlobalScope( + std::unique_ptr<GlobalScopeCreationParams> creation_params, + WorkerReportingProxy& reporting_proxy, + LocalFrame* frame) + : WorkletGlobalScope(std::move(creation_params), + reporting_proxy, + ToIsolate(frame), + ThreadType::kMainThread, + frame, + nullptr /* worker_thread */) {} + +WorkletGlobalScope::WorkletGlobalScope( + std::unique_ptr<GlobalScopeCreationParams> creation_params, + WorkerReportingProxy& reporting_proxy, + WorkerThread* worker_thread) + : WorkletGlobalScope(std::move(creation_params), + reporting_proxy, + worker_thread->GetIsolate(), + ThreadType::kOffMainThread, + nullptr /* frame */, + worker_thread) {} + // Partial implementation of the "set up a worklet environment settings object" // algorithm: // https://drafts.css-houdini.org/worklets/#script-settings-for-worklets WorkletGlobalScope::WorkletGlobalScope( std::unique_ptr<GlobalScopeCreationParams> creation_params, + WorkerReportingProxy& reporting_proxy, v8::Isolate* isolate, - WorkerReportingProxy& reporting_proxy) + ThreadType thread_type, + LocalFrame* frame, + WorkerThread* worker_thread) : WorkerOrWorkletGlobalScope(isolate, creation_params->worker_clients, reporting_proxy), @@ -42,7 +73,13 @@ https_state_(creation_params->starter_https_state), agent_cluster_id_(creation_params->agent_cluster_id.is_empty() ? base::UnguessableToken::Create() - : creation_params->agent_cluster_id) { + : creation_params->agent_cluster_id), + thread_type_(thread_type), + frame_(frame), + worker_thread_(worker_thread) { + DCHECK((thread_type_ == ThreadType::kMainThread && frame_) || + (thread_type_ == ThreadType::kOffMainThread && worker_thread_)); + // Step 2: "Let inheritedAPIBaseURL be outsideSettings's API base URL." // |url_| is the inheritedAPIBaseURL passed from the parent Document. @@ -57,6 +94,7 @@ // workletGlobalScope." InitContentSecurityPolicyFromVector( creation_params->content_security_policy_parsed_headers); + BindContentSecurityPolicyToExecutionContext(); OriginTrialContext::AddTokens(this, creation_params->origin_trial_tokens.get()); @@ -64,6 +102,14 @@ WorkletGlobalScope::~WorkletGlobalScope() = default; +bool WorkletGlobalScope::IsMainThreadWorkletGlobalScope() const { + return thread_type_ == ThreadType::kMainThread; +} + +bool WorkletGlobalScope::IsThreadedWorkletGlobalScope() const { + return thread_type_ == ThreadType::kOffMainThread; +} + ExecutionContext* WorkletGlobalScope::GetExecutionContext() const { return const_cast<WorkletGlobalScope*>(this); } @@ -78,6 +124,64 @@ return false; } +bool WorkletGlobalScope::IsContextThread() const { + if (IsMainThreadWorkletGlobalScope()) + return IsMainThread(); + return worker_thread_->IsCurrentThread(); +} + +void WorkletGlobalScope::AddConsoleMessage(ConsoleMessage* console_message) { + if (IsMainThreadWorkletGlobalScope()) { + frame_->Console().AddMessage(console_message); + return; + } + worker_thread_->GetWorkerReportingProxy().ReportConsoleMessage( + console_message->Source(), console_message->Level(), + console_message->Message(), console_message->Location()); + worker_thread_->GetConsoleMessageStorage()->AddConsoleMessage( + worker_thread_->GlobalScope(), console_message); +} + +void WorkletGlobalScope::ExceptionThrown(ErrorEvent* error_event) { + if (IsMainThreadWorkletGlobalScope()) { + MainThreadDebugger::Instance()->ExceptionThrown(this, error_event); + return; + } + if (WorkerThreadDebugger* debugger = + WorkerThreadDebugger::From(GetThread()->GetIsolate())) { + debugger->ExceptionThrown(worker_thread_, error_event); + } +} + +void WorkletGlobalScope::Dispose() { + frame_ = nullptr; + worker_thread_ = nullptr; + WorkerOrWorkletGlobalScope::Dispose(); +} + +WorkerThread* WorkletGlobalScope::GetThread() const { + DCHECK(!IsMainThreadWorkletGlobalScope()); + return worker_thread_; +} + +CoreProbeSink* WorkletGlobalScope::GetProbeSink() { + if (IsMainThreadWorkletGlobalScope()) + return probe::ToCoreProbeSink(frame_); + return nullptr; +} + +scoped_refptr<base::SingleThreadTaskRunner> WorkletGlobalScope::GetTaskRunner( + TaskType task_type) { + if (IsMainThreadWorkletGlobalScope()) + return frame_->GetFrameScheduler()->GetTaskRunner(task_type); + return worker_thread_->GetTaskRunner(task_type); +} + +LocalFrame* WorkletGlobalScope::GetFrame() const { + DCHECK(IsMainThreadWorkletGlobalScope()); + return frame_; +} + // Implementation of the first half of the "fetch and invoke a worklet script" // algorithm: // https://drafts.css-houdini.org/worklets/#fetch-and-invoke-a-worklet-script @@ -135,6 +239,7 @@ } void WorkletGlobalScope::Trace(blink::Visitor* visitor) { + visitor->Trace(frame_); WorkerOrWorkletGlobalScope::Trace(visitor); }
diff --git a/third_party/blink/renderer/core/workers/worklet_global_scope.h b/third_party/blink/renderer/core/workers/worklet_global_scope.h index bc94455..1bdbef8 100644 --- a/third_party/blink/renderer/core/workers/worklet_global_scope.h +++ b/third_party/blink/renderer/core/workers/worklet_global_scope.h
@@ -25,6 +25,13 @@ class WorkerReportingProxy; struct GlobalScopeCreationParams; +// This is an implementation of the web-exposed WorkletGlobalScope interface +// defined in the Worklets spec: +// https://drafts.css-houdini.org/worklets/#workletglobalscope +// +// This instance lives either on the main thread (main thread worklet) or a +// worker thread (threaded worklet). It's determined by constructors. See +// comments on the constructors. class CORE_EXPORT WorkletGlobalScope : public WorkerOrWorkletGlobalScope, public ActiveScriptWrappable<WorkletGlobalScope> { @@ -34,6 +41,8 @@ public: ~WorkletGlobalScope() override; + bool IsMainThreadWorkletGlobalScope() const final; + bool IsThreadedWorkletGlobalScope() const final; bool IsWorkletGlobalScope() const final { return true; } // Always returns false here as PaintWorkletGlobalScope and @@ -50,6 +59,18 @@ String UserAgent() const final { return user_agent_; } SecurityContext& GetSecurityContext() final { return *this; } bool IsSecureContext(String& error_message) const final; + bool IsContextThread() const final; + void AddConsoleMessage(ConsoleMessage*) final; + void ExceptionThrown(ErrorEvent*) final; + CoreProbeSink* GetProbeSink() final; + scoped_refptr<base::SingleThreadTaskRunner> GetTaskRunner(TaskType) final; + + // WorkerOrWorkletGlobalScope + void Dispose() override; + WorkerThread* GetThread() const final; + + virtual LocalFrame* GetFrame() const; + const base::UnguessableToken& GetAgentClusterID() const final { // Currently, worklet agents have no clearly defined owner. See // https://html.spec.whatwg.org/multipage/webappapis.html#integration-with-the-javascript-agent-cluster-formalism @@ -101,19 +122,40 @@ HttpsState GetHttpsState() const override { return https_state_; } - protected: - // Partial implementation of the "set up a worklet environment settings - // object" algorithm: - // https://drafts.css-houdini.org/worklets/#script-settings-for-worklets + // Constructs an instance as a main thread worklet. Must be called on the main + // thread. WorkletGlobalScope(std::unique_ptr<GlobalScopeCreationParams>, - v8::Isolate*, - WorkerReportingProxy&); - - void BindContentSecurityPolicyToExecutionContext() override; + WorkerReportingProxy&, + LocalFrame*); + // Constructs an instance as a threaded worklet. Must be called on a worker + // thread. + WorkletGlobalScope(std::unique_ptr<GlobalScopeCreationParams>, + WorkerReportingProxy&, + WorkerThread*); private: + enum class ThreadType { + // Indicates this global scope lives on the main thread. + kMainThread, + // Indicates this global scope lives on a worker thread. + kOffMainThread + }; + + // The base constructor delegated from other public constructors. This + // partially implements the "set up a worklet environment settings object" + // algorithm defined in the Worklets spec: + // https://drafts.css-houdini.org/worklets/#script-settings-for-worklets + WorkletGlobalScope(std::unique_ptr<GlobalScopeCreationParams>, + WorkerReportingProxy&, + v8::Isolate*, + ThreadType, + LocalFrame*, + WorkerThread*); + EventTarget* ErrorEventTarget() final { return nullptr; } + void BindContentSecurityPolicyToExecutionContext() override; + // The |url_| and |user_agent_| are inherited from the parent Document. const KURL url_; const String user_agent_; @@ -130,6 +172,12 @@ const HttpsState https_state_; const base::UnguessableToken agent_cluster_id_; + + const ThreadType thread_type_; + // |frame_| is available only when |thread_type_| is kMainThread. + Member<LocalFrame> frame_; + // |worker_thread_| is available only when |thread_type_| is kOffMainThread. + WorkerThread* worker_thread_; }; DEFINE_TYPE_CASTS(WorkletGlobalScope,
diff --git a/third_party/blink/renderer/modules/animationworklet/animation_worklet_global_scope.cc b/third_party/blink/renderer/modules/animationworklet/animation_worklet_global_scope.cc index 3becaaf..c7912c9 100644 --- a/third_party/blink/renderer/modules/animationworklet/animation_worklet_global_scope.cc +++ b/third_party/blink/renderer/modules/animationworklet/animation_worklet_global_scope.cc
@@ -8,6 +8,7 @@ #include "third_party/blink/renderer/bindings/core/v8/v8_object_parser.h" #include "third_party/blink/renderer/bindings/core/v8/worker_or_worklet_script_controller.h" #include "third_party/blink/renderer/core/workers/global_scope_creation_params.h" +#include "third_party/blink/renderer/core/workers/worker_thread.h" #include "third_party/blink/renderer/modules/animationworklet/animation_worklet_proxy_client.h" #include "third_party/blink/renderer/modules/animationworklet/worklet_animation_options.h" #include "third_party/blink/renderer/platform/bindings/exception_state.h" @@ -35,25 +36,23 @@ AnimationWorkletGlobalScope* AnimationWorkletGlobalScope::Create( std::unique_ptr<GlobalScopeCreationParams> creation_params, - v8::Isolate* isolate, WorkerThread* thread) { - return new AnimationWorkletGlobalScope(std::move(creation_params), isolate, - thread); + return new AnimationWorkletGlobalScope(std::move(creation_params), thread); } AnimationWorkletGlobalScope::AnimationWorkletGlobalScope( std::unique_ptr<GlobalScopeCreationParams> creation_params, - v8::Isolate* isolate, WorkerThread* thread) - : ThreadedWorkletGlobalScope(std::move(creation_params), isolate, thread) { -} + : WorkletGlobalScope(std::move(creation_params), + thread->GetWorkerReportingProxy(), + thread) {} AnimationWorkletGlobalScope::~AnimationWorkletGlobalScope() = default; void AnimationWorkletGlobalScope::Trace(blink::Visitor* visitor) { visitor->Trace(animator_definitions_); visitor->Trace(animators_); - ThreadedWorkletGlobalScope::Trace(visitor); + WorkletGlobalScope::Trace(visitor); } void AnimationWorkletGlobalScope::Dispose() { @@ -61,7 +60,7 @@ if (AnimationWorkletProxyClient* proxy_client = AnimationWorkletProxyClient::From(Clients())) proxy_client->Dispose(); - ThreadedWorkletGlobalScope::Dispose(); + WorkletGlobalScope::Dispose(); } Animator* AnimationWorkletGlobalScope::CreateAnimatorFor( @@ -199,9 +198,11 @@ if (options && options->GetData()) value = options->GetData()->Deserialize(isolate); - v8::Local<v8::Object> instance; - if (!V8ObjectConstructor::NewInstance(isolate, constructor, - !value.IsEmpty() ? 1 : 0, &value) + v8::Local<v8::Value> instance; + if (!V8ScriptRunner::CallAsConstructor( + isolate, constructor, + ExecutionContext::From(ScriptController()->GetScriptState()), + !value.IsEmpty() ? 1 : 0, &value) .ToLocal(&instance)) return nullptr;
diff --git a/third_party/blink/renderer/modules/animationworklet/animation_worklet_global_scope.h b/third_party/blink/renderer/modules/animationworklet/animation_worklet_global_scope.h index 3c117e8..c0ee79b 100644 --- a/third_party/blink/renderer/modules/animationworklet/animation_worklet_global_scope.h +++ b/third_party/blink/renderer/modules/animationworklet/animation_worklet_global_scope.h
@@ -6,7 +6,7 @@ #define THIRD_PARTY_BLINK_RENDERER_MODULES_ANIMATIONWORKLET_ANIMATION_WORKLET_GLOBAL_SCOPE_H_ #include "third_party/blink/renderer/bindings/core/v8/script_value.h" -#include "third_party/blink/renderer/core/workers/threaded_worklet_global_scope.h" +#include "third_party/blink/renderer/core/workers/worklet_global_scope.h" #include "third_party/blink/renderer/modules/animationworklet/animator.h" #include "third_party/blink/renderer/modules/animationworklet/animator_definition.h" #include "third_party/blink/renderer/modules/modules_export.h" @@ -27,14 +27,12 @@ // The scope keeps a map of these animator definitions and can look them up // based on their name. The scope also owns a list of active animators that it // animates. -class MODULES_EXPORT AnimationWorkletGlobalScope - : public ThreadedWorkletGlobalScope { +class MODULES_EXPORT AnimationWorkletGlobalScope : public WorkletGlobalScope { DEFINE_WRAPPERTYPEINFO(); public: static AnimationWorkletGlobalScope* Create( std::unique_ptr<GlobalScopeCreationParams>, - v8::Isolate*, WorkerThread*); ~AnimationWorkletGlobalScope() override; void Trace(blink::Visitor*) override; @@ -54,7 +52,6 @@ private: AnimationWorkletGlobalScope(std::unique_ptr<GlobalScopeCreationParams>, - v8::Isolate*, WorkerThread*); void RegisterWithProxyClientIfNeeded();
diff --git a/third_party/blink/renderer/modules/animationworklet/animation_worklet_thread.cc b/third_party/blink/renderer/modules/animationworklet/animation_worklet_thread.cc index d679d4d..6f047664 100644 --- a/third_party/blink/renderer/modules/animationworklet/animation_worklet_thread.cc +++ b/third_party/blink/renderer/modules/animationworklet/animation_worklet_thread.cc
@@ -66,8 +66,7 @@ std::unique_ptr<GlobalScopeCreationParams> creation_params) { TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("animation-worklet"), "AnimationWorkletThread::CreateWorkerGlobalScope"); - return AnimationWorkletGlobalScope::Create(std::move(creation_params), - GetIsolate(), this); + return AnimationWorkletGlobalScope::Create(std::move(creation_params), this); } } // namespace blink
diff --git a/third_party/blink/renderer/modules/animationworklet/animator.cc b/third_party/blink/renderer/modules/animationworklet/animator.cc index 8c87bd0..5faecda3 100644 --- a/third_party/blink/renderer/modules/animationworklet/animator.cc +++ b/third_party/blink/renderer/modules/animationworklet/animator.cc
@@ -15,7 +15,7 @@ Animator::Animator(v8::Isolate* isolate, AnimatorDefinition* definition, - v8::Local<v8::Object> instance) + v8::Local<v8::Value> instance) : definition_(definition), instance_(isolate, instance), effect_(new EffectProxy()) {} @@ -25,7 +25,7 @@ void Animator::Trace(blink::Visitor* visitor) { visitor->Trace(definition_); visitor->Trace(effect_); - visitor->Trace(instance_.Cast<v8::Value>()); + visitor->Trace(instance_); } bool Animator::Animate( @@ -34,7 +34,7 @@ AnimationWorkletDispatcherOutput::AnimationState* output) { v8::Isolate* isolate = script_state->GetIsolate(); - v8::Local<v8::Object> instance = instance_.NewLocal(isolate); + v8::Local<v8::Value> instance = instance_.NewLocal(isolate); v8::Local<v8::Function> animate = definition_->AnimateLocal(isolate); if (IsUndefinedOrNull(instance) || IsUndefinedOrNull(animate))
diff --git a/third_party/blink/renderer/modules/animationworklet/animator.h b/third_party/blink/renderer/modules/animationworklet/animator.h index ed8197b..c37bf14d 100644 --- a/third_party/blink/renderer/modules/animationworklet/animator.h +++ b/third_party/blink/renderer/modules/animationworklet/animator.h
@@ -25,7 +25,7 @@ class Animator final : public GarbageCollectedFinalized<Animator>, public NameClient { public: - Animator(v8::Isolate*, AnimatorDefinition*, v8::Local<v8::Object> instance); + Animator(v8::Isolate*, AnimatorDefinition*, v8::Local<v8::Value> instance); ~Animator(); void Trace(blink::Visitor*); const char* NameInHeapSnapshot() const override { return "Animator"; } @@ -44,7 +44,7 @@ // This object keeps the definition object, and animator instance alive. // It participates in wrapper tracing as it holds onto V8 wrappers. TraceWrapperMember<AnimatorDefinition> definition_; - TraceWrapperV8Reference<v8::Object> instance_; + TraceWrapperV8Reference<v8::Value> instance_; Member<EffectProxy> effect_; };
diff --git a/third_party/blink/renderer/modules/background_fetch/background_fetch_event.idl b/third_party/blink/renderer/modules/background_fetch/background_fetch_event.idl index e4c633e..65c470a 100644 --- a/third_party/blink/renderer/modules/background_fetch/background_fetch_event.idl +++ b/third_party/blink/renderer/modules/background_fetch/background_fetch_event.idl
@@ -7,7 +7,7 @@ [ Constructor(DOMString type, BackgroundFetchEventInit init), Exposed=ServiceWorker, - RuntimeEnabled=BackgroundFetch + OriginTrialEnabled=BackgroundFetch ] interface BackgroundFetchEvent : ExtendableEvent { readonly attribute BackgroundFetchRegistration registration; };
diff --git a/third_party/blink/renderer/modules/background_fetch/background_fetch_fetch.idl b/third_party/blink/renderer/modules/background_fetch/background_fetch_fetch.idl index c87e156..df03e49 100644 --- a/third_party/blink/renderer/modules/background_fetch/background_fetch_fetch.idl +++ b/third_party/blink/renderer/modules/background_fetch/background_fetch_fetch.idl
@@ -6,7 +6,7 @@ [ Exposed=(Window,Worker), - RuntimeEnabled=BackgroundFetch + OriginTrialEnabled=BackgroundFetch ] interface BackgroundFetchFetch { readonly attribute Request request; };
diff --git a/third_party/blink/renderer/modules/background_fetch/background_fetch_manager.idl b/third_party/blink/renderer/modules/background_fetch/background_fetch_manager.idl index d62ceda..cd401cc 100644 --- a/third_party/blink/renderer/modules/background_fetch/background_fetch_manager.idl +++ b/third_party/blink/renderer/modules/background_fetch/background_fetch_manager.idl
@@ -6,7 +6,7 @@ [ Exposed=(Window,Worker), - RuntimeEnabled=BackgroundFetch + OriginTrialEnabled=BackgroundFetch ] interface BackgroundFetchManager { [CallWith=ScriptState, RaisesException, MeasureAs=BackgroundFetchManagerFetch] Promise<BackgroundFetchRegistration> fetch(DOMString id, (RequestInfo or sequence<RequestInfo>) requests, optional BackgroundFetchOptions options); [CallWith=ScriptState, MeasureAs=BackgroundFetchManagerGet] Promise<BackgroundFetchRegistration?> get(DOMString id);
diff --git a/third_party/blink/renderer/modules/background_fetch/background_fetch_record.idl b/third_party/blink/renderer/modules/background_fetch/background_fetch_record.idl index a3e4080..bf81238 100644 --- a/third_party/blink/renderer/modules/background_fetch/background_fetch_record.idl +++ b/third_party/blink/renderer/modules/background_fetch/background_fetch_record.idl
@@ -6,7 +6,7 @@ [ Exposed=(ServiceWorker), - RuntimeEnabled=BackgroundFetch + OriginTrialEnabled=BackgroundFetch ] interface BackgroundFetchRecord { readonly attribute Request request; [CallWith=ScriptState] readonly attribute Promise<Response> responseReady;
diff --git a/third_party/blink/renderer/modules/background_fetch/background_fetch_registration.cc b/third_party/blink/renderer/modules/background_fetch/background_fetch_registration.cc index 819479c..6b102bb5 100644 --- a/third_party/blink/renderer/modules/background_fetch/background_fetch_registration.cc +++ b/third_party/blink/renderer/modules/background_fetch/background_fetch_registration.cc
@@ -74,14 +74,19 @@ ->AddRegistrationObserver(unique_id_, std::move(observer)); } -void BackgroundFetchRegistration::OnProgress(uint64_t upload_total, - uint64_t uploaded, - uint64_t download_total, - uint64_t downloaded) { +void BackgroundFetchRegistration::OnProgress( + uint64_t upload_total, + uint64_t uploaded, + uint64_t download_total, + uint64_t downloaded, + mojom::BackgroundFetchResult result, + mojom::BackgroundFetchFailureReason failure_reason) { upload_total_ = upload_total; uploaded_ = uploaded; download_total_ = download_total; downloaded_ = downloaded; + result_ = result; + failure_reason_ = failure_reason; ExecutionContext* context = GetExecutionContext(); if (!context || context->IsContextDestroyed())
diff --git a/third_party/blink/renderer/modules/background_fetch/background_fetch_registration.h b/third_party/blink/renderer/modules/background_fetch/background_fetch_registration.h index b39e712..bb2adb7c 100644 --- a/third_party/blink/renderer/modules/background_fetch/background_fetch_registration.h +++ b/third_party/blink/renderer/modules/background_fetch/background_fetch_registration.h
@@ -57,7 +57,9 @@ void OnProgress(uint64_t upload_total, uint64_t uploaded, uint64_t download_total, - uint64_t downloaded) override; + uint64_t downloaded, + mojom::BackgroundFetchResult result, + mojom::BackgroundFetchFailureReason failure_reason) override; void OnRecordsUnavailable() override; // Web Exposed attribute defined in the IDL file. Corresponds to the
diff --git a/third_party/blink/renderer/modules/background_fetch/background_fetch_registration.idl b/third_party/blink/renderer/modules/background_fetch/background_fetch_registration.idl index e277b8e..5760956f 100644 --- a/third_party/blink/renderer/modules/background_fetch/background_fetch_registration.idl +++ b/third_party/blink/renderer/modules/background_fetch/background_fetch_registration.idl
@@ -22,7 +22,7 @@ [ Exposed=(Window,Worker), - RuntimeEnabled=BackgroundFetch + OriginTrialEnabled=BackgroundFetch ] interface BackgroundFetchRegistration : EventTarget { readonly attribute DOMString id; readonly attribute unsigned long long uploadTotal;
diff --git a/third_party/blink/renderer/modules/background_fetch/background_fetch_settled_fetch.idl b/third_party/blink/renderer/modules/background_fetch/background_fetch_settled_fetch.idl index 74090be..8bee778 100644 --- a/third_party/blink/renderer/modules/background_fetch/background_fetch_settled_fetch.idl +++ b/third_party/blink/renderer/modules/background_fetch/background_fetch_settled_fetch.idl
@@ -7,7 +7,7 @@ [ Constructor(Request request, Response response), Exposed=ServiceWorker, - RuntimeEnabled=BackgroundFetch + OriginTrialEnabled=BackgroundFetch ] interface BackgroundFetchSettledFetch : BackgroundFetchFetch { readonly attribute Response? response; };
diff --git a/third_party/blink/renderer/modules/background_fetch/background_fetch_update_ui_event.idl b/third_party/blink/renderer/modules/background_fetch/background_fetch_update_ui_event.idl index b494c006..20a3655 100644 --- a/third_party/blink/renderer/modules/background_fetch/background_fetch_update_ui_event.idl +++ b/third_party/blink/renderer/modules/background_fetch/background_fetch_update_ui_event.idl
@@ -7,7 +7,7 @@ [ Constructor(DOMString type, BackgroundFetchEventInit init), Exposed=ServiceWorker, - RuntimeEnabled=BackgroundFetch + OriginTrialEnabled=BackgroundFetch ] interface BackgroundFetchUpdateUIEvent : BackgroundFetchEvent { [CallWith=ScriptState] Promise<void> updateUI(BackgroundFetchUIOptions options); }; \ No newline at end of file
diff --git a/third_party/blink/renderer/modules/background_fetch/service_worker_global_scope_background_fetch.idl b/third_party/blink/renderer/modules/background_fetch/service_worker_global_scope_background_fetch.idl index 2f9f6c0..7dc81fe2 100644 --- a/third_party/blink/renderer/modules/background_fetch/service_worker_global_scope_background_fetch.idl +++ b/third_party/blink/renderer/modules/background_fetch/service_worker_global_scope_background_fetch.idl
@@ -6,7 +6,7 @@ [ ImplementedAs=ServiceWorkerGlobalScopeBackgroundFetch, - RuntimeEnabled=BackgroundFetch + OriginTrialEnabled=BackgroundFetch ] partial interface ServiceWorkerGlobalScope { attribute EventHandler onbackgroundfetchsuccess; attribute EventHandler onbackgroundfetchfail;
diff --git a/third_party/blink/renderer/modules/background_fetch/service_worker_registration_background_fetch.idl b/third_party/blink/renderer/modules/background_fetch/service_worker_registration_background_fetch.idl index a1d9dee7..529646b 100644 --- a/third_party/blink/renderer/modules/background_fetch/service_worker_registration_background_fetch.idl +++ b/third_party/blink/renderer/modules/background_fetch/service_worker_registration_background_fetch.idl
@@ -7,7 +7,7 @@ [ Exposed=(Window,Worker), ImplementedAs=ServiceWorkerRegistrationBackgroundFetch, - RuntimeEnabled=BackgroundFetch + OriginTrialEnabled=BackgroundFetch ] partial interface ServiceWorkerRegistration { readonly attribute BackgroundFetchManager backgroundFetch; };
diff --git a/third_party/blink/renderer/modules/csspaint/css_paint_definition.cc b/third_party/blink/renderer/modules/csspaint/css_paint_definition.cc index 4ab1a29..ffd88e09 100644 --- a/third_party/blink/renderer/modules/csspaint/css_paint_definition.cc +++ b/third_party/blink/renderer/modules/csspaint/css_paint_definition.cc
@@ -80,7 +80,7 @@ MaybeCreatePaintInstance(); v8::Isolate* isolate = script_state_->GetIsolate(); - v8::Local<v8::Object> instance = instance_.NewLocal(isolate); + v8::Local<v8::Value> instance = instance_.NewLocal(isolate); // We may have failed to create an instance class, in which case produce an // invalid image. @@ -144,11 +144,11 @@ v8::Local<v8::Function> constructor = constructor_.NewLocal(isolate); DCHECK(!IsUndefinedOrNull(constructor)); - v8::Local<v8::Object> paint_instance; - if (V8ObjectConstructor::NewInstance(isolate, constructor) - .ToLocal(&paint_instance)) { + v8::Local<v8::Value> paint_instance; + if (V8ScriptRunner::CallAsConstructor( + isolate, constructor, ExecutionContext::From(script_state_), 0, {}) + .ToLocal(&paint_instance)) instance_.Set(isolate, paint_instance); - } did_call_constructor_ = true; } @@ -156,7 +156,7 @@ void CSSPaintDefinition::Trace(Visitor* visitor) { visitor->Trace(constructor_.Cast<v8::Value>()); visitor->Trace(paint_.Cast<v8::Value>()); - visitor->Trace(instance_.Cast<v8::Value>()); + visitor->Trace(instance_); visitor->Trace(script_state_); }
diff --git a/third_party/blink/renderer/modules/csspaint/css_paint_definition.h b/third_party/blink/renderer/modules/csspaint/css_paint_definition.h index dede4c7..4622a7b 100644 --- a/third_party/blink/renderer/modules/csspaint/css_paint_definition.h +++ b/third_party/blink/renderer/modules/csspaint/css_paint_definition.h
@@ -97,7 +97,7 @@ TraceWrapperV8Reference<v8::Function> paint_; // At the moment there is only ever one instance of a paint class per type. - TraceWrapperV8Reference<v8::Object> instance_; + TraceWrapperV8Reference<v8::Value> instance_; bool did_call_constructor_;
diff --git a/third_party/blink/renderer/modules/csspaint/paint_worklet_global_scope.cc b/third_party/blink/renderer/modules/csspaint/paint_worklet_global_scope.cc index 69116af..7e2bbcf 100644 --- a/third_party/blink/renderer/modules/csspaint/paint_worklet_global_scope.cc +++ b/third_party/blink/renderer/modules/csspaint/paint_worklet_global_scope.cc
@@ -111,9 +111,7 @@ std::unique_ptr<GlobalScopeCreationParams> creation_params, WorkerReportingProxy& reporting_proxy, PaintWorkletPendingGeneratorRegistry* pending_generator_registry) - : MainThreadWorkletGlobalScope(frame, - std::move(creation_params), - reporting_proxy), + : WorkletGlobalScope(std::move(creation_params), reporting_proxy, frame), pending_generator_registry_(pending_generator_registry) {} PaintWorkletGlobalScope::~PaintWorkletGlobalScope() = default; @@ -121,9 +119,8 @@ void PaintWorkletGlobalScope::Dispose() { MainThreadDebugger::Instance()->ContextWillBeDestroyed( ScriptController()->GetScriptState()); - pending_generator_registry_ = nullptr; - MainThreadWorkletGlobalScope::Dispose(); + WorkletGlobalScope::Dispose(); } void PaintWorkletGlobalScope::registerPaint( @@ -230,7 +227,7 @@ void PaintWorkletGlobalScope::Trace(blink::Visitor* visitor) { visitor->Trace(paint_definitions_); visitor->Trace(pending_generator_registry_); - MainThreadWorkletGlobalScope::Trace(visitor); + WorkletGlobalScope::Trace(visitor); } } // namespace blink
diff --git a/third_party/blink/renderer/modules/csspaint/paint_worklet_global_scope.h b/third_party/blink/renderer/modules/csspaint/paint_worklet_global_scope.h index 1817e5df..6bd200d 100644 --- a/third_party/blink/renderer/modules/csspaint/paint_worklet_global_scope.h +++ b/third_party/blink/renderer/modules/csspaint/paint_worklet_global_scope.h
@@ -7,7 +7,7 @@ #include "third_party/blink/renderer/bindings/core/v8/script_value.h" #include "third_party/blink/renderer/core/execution_context/execution_context.h" -#include "third_party/blink/renderer/core/workers/main_thread_worklet_global_scope.h" +#include "third_party/blink/renderer/core/workers/worklet_global_scope.h" #include "third_party/blink/renderer/modules/csspaint/paint_worklet_pending_generator_registry.h" #include "third_party/blink/renderer/modules/modules_export.h" #include "third_party/blink/renderer/platform/bindings/script_wrappable.h" @@ -18,8 +18,7 @@ class ExceptionState; class WorkerReportingProxy; -class MODULES_EXPORT PaintWorkletGlobalScope final - : public MainThreadWorkletGlobalScope { +class MODULES_EXPORT PaintWorkletGlobalScope final : public WorkletGlobalScope { DEFINE_WRAPPERTYPEINFO(); USING_GARBAGE_COLLECTED_MIXIN(PaintWorkletGlobalScope);
diff --git a/third_party/blink/renderer/modules/peerconnection/rtc_peer_connection.cc b/third_party/blink/renderer/modules/peerconnection/rtc_peer_connection.cc index fd3fc68a..1072ca6 100644 --- a/third_party/blink/renderer/modules/peerconnection/rtc_peer_connection.cc +++ b/third_party/blink/renderer/modules/peerconnection/rtc_peer_connection.cc
@@ -114,7 +114,9 @@ #include "third_party/blink/renderer/platform/peerconnection/rtc_offer_options_platform.h" #include "third_party/blink/renderer/platform/runtime_enabled_features.h" #include "third_party/blink/renderer/platform/wtf/time.h" +#include "third_party/webrtc/api/jsep.h" #include "third_party/webrtc/api/peerconnectioninterface.h" +#include "third_party/webrtc/pc/sessiondescription.h" namespace blink { @@ -552,7 +554,8 @@ } RTCPeerConnection* peer_connection = new RTCPeerConnection( - context, std::move(configuration), constraints, exception_state); + context, std::move(configuration), rtc_configuration.hasSdpSemantics(), + constraints, exception_state); peer_connection->PauseIfNeeded(); if (exception_state.HadException()) return nullptr; @@ -567,6 +570,7 @@ RTCPeerConnection::RTCPeerConnection( ExecutionContext* context, webrtc::PeerConnectionInterface::RTCConfiguration configuration, + bool sdp_semantics_specified, WebMediaConstraints constraints, ExceptionState& exception_state) : PausableObject(context), @@ -585,7 +589,8 @@ stopped_(false), closed_(false), has_data_channels_(false), - sdp_semantics_(configuration.sdp_semantics) { + sdp_semantics_(configuration.sdp_semantics), + sdp_semantics_specified_(sdp_semantics_specified) { Document* document = To<Document>(GetExecutionContext()); InstanceCounters::IncrementCounter( @@ -841,9 +846,47 @@ return nullptr; } +bool RTCPeerConnection::ShouldShowComplexPlanBSdpWarning( + const RTCSessionDescriptionInit& session_description_init) const { + if (sdp_semantics_specified_) + return false; + if (!session_description_init.hasType() || !session_description_init.hasSdp()) + return false; + std::unique_ptr<webrtc::SessionDescriptionInterface> session_description( + webrtc::CreateSessionDescription( + session_description_init.type().Utf8().data(), + session_description_init.sdp().Utf8().data(), nullptr)); + if (!session_description) + return false; + size_t num_audio_mlines = 0u; + size_t num_video_mlines = 0u; + size_t num_audio_tracks = 0u; + size_t num_video_tracks = 0u; + for (const cricket::ContentInfo& content : + session_description->description()->contents()) { + cricket::MediaType media_type = content.media_description()->type(); + size_t num_tracks = std::max(static_cast<size_t>(1u), + content.media_description()->streams().size()); + if (media_type == cricket::MEDIA_TYPE_AUDIO) { + ++num_audio_mlines; + num_audio_tracks += num_tracks; + } else if (media_type == cricket::MEDIA_TYPE_VIDEO) { + ++num_video_mlines; + num_video_tracks += num_tracks; + } + } + return (num_audio_mlines == 1u && num_audio_tracks > 1u) || + (num_video_mlines == 1u && num_video_tracks > 1u); +} + ScriptPromise RTCPeerConnection::setLocalDescription( ScriptState* script_state, const RTCSessionDescriptionInit& session_description_init) { + if (ShouldShowComplexPlanBSdpWarning(session_description_init)) { + Deprecation::CountDeprecation( + GetExecutionContext(), + WebFeature::kRTCPeerConnectionComplexPlanBSdpUsingDefaultSdpSemantics); + } String sdp; DOMException* exception = checkSdpForStateErrors( ExecutionContext::From(script_state), session_description_init, &sdp); @@ -864,6 +907,11 @@ const RTCSessionDescriptionInit& session_description_init, V8VoidFunction* success_callback, V8RTCPeerConnectionErrorCallback* error_callback) { + if (ShouldShowComplexPlanBSdpWarning(session_description_init)) { + Deprecation::CountDeprecation( + GetExecutionContext(), + WebFeature::kRTCPeerConnectionComplexPlanBSdpUsingDefaultSdpSemantics); + } ExecutionContext* context = ExecutionContext::From(script_state); if (success_callback && error_callback) { UseCounter::Count( @@ -929,6 +977,11 @@ ScriptPromise RTCPeerConnection::setRemoteDescription( ScriptState* script_state, const RTCSessionDescriptionInit& session_description_init) { + if (ShouldShowComplexPlanBSdpWarning(session_description_init)) { + Deprecation::CountDeprecation( + GetExecutionContext(), + WebFeature::kRTCPeerConnectionComplexPlanBSdpUsingDefaultSdpSemantics); + } if (signaling_state_ == webrtc::PeerConnectionInterface::SignalingState::kClosed) { return ScriptPromise::RejectWithDOMException( @@ -951,6 +1004,11 @@ const RTCSessionDescriptionInit& session_description_init, V8VoidFunction* success_callback, V8RTCPeerConnectionErrorCallback* error_callback) { + if (ShouldShowComplexPlanBSdpWarning(session_description_init)) { + Deprecation::CountDeprecation( + GetExecutionContext(), + WebFeature::kRTCPeerConnectionComplexPlanBSdpUsingDefaultSdpSemantics); + } ExecutionContext* context = ExecutionContext::From(script_state); if (success_callback && error_callback) { UseCounter::Count(
diff --git a/third_party/blink/renderer/modules/peerconnection/rtc_peer_connection.h b/third_party/blink/renderer/modules/peerconnection/rtc_peer_connection.h index 49450d4..fc779f3 100644 --- a/third_party/blink/renderer/modules/peerconnection/rtc_peer_connection.h +++ b/third_party/blink/renderer/modules/peerconnection/rtc_peer_connection.h
@@ -258,6 +258,18 @@ static int PeerConnectionCount(); static int PeerConnectionCountLimit(); + // SLD/SRD helper method, public for testing. + // "Complex" Plan B SDP is SDP that is not compatible with Unified Plan, i.e. + // SDP that has multiple tracks listed under the same m= sections. We should + // show a deprecation warning when setLocalDescription() or + // setRemoteDescription() is called and: + // - The SDP is complex Plan B SDP. + // - sdpSemantics was not specified at RTCPeerConnection construction. + // Such calls would normally succeed, but as soon as the default switches to + // Unified Plan they would fail. This decides whether to show deprecation for + // WebFeature::kRTCPeerConnectionComplexPlanBSdpUsingDefaultSdpSemantics. + bool ShouldShowComplexPlanBSdpWarning(const RTCSessionDescriptionInit&) const; + void Trace(blink::Visitor*) override; private: @@ -288,6 +300,7 @@ RTCPeerConnection(ExecutionContext*, webrtc::PeerConnectionInterface::RTCConfiguration, + bool sdp_semantics_specified, WebMediaConstraints, ExceptionState&); void Dispose(); @@ -442,6 +455,8 @@ // "kUnifiedPlan", if constructed with "kDefault" it is translated to one or // the other. webrtc::SdpSemantics sdp_semantics_; + // Whether sdpSemantics was specified at construction. + bool sdp_semantics_specified_; }; } // namespace blink
diff --git a/third_party/blink/renderer/modules/peerconnection/rtc_peer_connection_test.cc b/third_party/blink/renderer/modules/peerconnection/rtc_peer_connection_test.cc index cdef143..a20d8fa8 100644 --- a/third_party/blink/renderer/modules/peerconnection/rtc_peer_connection_test.cc +++ b/third_party/blink/renderer/modules/peerconnection/rtc_peer_connection_test.cc
@@ -19,16 +19,352 @@ #include "third_party/blink/renderer/modules/mediastream/media_stream_track.h" #include "third_party/blink/renderer/modules/peerconnection/rtc_configuration.h" #include "third_party/blink/renderer/modules/peerconnection/rtc_ice_server.h" +#include "third_party/blink/renderer/modules/peerconnection/rtc_session_description_init.h" #include "third_party/blink/renderer/platform/heap/heap_allocator.h" #include "third_party/blink/renderer/platform/testing/testing_platform_support.h" #include "third_party/blink/renderer/platform/testing/testing_platform_support_with_web_rtc.h" namespace blink { +static const char* kOfferSdpUnifiedPlanSingleAudioSingleVideo = + "v=0\r\n" + "o=- 6676943034916303038 2 IN IP4 127.0.0.1\r\n" + "s=-\r\n" + "t=0 0\r\n" + "a=group:BUNDLE 0 1\r\n" + "a=msid-semantic: WMS\r\n" + "m=audio 9 UDP/TLS/RTP/SAVPF 111 103 104 9 0 8 106 105 13 110 112 113 " + "126\r\n" + "c=IN IP4 0.0.0.0\r\n" + "a=rtcp:9 IN IP4 0.0.0.0\r\n" + "a=ice-ufrag:pKAt\r\n" + "a=ice-pwd:bDmIGcCbVl+VkMymNfwdE/Mv\r\n" + "a=ice-options:trickle\r\n" + "a=fingerprint:sha-256 " + "F2:D4:95:C5:FC:98:F2:7E:6F:6C:46:BF:5E:05:00:56:4F:A9:BC:4B:1E:56:98:C1:" + "68:BF:5E:7D:01:A3:EC:93\r\n" + "a=setup:actpass\r\n" + "a=mid:0\r\n" + "a=extmap:1 urn:ietf:params:rtp-hdrext:ssrc-audio-level\r\n" + "a=extmap:9 urn:ietf:params:rtp-hdrext:sdes:mid\r\n" + "a=sendrecv\r\n" + "a=msid:- 36f80301-b634-4c5a-a03b-d1ad79997531\r\n" + "a=rtcp-mux\r\n" + "a=rtpmap:111 opus/48000/2\r\n" + "a=rtcp-fb:111 transport-cc\r\n" + "a=fmtp:111 minptime=10;useinbandfec=1\r\n" + "a=rtpmap:103 ISAC/16000\r\n" + "a=rtpmap:104 ISAC/32000\r\n" + "a=rtpmap:9 G722/8000\r\n" + "a=rtpmap:0 PCMU/8000\r\n" + "a=rtpmap:8 PCMA/8000\r\n" + "a=rtpmap:106 CN/32000\r\n" + "a=rtpmap:105 CN/16000\r\n" + "a=rtpmap:13 CN/8000\r\n" + "a=rtpmap:110 telephone-event/48000\r\n" + "a=rtpmap:112 telephone-event/32000\r\n" + "a=rtpmap:113 telephone-event/16000\r\n" + "a=rtpmap:126 telephone-event/8000\r\n" + "a=ssrc:4264546776 cname:GkUsSfx+DbDplYYT\r\n" + "a=ssrc:4264546776 msid: 36f80301-b634-4c5a-a03b-d1ad79997531\r\n" + "a=ssrc:4264546776 mslabel:\r\n" + "a=ssrc:4264546776 label:36f80301-b634-4c5a-a03b-d1ad79997531\r\n" + "m=video 9 UDP/TLS/RTP/SAVPF 96 97 98 99 100 101 102\r\n" + "c=IN IP4 0.0.0.0\r\n" + "a=rtcp:9 IN IP4 0.0.0.0\r\n" + "a=ice-ufrag:pKAt\r\n" + "a=ice-pwd:bDmIGcCbVl+VkMymNfwdE/Mv\r\n" + "a=ice-options:trickle\r\n" + "a=fingerprint:sha-256 " + "F2:D4:95:C5:FC:98:F2:7E:6F:6C:46:BF:5E:05:00:56:4F:A9:BC:4B:1E:56:98:C1:" + "68:BF:5E:7D:01:A3:EC:93\r\n" + "a=setup:actpass\r\n" + "a=mid:1\r\n" + "a=extmap:2 urn:ietf:params:rtp-hdrext:toffset\r\n" + "a=extmap:3 http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time\r\n" + "a=extmap:4 urn:3gpp:video-orientation\r\n" + "a=extmap:5 " + "http://www.ietf.org/id/" + "draft-holmer-rmcat-transport-wide-cc-extensions-01\r\n" + "a=extmap:6 http://www.webrtc.org/experiments/rtp-hdrext/playout-delay\r\n" + "a=extmap:7 " + "http://www.webrtc.org/experiments/rtp-hdrext/video-content-type\r\n" + "a=extmap:8 http://www.webrtc.org/experiments/rtp-hdrext/video-timing\r\n" + "a=extmap:10 " + "http://tools.ietf.org/html/draft-ietf-avtext-framemarking-07\r\n" + "a=extmap:9 urn:ietf:params:rtp-hdrext:sdes:mid\r\n" + "a=sendrecv\r\n" + "a=msid:- 0db71b61-c1ae-4741-bcce-320a254244f3\r\n" + "a=rtcp-mux\r\n" + "a=rtcp-rsize\r\n" + "a=rtpmap:96 VP8/90000\r\n" + "a=rtcp-fb:96 goog-remb\r\n" + "a=rtcp-fb:96 transport-cc\r\n" + "a=rtcp-fb:96 ccm fir\r\n" + "a=rtcp-fb:96 nack\r\n" + "a=rtcp-fb:96 nack pli\r\n" + "a=rtpmap:97 rtx/90000\r\n" + "a=fmtp:97 apt=96\r\n" + "a=rtpmap:98 VP9/90000\r\n" + "a=rtcp-fb:98 goog-remb\r\n" + "a=rtcp-fb:98 transport-cc\r\n" + "a=rtcp-fb:98 ccm fir\r\n" + "a=rtcp-fb:98 nack\r\n" + "a=rtcp-fb:98 nack pli\r\n" + "a=fmtp:98 x-google-profile-id=0\r\n" + "a=rtpmap:99 rtx/90000\r\n" + "a=fmtp:99 apt=98\r\n" + "a=rtpmap:100 red/90000\r\n" + "a=rtpmap:101 rtx/90000\r\n" + "a=fmtp:101 apt=100\r\n" + "a=rtpmap:102 ulpfec/90000\r\n" + "a=ssrc-group:FID 680673332 1566706172\r\n" + "a=ssrc:680673332 cname:GkUsSfx+DbDplYYT\r\n" + "a=ssrc:680673332 msid: 0db71b61-c1ae-4741-bcce-320a254244f3\r\n" + "a=ssrc:680673332 mslabel:\r\n" + "a=ssrc:680673332 label:0db71b61-c1ae-4741-bcce-320a254244f3\r\n" + "a=ssrc:1566706172 cname:GkUsSfx+DbDplYYT\r\n" + "a=ssrc:1566706172 msid: 0db71b61-c1ae-4741-bcce-320a254244f3\r\n" + "a=ssrc:1566706172 mslabel:\r\n" + "a=ssrc:1566706172 label:0db71b61-c1ae-4741-bcce-320a254244f3\r\n"; + +static const char* kOfferSdpUnifiedPlanMultipleAudioTracks = + "v=0\r\n" + "o=- 1821816752660535838 2 IN IP4 127.0.0.1\r\n" + "s=-\r\n" + "t=0 0\r\n" + "a=group:BUNDLE 0 1\r\n" + "a=msid-semantic: WMS\r\n" + "m=audio 9 UDP/TLS/RTP/SAVPF 111 103 104 9 0 8 106 105 13 110 112 113 " + "126\r\n" + "c=IN IP4 0.0.0.0\r\n" + "a=rtcp:9 IN IP4 0.0.0.0\r\n" + "a=ice-ufrag:rbEc\r\n" + "a=ice-pwd:vmDec3+MrTigDESzNiDuWBnD\r\n" + "a=ice-options:trickle\r\n" + "a=fingerprint:sha-256 " + "05:9B:0A:BC:B3:E1:B9:5C:A6:78:96:23:00:0F:96:71:7B:B0:3E:37:87:1D:3A:62:" + "5E:00:A5:27:22:BB:26:5D\r\n" + "a=setup:actpass\r\n" + "a=mid:0\r\n" + "a=extmap:1 urn:ietf:params:rtp-hdrext:ssrc-audio-level\r\n" + "a=extmap:9 urn:ietf:params:rtp-hdrext:sdes:mid\r\n" + "a=sendrecv\r\n" + "a=msid:- adcd8158-3ad7-4a1f-ac87-8711db959fe8\r\n" + "a=rtcp-mux\r\n" + "a=rtpmap:111 opus/48000/2\r\n" + "a=rtcp-fb:111 transport-cc\r\n" + "a=fmtp:111 minptime=10;useinbandfec=1\r\n" + "a=rtpmap:103 ISAC/16000\r\n" + "a=rtpmap:104 ISAC/32000\r\n" + "a=rtpmap:9 G722/8000\r\n" + "a=rtpmap:0 PCMU/8000\r\n" + "a=rtpmap:8 PCMA/8000\r\n" + "a=rtpmap:106 CN/32000\r\n" + "a=rtpmap:105 CN/16000\r\n" + "a=rtpmap:13 CN/8000\r\n" + "a=rtpmap:110 telephone-event/48000\r\n" + "a=rtpmap:112 telephone-event/32000\r\n" + "a=rtpmap:113 telephone-event/16000\r\n" + "a=rtpmap:126 telephone-event/8000\r\n" + "a=ssrc:2988156579 cname:gr88KGUzymBvrIaJ\r\n" + "a=ssrc:2988156579 msid: adcd8158-3ad7-4a1f-ac87-8711db959fe8\r\n" + "a=ssrc:2988156579 mslabel:\r\n" + "a=ssrc:2988156579 label:adcd8158-3ad7-4a1f-ac87-8711db959fe8\r\n" + "m=audio 9 UDP/TLS/RTP/SAVPF 111 103 104 9 0 8 106 105 13 110 112 113 " + "126\r\n" + "c=IN IP4 0.0.0.0\r\n" + "a=rtcp:9 IN IP4 0.0.0.0\r\n" + "a=ice-ufrag:rbEc\r\n" + "a=ice-pwd:vmDec3+MrTigDESzNiDuWBnD\r\n" + "a=ice-options:trickle\r\n" + "a=fingerprint:sha-256 " + "05:9B:0A:BC:B3:E1:B9:5C:A6:78:96:23:00:0F:96:71:7B:B0:3E:37:87:1D:3A:62:" + "5E:00:A5:27:22:BB:26:5D\r\n" + "a=setup:actpass\r\n" + "a=mid:1\r\n" + "a=extmap:1 urn:ietf:params:rtp-hdrext:ssrc-audio-level\r\n" + "a=extmap:9 urn:ietf:params:rtp-hdrext:sdes:mid\r\n" + "a=sendrecv\r\n" + "a=msid:- b5f69d2c-e753-4eb5-a302-d41ee75f9fcb\r\n" + "a=rtcp-mux\r\n" + "a=rtpmap:111 opus/48000/2\r\n" + "a=rtcp-fb:111 transport-cc\r\n" + "a=fmtp:111 minptime=10;useinbandfec=1\r\n" + "a=rtpmap:103 ISAC/16000\r\n" + "a=rtpmap:104 ISAC/32000\r\n" + "a=rtpmap:9 G722/8000\r\n" + "a=rtpmap:0 PCMU/8000\r\n" + "a=rtpmap:8 PCMA/8000\r\n" + "a=rtpmap:106 CN/32000\r\n" + "a=rtpmap:105 CN/16000\r\n" + "a=rtpmap:13 CN/8000\r\n" + "a=rtpmap:110 telephone-event/48000\r\n" + "a=rtpmap:112 telephone-event/32000\r\n" + "a=rtpmap:113 telephone-event/16000\r\n" + "a=rtpmap:126 telephone-event/8000\r\n" + "a=ssrc:2562757057 cname:gr88KGUzymBvrIaJ\r\n" + "a=ssrc:2562757057 msid: b5f69d2c-e753-4eb5-a302-d41ee75f9fcb\r\n" + "a=ssrc:2562757057 mslabel:\r\n" + "a=ssrc:2562757057 label:b5f69d2c-e753-4eb5-a302-d41ee75f9fcb\r\n"; + +static const char* kOfferSdpPlanBSingleAudioSingleVideo = + "v=0\r\n" + "o=- 267029810971159627 2 IN IP4 127.0.0.1\r\n" + "s=-\r\n" + "t=0 0\r\n" + "a=group:BUNDLE audio video\r\n" + "a=msid-semantic: WMS 655e92b8-9130-44d8-a188-f5f4633d1a8d " + "b15218e5-f921-4988-9e1f-6e50ecbd24c2\r\n" + "m=audio 9 UDP/TLS/RTP/SAVPF 111 103 104 9 0 8 106 105 13 110 112 113 " + "126\r\n" + "c=IN IP4 0.0.0.0\r\n" + "a=rtcp:9 IN IP4 0.0.0.0\r\n" + "a=ice-ufrag:ErlQ\r\n" + "a=ice-pwd:VCnwY8XlD9EX4gpcOHRhU0HV\r\n" + "a=ice-options:trickle\r\n" + "a=fingerprint:sha-256 " + "AC:30:90:F9:3B:CB:9A:0D:C6:FB:F3:D6:D6:97:4F:40:A2:B9:5E:4D:F5:32:DC:A7:" + "B0:3A:33:82:C8:67:FF:7A\r\n" + "a=setup:actpass\r\n" + "a=mid:audio\r\n" + "a=extmap:1 urn:ietf:params:rtp-hdrext:ssrc-audio-level\r\n" + "a=sendrecv\r\n" + "a=rtcp-mux\r\n" + "a=rtpmap:111 opus/48000/2\r\n" + "a=rtcp-fb:111 transport-cc\r\n" + "a=fmtp:111 minptime=10;useinbandfec=1\r\n" + "a=rtpmap:103 ISAC/16000\r\n" + "a=rtpmap:104 ISAC/32000\r\n" + "a=rtpmap:9 G722/8000\r\n" + "a=rtpmap:0 PCMU/8000\r\n" + "a=rtpmap:8 PCMA/8000\r\n" + "a=rtpmap:106 CN/32000\r\n" + "a=rtpmap:105 CN/16000\r\n" + "a=rtpmap:13 CN/8000\r\n" + "a=rtpmap:110 telephone-event/48000\r\n" + "a=rtpmap:112 telephone-event/32000\r\n" + "a=rtpmap:113 telephone-event/16000\r\n" + "a=rtpmap:126 telephone-event/8000\r\n" + "a=ssrc:1670492497 cname:rNEKgm1NFupmwR4x\r\n" + "a=ssrc:1670492497 msid:b15218e5-f921-4988-9e1f-6e50ecbd24c2 " + "089fd06c-73e4-4720-a6dc-e182eeaeced7\r\n" + "a=ssrc:1670492497 mslabel:b15218e5-f921-4988-9e1f-6e50ecbd24c2\r\n" + "a=ssrc:1670492497 label:089fd06c-73e4-4720-a6dc-e182eeaeced7\r\n" + "m=video 9 UDP/TLS/RTP/SAVPF 96 97 98 99 100 101 102\r\n" + "c=IN IP4 0.0.0.0\r\n" + "a=rtcp:9 IN IP4 0.0.0.0\r\n" + "a=ice-ufrag:ErlQ\r\n" + "a=ice-pwd:VCnwY8XlD9EX4gpcOHRhU0HV\r\n" + "a=ice-options:trickle\r\n" + "a=fingerprint:sha-256 " + "AC:30:90:F9:3B:CB:9A:0D:C6:FB:F3:D6:D6:97:4F:40:A2:B9:5E:4D:F5:32:DC:A7:" + "B0:3A:33:82:C8:67:FF:7A\r\n" + "a=setup:actpass\r\n" + "a=mid:video\r\n" + "a=extmap:2 urn:ietf:params:rtp-hdrext:toffset\r\n" + "a=extmap:3 http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time\r\n" + "a=extmap:4 urn:3gpp:video-orientation\r\n" + "a=extmap:5 " + "http://www.ietf.org/id/" + "draft-holmer-rmcat-transport-wide-cc-extensions-01\r\n" + "a=extmap:6 http://www.webrtc.org/experiments/rtp-hdrext/playout-delay\r\n" + "a=extmap:7 " + "http://www.webrtc.org/experiments/rtp-hdrext/video-content-type\r\n" + "a=extmap:8 http://www.webrtc.org/experiments/rtp-hdrext/video-timing\r\n" + "a=extmap:10 " + "http://tools.ietf.org/html/draft-ietf-avtext-framemarking-07\r\n" + "a=sendrecv\r\n" + "a=rtcp-mux\r\n" + "a=rtcp-rsize\r\n" + "a=rtpmap:96 VP8/90000\r\n" + "a=rtcp-fb:96 goog-remb\r\n" + "a=rtcp-fb:96 transport-cc\r\n" + "a=rtcp-fb:96 ccm fir\r\n" + "a=rtcp-fb:96 nack\r\n" + "a=rtcp-fb:96 nack pli\r\n" + "a=rtpmap:97 rtx/90000\r\n" + "a=fmtp:97 apt=96\r\n" + "a=rtpmap:98 VP9/90000\r\n" + "a=rtcp-fb:98 goog-remb\r\n" + "a=rtcp-fb:98 transport-cc\r\n" + "a=rtcp-fb:98 ccm fir\r\n" + "a=rtcp-fb:98 nack\r\n" + "a=rtcp-fb:98 nack pli\r\n" + "a=fmtp:98 x-google-profile-id=0\r\n" + "a=rtpmap:99 rtx/90000\r\n" + "a=fmtp:99 apt=98\r\n" + "a=rtpmap:100 red/90000\r\n" + "a=rtpmap:101 rtx/90000\r\n" + "a=fmtp:101 apt=100\r\n" + "a=rtpmap:102 ulpfec/90000\r\n" + "a=ssrc-group:FID 3263949794 2166305097\r\n" + "a=ssrc:3263949794 cname:rNEKgm1NFupmwR4x\r\n" + "a=ssrc:3263949794 msid:655e92b8-9130-44d8-a188-f5f4633d1a8d " + "6391e0e8-ac1e-42c2-844c-a7299758db6a\r\n" + "a=ssrc:3263949794 mslabel:655e92b8-9130-44d8-a188-f5f4633d1a8d\r\n" + "a=ssrc:3263949794 label:6391e0e8-ac1e-42c2-844c-a7299758db6a\r\n" + "a=ssrc:2166305097 cname:rNEKgm1NFupmwR4x\r\n" + "a=ssrc:2166305097 msid:655e92b8-9130-44d8-a188-f5f4633d1a8d " + "6391e0e8-ac1e-42c2-844c-a7299758db6a\r\n" + "a=ssrc:2166305097 mslabel:655e92b8-9130-44d8-a188-f5f4633d1a8d\r\n" + "a=ssrc:2166305097 label:6391e0e8-ac1e-42c2-844c-a7299758db6a\r\n"; + +static const char* kOfferSdpPlanBMultipleAudioTracks = + "v=0\r\n" + "o=- 6228437149521864740 2 IN IP4 127.0.0.1\r\n" + "s=-\r\n" + "t=0 0\r\n" + "a=group:BUNDLE audio\r\n" + "a=msid-semantic: WMS 46f8615e-7599-49f3-9a45-3cf0faf58614 " + "e01b7c23-2b77-4e09-bee7-4b9140e49647\r\n" + "m=audio 9 UDP/TLS/RTP/SAVPF 111 103 104 9 0 8 106 105 13 110 112 113 " + "126\r\n" + "c=IN IP4 0.0.0.0\r\n" + "a=rtcp:9 IN IP4 0.0.0.0\r\n" + "a=ice-ufrag:Nzla\r\n" + "a=ice-pwd:PL1APGM2pr773UoUOsj8jzBI\r\n" + "a=ice-options:trickle\r\n" + "a=fingerprint:sha-256 " + "DF:8F:89:33:68:AB:55:26:4E:81:CF:95:8C:71:B7:89:45:E7:05:7A:5D:A8:CF:BF:" + "60:AA:C7:42:F2:85:23:1D\r\n" + "a=setup:actpass\r\n" + "a=mid:audio\r\n" + "a=extmap:1 urn:ietf:params:rtp-hdrext:ssrc-audio-level\r\n" + "a=sendrecv\r\n" + "a=rtcp-mux\r\n" + "a=rtpmap:111 opus/48000/2\r\n" + "a=rtcp-fb:111 transport-cc\r\n" + "a=fmtp:111 minptime=10;useinbandfec=1\r\n" + "a=rtpmap:103 ISAC/16000\r\n" + "a=rtpmap:104 ISAC/32000\r\n" + "a=rtpmap:9 G722/8000\r\n" + "a=rtpmap:0 PCMU/8000\r\n" + "a=rtpmap:8 PCMA/8000\r\n" + "a=rtpmap:106 CN/32000\r\n" + "a=rtpmap:105 CN/16000\r\n" + "a=rtpmap:13 CN/8000\r\n" + "a=rtpmap:110 telephone-event/48000\r\n" + "a=rtpmap:112 telephone-event/32000\r\n" + "a=rtpmap:113 telephone-event/16000\r\n" + "a=rtpmap:126 telephone-event/8000\r\n" + "a=ssrc:2716812081 cname:0QgfsHYGSuZjeg5/\r\n" + "a=ssrc:2716812081 msid:e01b7c23-2b77-4e09-bee7-4b9140e49647 " + "d73d8a47-3d3f-408f-a2ce-2270eb44ffc5\r\n" + "a=ssrc:2716812081 mslabel:e01b7c23-2b77-4e09-bee7-4b9140e49647\r\n" + "a=ssrc:2716812081 label:d73d8a47-3d3f-408f-a2ce-2270eb44ffc5\r\n" + "a=ssrc:4092260337 cname:0QgfsHYGSuZjeg5/\r\n" + "a=ssrc:4092260337 msid:46f8615e-7599-49f3-9a45-3cf0faf58614 " + "6b5f436e-f85d-40a1-83e4-acec63ca4b82\r\n" + "a=ssrc:4092260337 mslabel:46f8615e-7599-49f3-9a45-3cf0faf58614\r\n" + "a=ssrc:4092260337 label:6b5f436e-f85d-40a1-83e4-acec63ca4b82\r\n"; + class RTCPeerConnectionTest : public testing::Test { public: - RTCPeerConnection* CreatePC(V8TestingScope& scope) { + RTCPeerConnection* CreatePC(V8TestingScope& scope, + const String& sdpSemantics = String()) { RTCConfiguration config; + config.setSdpSemantics(sdpSemantics); RTCIceServer ice_server; ice_server.setURL("stun:fake.stun.url"); HeapVector<RTCIceServer> ice_servers; @@ -236,4 +572,78 @@ EXPECT_FALSE(pc->GetTrack(track_component)); } +TEST_F(RTCPeerConnectionTest, PlanBSdpWarningNotShownWhenPlanBSpecified) { + V8TestingScope scope; + Persistent<RTCPeerConnection> pc = CreatePC(scope, "plan-b"); + RTCSessionDescriptionInit sdp; + sdp.setType("offer"); + // It doesn't matter the SDP, never show a warning if sdpSemantics was + // specified at construction. + sdp.setSdp(kOfferSdpUnifiedPlanSingleAudioSingleVideo); + ASSERT_FALSE(pc->ShouldShowComplexPlanBSdpWarning(sdp)); + sdp.setSdp(kOfferSdpUnifiedPlanMultipleAudioTracks); + ASSERT_FALSE(pc->ShouldShowComplexPlanBSdpWarning(sdp)); + sdp.setSdp(kOfferSdpPlanBSingleAudioSingleVideo); + ASSERT_FALSE(pc->ShouldShowComplexPlanBSdpWarning(sdp)); + sdp.setSdp(kOfferSdpPlanBMultipleAudioTracks); + ASSERT_FALSE(pc->ShouldShowComplexPlanBSdpWarning(sdp)); +} + +TEST_F(RTCPeerConnectionTest, PlanBSdpWarningNotShownWhenUnifiedPlanSpecified) { + V8TestingScope scope; + Persistent<RTCPeerConnection> pc = CreatePC(scope, "unified-plan"); + RTCSessionDescriptionInit sdp; + sdp.setType("offer"); + // It doesn't matter the SDP, never show a warning if sdpSemantics was + // specified at construction. + sdp.setSdp(kOfferSdpUnifiedPlanSingleAudioSingleVideo); + ASSERT_FALSE(pc->ShouldShowComplexPlanBSdpWarning(sdp)); + sdp.setSdp(kOfferSdpUnifiedPlanMultipleAudioTracks); + ASSERT_FALSE(pc->ShouldShowComplexPlanBSdpWarning(sdp)); + sdp.setSdp(kOfferSdpPlanBSingleAudioSingleVideo); + ASSERT_FALSE(pc->ShouldShowComplexPlanBSdpWarning(sdp)); + sdp.setSdp(kOfferSdpPlanBMultipleAudioTracks); + ASSERT_FALSE(pc->ShouldShowComplexPlanBSdpWarning(sdp)); +} + +TEST_F(RTCPeerConnectionTest, PlanBSdpWarningNotShownWhenInvalidSdp) { + V8TestingScope scope; + Persistent<RTCPeerConnection> pc = CreatePC(scope); + RTCSessionDescriptionInit sdp; + sdp.setType("offer"); + sdp.setSdp("invalid sdp"); + ASSERT_FALSE(pc->ShouldShowComplexPlanBSdpWarning(sdp)); +} + +TEST_F(RTCPeerConnectionTest, PlanBSdpWarningNotShownForSingleTracks) { + V8TestingScope scope; + Persistent<RTCPeerConnection> pc = CreatePC(scope); + RTCSessionDescriptionInit sdp; + sdp.setType("offer"); + // Neither Unified Plan or Plan B SDP should result in a warning if only a + // single track per m= section is used. + sdp.setSdp(kOfferSdpUnifiedPlanSingleAudioSingleVideo); + ASSERT_FALSE(pc->ShouldShowComplexPlanBSdpWarning(sdp)); + sdp.setSdp(kOfferSdpPlanBSingleAudioSingleVideo); + ASSERT_FALSE(pc->ShouldShowComplexPlanBSdpWarning(sdp)); +} + +TEST_F(RTCPeerConnectionTest, PlanBSdpWarningShownForComplexPlanB) { + V8TestingScope scope; + Persistent<RTCPeerConnection> pc = CreatePC(scope); + RTCSessionDescriptionInit sdp; + sdp.setType("offer"); + sdp.setSdp(kOfferSdpPlanBMultipleAudioTracks); + ASSERT_TRUE(pc->ShouldShowComplexPlanBSdpWarning(sdp)); +} + +TEST_F(RTCPeerConnectionTest, PlanBSdpWarningNotShownForComplexUnifiedPlan) { + V8TestingScope scope; + Persistent<RTCPeerConnection> pc = CreatePC(scope); + RTCSessionDescriptionInit sdp; + sdp.setType("offer"); + sdp.setSdp(kOfferSdpUnifiedPlanMultipleAudioTracks); + ASSERT_FALSE(pc->ShouldShowComplexPlanBSdpWarning(sdp)); +} + } // namespace blink
diff --git a/third_party/blink/renderer/modules/permissions/permissions.cc b/third_party/blink/renderer/modules/permissions/permissions.cc index 402001ad..4b57a301 100644 --- a/third_party/blink/renderer/modules/permissions/permissions.cc +++ b/third_party/blink/renderer/modules/permissions/permissions.cc
@@ -140,7 +140,8 @@ if (name == "payment-handler") return CreatePermissionDescriptor(PermissionName::PAYMENT_HANDLER); if (name == "background-fetch") { - if (!RuntimeEnabledFeatures::BackgroundFetchEnabled()) { + if (!OriginTrials::BackgroundFetchEnabled( + ExecutionContext::From(script_state))) { exception_state.ThrowTypeError("Background Fetch is not enabled."); return nullptr; }
diff --git a/third_party/blink/renderer/modules/service_worker/wait_until_observer.cc b/third_party/blink/renderer/modules/service_worker/wait_until_observer.cc index 1a664a7c..8caa652 100644 --- a/third_party/blink/renderer/modules/service_worker/wait_until_observer.cc +++ b/third_party/blink/renderer/modules/service_worker/wait_until_observer.cc
@@ -112,13 +112,15 @@ void WaitUntilObserver::WillDispatchEvent() { event_dispatch_time_ = WTF::CurrentTimeTicks(); - // When handling a notificationclick or paymentrequest event, we want to - // allow one window to be focused or opened. These calls are allowed between - // the call to willDispatchEvent() and the last call to + // When handling a notificationclick, paymentrequest, or backgroundfetchclick + // event, we want to allow one window to be focused or opened. These calls are + // allowed between the call to willDispatchEvent() and the last call to // DecrementPendingPromiseCount(). If waitUntil() isn't called, that means // between willDispatchEvent() and didDispatchEvent(). - if (type_ == kNotificationClick || type_ == kPaymentRequest) + if (type_ == kNotificationClick || type_ == kPaymentRequest || + type_ == kBackgroundFetchClick) { execution_context_->AllowWindowInteraction(); + } DCHECK_EQ(EventDispatchState::kInitial, event_dispatch_state_); event_dispatch_state_ = EventDispatchState::kDispatching;
diff --git a/third_party/blink/renderer/modules/webaudio/audio_worklet_global_scope.cc b/third_party/blink/renderer/modules/webaudio/audio_worklet_global_scope.cc index 9dc2b84..718ef75d 100644 --- a/third_party/blink/renderer/modules/webaudio/audio_worklet_global_scope.cc +++ b/third_party/blink/renderer/modules/webaudio/audio_worklet_global_scope.cc
@@ -20,6 +20,7 @@ #include "third_party/blink/renderer/core/messaging/message_port.h" #include "third_party/blink/renderer/core/typed_arrays/dom_typed_array.h" #include "third_party/blink/renderer/core/workers/global_scope_creation_params.h" +#include "third_party/blink/renderer/core/workers/worker_thread.h" #include "third_party/blink/renderer/modules/webaudio/audio_buffer.h" #include "third_party/blink/renderer/modules/webaudio/audio_param_descriptor.h" #include "third_party/blink/renderer/modules/webaudio/audio_worklet_processor.h" @@ -36,24 +37,23 @@ AudioWorkletGlobalScope* AudioWorkletGlobalScope::Create( std::unique_ptr<GlobalScopeCreationParams> creation_params, - v8::Isolate* isolate, WorkerThread* thread) { - return new AudioWorkletGlobalScope(std::move(creation_params), isolate, - thread); + return new AudioWorkletGlobalScope(std::move(creation_params), thread); } AudioWorkletGlobalScope::AudioWorkletGlobalScope( std::unique_ptr<GlobalScopeCreationParams> creation_params, - v8::Isolate* isolate, WorkerThread* thread) - : ThreadedWorkletGlobalScope(std::move(creation_params), isolate, thread) {} + : WorkletGlobalScope(std::move(creation_params), + thread->GetWorkerReportingProxy(), + thread) {} AudioWorkletGlobalScope::~AudioWorkletGlobalScope() = default; void AudioWorkletGlobalScope::Dispose() { DCHECK(IsContextThread()); is_closing_ = true; - ThreadedWorkletGlobalScope::Dispose(); + WorkletGlobalScope::Dispose(); } void AudioWorkletGlobalScope::registerProcessor( @@ -401,7 +401,7 @@ void AudioWorkletGlobalScope::Trace(blink::Visitor* visitor) { visitor->Trace(processor_definition_map_); visitor->Trace(processor_instances_); - ThreadedWorkletGlobalScope::Trace(visitor); + WorkletGlobalScope::Trace(visitor); } } // namespace blink
diff --git a/third_party/blink/renderer/modules/webaudio/audio_worklet_global_scope.h b/third_party/blink/renderer/modules/webaudio/audio_worklet_global_scope.h index d92c005..ce29470 100644 --- a/third_party/blink/renderer/modules/webaudio/audio_worklet_global_scope.h +++ b/third_party/blink/renderer/modules/webaudio/audio_worklet_global_scope.h
@@ -7,7 +7,7 @@ #include "third_party/blink/renderer/bindings/core/v8/script_value.h" #include "third_party/blink/renderer/core/execution_context/execution_context.h" -#include "third_party/blink/renderer/core/workers/threaded_worklet_global_scope.h" +#include "third_party/blink/renderer/core/workers/worklet_global_scope.h" #include "third_party/blink/renderer/modules/modules_export.h" #include "third_party/blink/renderer/modules/webaudio/audio_param_descriptor.h" #include "third_party/blink/renderer/platform/audio/audio_array.h" @@ -46,14 +46,12 @@ // This is constructed and destroyed on a worker thread, and all methods also // must be called on the worker thread. -class MODULES_EXPORT AudioWorkletGlobalScope final - : public ThreadedWorkletGlobalScope { +class MODULES_EXPORT AudioWorkletGlobalScope final : public WorkletGlobalScope { DEFINE_WRAPPERTYPEINFO(); public: static AudioWorkletGlobalScope* Create( std::unique_ptr<GlobalScopeCreationParams>, - v8::Isolate*, WorkerThread*); ~AudioWorkletGlobalScope() override; bool IsAudioWorkletGlobalScope() const final { return true; } @@ -106,7 +104,6 @@ private: AudioWorkletGlobalScope(std::unique_ptr<GlobalScopeCreationParams>, - v8::Isolate*, WorkerThread*); bool is_closing_ = false;
diff --git a/third_party/blink/renderer/modules/webaudio/audio_worklet_thread.cc b/third_party/blink/renderer/modules/webaudio/audio_worklet_thread.cc index 6195e9cf..2778e171 100644 --- a/third_party/blink/renderer/modules/webaudio/audio_worklet_thread.cc +++ b/third_party/blink/renderer/modules/webaudio/audio_worklet_thread.cc
@@ -68,8 +68,7 @@ std::unique_ptr<GlobalScopeCreationParams> creation_params) { TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("audio-worklet"), "AudioWorkletThread::createWorkerGlobalScope"); - return AudioWorkletGlobalScope::Create(std::move(creation_params), - GetIsolate(), this); + return AudioWorkletGlobalScope::Create(std::move(creation_params), this); } } // namespace blink
diff --git a/third_party/blink/renderer/platform/BUILD.gn b/third_party/blink/renderer/platform/BUILD.gn index 8c0b114..ba7d1183 100644 --- a/third_party/blink/renderer/platform/BUILD.gn +++ b/third_party/blink/renderer/platform/BUILD.gn
@@ -665,8 +665,8 @@ "fonts/mac/core_text_font_format_support.cc", "fonts/mac/core_text_font_format_support.h", "fonts/mac/font_cache_mac.mm", - "fonts/mac/font_family_matcher_mac.h", - "fonts/mac/font_family_matcher_mac.mm", + "fonts/mac/font_matcher_mac.h", + "fonts/mac/font_matcher_mac.mm", "fonts/mac/font_platform_data_mac.mm", "fonts/ng_text_fragment_paint_info.h", "fonts/opentype/font_format_check.cc", @@ -1678,7 +1678,7 @@ "fonts/font_test.cc", "fonts/font_test_utilities.cc", "fonts/generic_font_family_settings_test.cc", - "fonts/mac/font_family_matcher_mac_test.mm", + "fonts/mac/font_matcher_mac_test.mm", "fonts/opentype/font_settings_test.cc", "fonts/opentype/open_type_vertical_data_test.cc", "fonts/orientation_iterator_test.cc",
diff --git a/third_party/blink/renderer/platform/exported/web_url_loader_test_delegate.cc b/third_party/blink/renderer/platform/exported/web_url_loader_test_delegate.cc index 417aab0..ce7d6b7e 100644 --- a/third_party/blink/renderer/platform/exported/web_url_loader_test_delegate.cc +++ b/third_party/blink/renderer/platform/exported/web_url_loader_test_delegate.cc
@@ -44,9 +44,10 @@ int64_t total_encoded_data_length, int64_t total_encoded_body_length, int64_t total_decoded_body_length) { - original_client->DidFinishLoading(finish_time, total_encoded_data_length, - total_encoded_body_length, - total_decoded_body_length, false); + original_client->DidFinishLoading( + finish_time, total_encoded_data_length, total_encoded_body_length, + total_decoded_body_length, false, + std::vector<network::cors::PreflightTimingInfo>()); } } // namespace blink
diff --git a/third_party/blink/renderer/platform/fonts/mac/font_cache_mac.mm b/third_party/blink/renderer/platform/fonts/mac/font_cache_mac.mm index 7eba080..8b60504 100644 --- a/third_party/blink/renderer/platform/fonts/mac/font_cache_mac.mm +++ b/third_party/blink/renderer/platform/fonts/mac/font_cache_mac.mm
@@ -37,9 +37,10 @@ #include "third_party/blink/renderer/platform/fonts/font_description.h" #include "third_party/blink/renderer/platform/fonts/font_face_creation_params.h" #include "third_party/blink/renderer/platform/fonts/font_platform_data.h" -#include "third_party/blink/renderer/platform/fonts/mac/font_family_matcher_mac.h" +#include "third_party/blink/renderer/platform/fonts/mac/font_matcher_mac.h" #include "third_party/blink/renderer/platform/fonts/simple_font_data.h" #include "third_party/blink/renderer/platform/layout_test_support.h" +#include "third_party/blink/renderer/platform/runtime_enabled_features.h" #include "third_party/blink/renderer/platform/scheduler/public/thread.h" #include "third_party/blink/renderer/platform/wtf/functional.h" #include "third_party/blink/renderer/platform/wtf/std_lib_extras.h" @@ -248,23 +249,29 @@ const FontDescription& font_description, const FontFaceCreationParams& creation_params, float font_size, - AlternateFontName) { + AlternateFontName alternate_name) { NSFontTraitMask traits = font_description.Style() ? NSFontItalicTrait : 0; float size = font_size; - NSFont* ns_font = MatchNSFontFamily(creation_params.Family(), traits, - font_description.Weight(), size); - if (!ns_font) + NSFont* matched_font = nullptr; + if (alternate_name == AlternateFontName::kLocalUniqueFace && + RuntimeEnabledFeatures::FontSrcLocalMatchingEnabled()) { + matched_font = MatchUniqueFont(creation_params.Family(), size); + } else { + matched_font = MatchNSFontFamily(creation_params.Family(), traits, + font_description.Weight(), size); + } + if (!matched_font) return nullptr; NSFontManager* font_manager = [NSFontManager sharedFontManager]; NSFontTraitMask actual_traits = 0; if (font_description.Style()) - actual_traits = [font_manager traitsOfFont:ns_font]; - NSInteger actual_weight = [font_manager weightOfFont:ns_font]; + actual_traits = [font_manager traitsOfFont:matched_font]; + NSInteger actual_weight = [font_manager weightOfFont:matched_font]; NSFont* platform_font = - UseHinting() ? [ns_font screenFont] : [ns_font printerFont]; + UseHinting() ? [matched_font screenFont] : [matched_font printerFont]; NSInteger app_kit_weight = ToAppKitFontWeight(font_description.Weight()); // TODO(eae): Remove once skia supports bold emoji. See
diff --git a/third_party/blink/renderer/platform/fonts/mac/font_family_matcher_mac_test.mm b/third_party/blink/renderer/platform/fonts/mac/font_family_matcher_mac_test.mm deleted file mode 100644 index 6ed8ac7..0000000 --- a/third_party/blink/renderer/platform/fonts/mac/font_family_matcher_mac_test.mm +++ /dev/null
@@ -1,41 +0,0 @@ -// Copyright 2015 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#import "third_party/blink/renderer/platform/fonts/mac/font_family_matcher_mac.h" - -#include <AppKit/AppKit.h> - -#include "testing/gtest/include/gtest/gtest.h" -#include "third_party/blink/renderer/platform/font_family_names.h" -#include "third_party/blink/renderer/platform/mac/version_util_mac.h" - -@interface NSString (YosemiteAdditions) -- (BOOL)containsString:(NSString*)string; -@end - -namespace blink { - -void TestSystemFontContainsString(FontSelectionValue desired_weight, - NSString* substring) { - NSFont* font = - MatchNSFontFamily(FontFamilyNames::system_ui, 0, desired_weight, 11); - EXPECT_TRUE([font.description containsString:substring]); -} - -TEST(FontFamilyMatcherMacTest, YosemiteFontWeights) { - if (!IsOS10_10()) - return; - - TestSystemFontContainsString(FontSelectionValue(100), @"-UltraLight"); - TestSystemFontContainsString(FontSelectionValue(200), @"-Thin"); - TestSystemFontContainsString(FontSelectionValue(300), @"-Light"); - TestSystemFontContainsString(FontSelectionValue(400), @"-Regular"); - TestSystemFontContainsString(FontSelectionValue(500), @"-Medium"); - TestSystemFontContainsString(FontSelectionValue(600), @"-Bold"); - TestSystemFontContainsString(FontSelectionValue(700), @"-Bold"); - TestSystemFontContainsString(FontSelectionValue(800), @"-Heavy"); - TestSystemFontContainsString(FontSelectionValue(900), @"-Heavy"); -} - -} // namespace blink
diff --git a/third_party/blink/renderer/platform/fonts/mac/font_family_matcher_mac.h b/third_party/blink/renderer/platform/fonts/mac/font_matcher_mac.h similarity index 87% rename from third_party/blink/renderer/platform/fonts/mac/font_family_matcher_mac.h rename to third_party/blink/renderer/platform/fonts/mac/font_matcher_mac.h index 679bc3e0..23de6b6c 100644 --- a/third_party/blink/renderer/platform/fonts/mac/font_family_matcher_mac.h +++ b/third_party/blink/renderer/platform/fonts/mac/font_matcher_mac.h
@@ -24,8 +24,8 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_FONTS_MAC_FONT_FAMILY_MATCHER_MAC_H_ -#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_FONTS_MAC_FONT_FAMILY_MATCHER_MAC_H_ +#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_FONTS_MAC_FONT_MATCHER_MAC_H_ +#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_FONTS_MAC_FONT_MATCHER_MAC_H_ #include <AppKit/NSFontManager.h> #include "third_party/blink/renderer/platform/fonts/font_selection_types.h" @@ -39,9 +39,12 @@ FontSelectionValue desired_weight, float size); +PLATFORM_EXPORT NSFont* MatchUniqueFont(const AtomicString& unique_font_name, + float size); + // Converts ablink::FontSelectionValue to the nearest AppKit font weight if // possible, otherwise returns the default font weight. int ToAppKitFontWeight(FontSelectionValue); -} +} // namespace blink #endif // THIRD_PARTY_BLINK_RENDERER_PLATFORM_FONTS_MAC_FONT_FAMILY_MATCHER_MAC_H_
diff --git a/third_party/blink/renderer/platform/fonts/mac/font_family_matcher_mac.mm b/third_party/blink/renderer/platform/fonts/mac/font_matcher_mac.mm similarity index 84% rename from third_party/blink/renderer/platform/fonts/mac/font_family_matcher_mac.mm rename to third_party/blink/renderer/platform/fonts/mac/font_matcher_mac.mm index 0c0a983..c6bced3e 100644 --- a/third_party/blink/renderer/platform/fonts/mac/font_family_matcher_mac.mm +++ b/third_party/blink/renderer/platform/fonts/mac/font_matcher_mac.mm
@@ -27,14 +27,16 @@ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#import "third_party/blink/renderer/platform/fonts/mac/font_family_matcher_mac.h" +#import "third_party/blink/renderer/platform/fonts/mac/font_matcher_mac.h" #import <AppKit/AppKit.h> #import <Foundation/Foundation.h> #import <math.h> +#include "base/stl_util.h" #include "third_party/blink/renderer/platform/fonts/font_cache.h" #include "third_party/blink/renderer/platform/mac/version_util_mac.h" #import "third_party/blink/renderer/platform/wtf/hash_set.h" +#import "third_party/blink/renderer/platform/wtf/retain_ptr.h" #import "third_party/blink/renderer/platform/wtf/text/atomic_string_hash.h" @interface NSFont (YosemiteAdditions) @@ -60,7 +62,7 @@ size_t select_weight = roundf(font_weight / 100) - 1; DCHECK_GE(select_weight, 0ul); - DCHECK_LE(select_weight, arraysize(ns_font_weights)); + DCHECK_LE(select_weight, base::size(ns_font_weights)); CGFloat* return_weight = reinterpret_cast<CGFloat*>(&ns_font_weights[select_weight]); return *return_weight; @@ -74,9 +76,7 @@ const NSFontTraitMask IMPORTANT_FONT_TRAITS = (NSCompressedFontMask | NSCondensedFontMask | NSExpandedFontMask | - NSItalicFontMask | - NSNarrowFontMask | - NSPosterFontMask | + NSItalicFontMask | NSNarrowFontMask | NSPosterFontMask | NSSmallCapsFontMask); static BOOL AcceptableChoice(NSFontTraitMask desired_traits, @@ -127,6 +127,43 @@ return candidate_weight_delta_magnitude < chosen_weight_delta_magnitude; } +NSFont* MatchUniqueFont(const AtomicString& unique_font_name, float size) { + // Testing with a large list of fonts available on Mac OS shows that matching + // for kCTFontNameAttribute matches postscript name as well as full font name. + WTF::RetainPtr<CFMutableDictionaryRef> attributes( + CFDictionaryCreateMutable(kCFAllocatorDefault, 0, NULL, NULL)); + WTF::RetainPtr<NSString> desired_name(unique_font_name); + CFDictionarySetValue(attributes.Get(), kCTFontNameAttribute, + desired_name.Get()); + WTF::RetainPtr<CFNumberRef> font_size = + CFNumberCreate(kCFAllocatorDefault, kCFNumberFloat32Type, &size); + CFDictionarySetValue(attributes.Get(), kCTFontSizeAttribute, font_size.Get()); + WTF::RetainPtr<CTFontDescriptorRef> descriptor( + CTFontDescriptorCreateWithAttributes(attributes.Get())); + WTF::RetainPtr<CTFontRef> matched_font( + CTFontCreateWithFontDescriptor(descriptor.Get(), 0, nullptr)); + // CoreText will usually give us *something* but not always an exactly + // matched font. + DCHECK(matched_font.Get()); + WTF::RetainPtr<CFStringRef> matched_font_ps_name( + CTFontCopyName(matched_font.Get(), kCTFontPostScriptNameKey)); + WTF::RetainPtr<CFStringRef> matched_font_full_font_name( + CTFontCopyName(matched_font.Get(), kCTFontFullNameKey)); + // If the found font does not match in postscript name or full font name, it's + // not the exact match that is required, so return nullptr. + if ((kCFCompareEqualTo != + CFStringCompare(matched_font_ps_name.Get(), + (__bridge CFStringRef)desired_name.Get(), + kCFCompareCaseInsensitive)) && + (kCFCompareEqualTo != + CFStringCompare(matched_font_full_font_name.Get(), + (__bridge CFStringRef)desired_name.Get(), + kCFCompareCaseInsensitive))) { + return nullptr; + } + return (__bridge NSFont*)matched_font.LeakRef(); +} + // Family name is somewhat of a misnomer here. We first attempt to find an // exact match comparing the desiredFamily to the PostScript name of the // installed fonts. If that fails we then do a search based on the family @@ -308,7 +345,7 @@ 12, // FontWeight900 }; DCHECK_GE(select_weight, 0ul); - DCHECK_LE(select_weight, arraysize(app_kit_font_weights)); + DCHECK_LE(select_weight, base::size(app_kit_font_weights)); return app_kit_font_weights[select_weight]; }
diff --git a/third_party/blink/renderer/platform/fonts/mac/font_matcher_mac_test.mm b/third_party/blink/renderer/platform/fonts/mac/font_matcher_mac_test.mm new file mode 100644 index 0000000..67476f5a --- /dev/null +++ b/third_party/blink/renderer/platform/fonts/mac/font_matcher_mac_test.mm
@@ -0,0 +1,93 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#import "third_party/blink/renderer/platform/fonts/mac/font_matcher_mac.h" + +#include <AppKit/AppKit.h> + +#include "testing/gtest/include/gtest/gtest.h" +#include "third_party/blink/renderer/platform/font_family_names.h" +#include "third_party/blink/renderer/platform/mac/version_util_mac.h" + +@interface NSString (YosemiteAdditions) +- (BOOL)containsString:(NSString*)string; +@end + +namespace blink { + +void TestSystemFontContainsString(FontSelectionValue desired_weight, + NSString* substring) { + NSFont* font = + MatchNSFontFamily(FontFamilyNames::system_ui, 0, desired_weight, 11); + EXPECT_TRUE([font.description containsString:substring]); +} + +TEST(FontMatcherMacTest, YosemiteFontWeights) { + if (!IsOS10_10()) + return; + + TestSystemFontContainsString(FontSelectionValue(100), @"-UltraLight"); + TestSystemFontContainsString(FontSelectionValue(200), @"-Thin"); + TestSystemFontContainsString(FontSelectionValue(300), @"-Light"); + TestSystemFontContainsString(FontSelectionValue(400), @"-Regular"); + TestSystemFontContainsString(FontSelectionValue(500), @"-Medium"); + TestSystemFontContainsString(FontSelectionValue(600), @"-Bold"); + TestSystemFontContainsString(FontSelectionValue(700), @"-Bold"); + TestSystemFontContainsString(FontSelectionValue(800), @"-Heavy"); + TestSystemFontContainsString(FontSelectionValue(900), @"-Heavy"); +} + +TEST(FontMatcherMacTest, NoUniqueFontMatchOnUnavailableFont) { + NSFont* font = MatchUniqueFont( + "ThisFontNameDoesNotExist07F444B9-4DDF-4A41-8F30-C80D4ED4CCA2", 12); + EXPECT_FALSE(font); +} + +// If these font names are unavaiable on future Mac OS versions, please try to +// find replacements or remove individual lines. +TEST(FontMatcherMacTest, MatchFullFontName) { + const char* font_names[] = {"American Typewriter Condensed Light", + "Arial Narrow Bold Italic", + "Baskerville SemiBold Italic", + "Devanagari MT", + "DIN Alternate Bold", + "Gill Sans Light Italic", + "Iowan Old Style Titling", + "Malayalam Sangam MN", + "Hiragino Maru Gothic Pro W4", + "Hiragino Kaku Gothic StdN W8"}; + + for (const char* font_name : font_names) { + @autoreleasepool { + NSFont* font = MatchUniqueFont(font_name, 12); + EXPECT_TRUE(font); + } + } +} + +// If these font names are unavaiable on future Mac OS versions, please try to +// find replacements or remove individual lines. +TEST(FontMatcherMacTest, MatchPostscriptName) { + const char* font_names[] = { + "AmericanTypewriter-CondensedLight", + "ArialNarrow-BoldItalic", + "Baskerville-SemiBoldItalic", + "DevanagariMT", + "DINAlternate-Bold", + "GillSans-LightItalic", + "IowanOldStyle-Titling", + "MalayalamSangamMN", + "HiraMaruPro-W4", + "HiraKakuStdN-W8", + }; + + for (const char* font_name : font_names) { + @autoreleasepool { + NSFont* font = MatchUniqueFont(font_name, 12); + EXPECT_TRUE(font); + } + } +} + +} // namespace blink
diff --git a/third_party/blink/renderer/platform/image-decoders/png/png_image_decoder_test.cc b/third_party/blink/renderer/platform/image-decoders/png/png_image_decoder_test.cc index 26ab2543..b4fa63f 100644 --- a/third_party/blink/renderer/platform/image-decoders/png/png_image_decoder_test.cc +++ b/third_party/blink/renderer/platform/image-decoders/png/png_image_decoder_test.cc
@@ -1078,6 +1078,11 @@ // Color components of opaque and transparent 16 bit PNG, read with libpng // in BigEndian and scaled to [0,1]. The values are read from non-interlaced // samples, but used for both interlaced and non-interlaced test cases. + // The sample pngs were all created by color converting the 8 bit sRGB source + // in Adobe Photoshop 18. The only exception is e-sRGB test case, for which + // Adobe software created a non-matching color profile (see crbug.com/874939). + // Hence, SkEncoder was used to generate the e-sRGB file (see the skia fiddle + // here: https://fiddle.skia.org/c/17beedfd66dac1ec930f0c414c50f847). static const std::vector<float> source_pixels_opaque_srgb = { 0.4986953536, 0.5826657511, 0.7013199054, 1, // Top left pixel 0.907988098, 0.8309605554, 0.492011902, 1, // Top right pixel @@ -1094,10 +1099,10 @@ 0.772121767, 0.9671625849, 0.973510338, 1, // Bottom left pixel 0.9118944076, 0.9645685512, 0.9110704204, 1}; // Bottom right pixel static const std::vector<float> source_pixels_opaque_e_srgb = { - 0.6414435035, 0.6857862211, 0.747005417, 1, // Top left pixel - 0.877347982, 0.8382848859, 0.6494087129, 1, // Top right pixel - 0.735194934, 0.9353933013, 0.9374380102, 1, // Bottom left pixel - 0.9209277485, 0.9575799191, 0.9264515145, 1}; // Bottom right pixel + 0.6977539062, 0.5839843750, 0.4978027344, 1, // Top left pixel + 0.4899902344, 0.8310546875, 0.9096679688, 1, // Top right pixel + 0.9760742188, 0.9721679688, 0.6230468750, 1, // Bottom left pixel + 0.9057617188, 0.9643554688, 0.8940429688, 1}; // Bottom right pixel static const std::vector<float> source_pixels_opaque_prophoto = { 0.5032883192, 0.5191271839, 0.6309147784, 1, // Top left pixel 0.8184176394, 0.8002899214, 0.5526970321, 1, // Top right pixel @@ -1125,10 +1130,10 @@ 0.4302738994, 0.9179064622, 0.933806363, 0.4, // Bottom left pixel 0.5595330739, 0.8228122377, 0.5554436561, 0.2}; // Bottom right pixel static const std::vector<float> source_pixels_transparent_e_srgb = { - 0.5517814908, 0.6072327764, 0.6837415122, 0.8, // Top left pixel - 0.7955901427, 0.7304646372, 0.4156557565, 0.6, // Top right pixel - 0.3380178531, 0.8385290303, 0.8435950256, 0.4, // Bottom left pixel - 0.6046997787, 0.7879606317, 0.6323186084, 0.2}; // Bottom right pixel + 0.6230468750, 0.4782714844, 0.3723144531, 0.8, // Top left pixel + 0.1528320312, 0.7172851562, 0.8466796875, 0.6, // Top right pixel + 0.9409179688, 0.9331054688, 0.0588073730, 0.4, // Bottom left pixel + 0.5253906250, 0.8310546875, 0.4743652344, 0.2}; // Bottom right pixel static const std::vector<float> source_pixels_transparent_prophoto = { 0.379064622, 0.3988708324, 0.5386282139, 0.8, // Top left pixel 0.6973525597, 0.6671396963, 0.2544289311, 0.6, // Top right pixel @@ -1174,10 +1179,8 @@ static std::vector<PNGSample> GetPNGSamplesInfo(bool include_8bit_pngs) { std::vector<PNGSample> png_samples; std::vector<String> interlace_status = {"", "_interlaced"}; - // TODO(zakerinasab) https://crbug.com/874939: - // e-sRGB decodes fine to 8888, but fails to decode to F16, hence not tested. - std::vector<String> color_spaces = {"sRGB", "AdobeRGB", "DisplayP3", - "ProPhoto", "Rec2020"}; + std::vector<String> color_spaces = {"sRGB", "AdobeRGB", "DisplayP3", + "e-sRGB", "ProPhoto", "Rec2020"}; std::vector<String> alpha_status = {"_opaque", "_transparent"}; for (String color_space : color_spaces) {
diff --git a/third_party/blink/renderer/platform/loader/fetch/resource_fetcher.cc b/third_party/blink/renderer/platform/loader/fetch/resource_fetcher.cc index c37d0c9..f2ef796 100644 --- a/third_party/blink/renderer/platform/loader/fetch/resource_fetcher.cc +++ b/third_party/blink/renderer/platform/loader/fetch/resource_fetcher.cc
@@ -1561,11 +1561,14 @@ resource->ReloadIfLoFiOrPlaceholderImage(this, Resource::kReloadIfNeeded); } -void ResourceFetcher::HandleLoaderFinish(Resource* resource, - TimeTicks finish_time, - LoaderFinishType type, - uint32_t inflight_keepalive_bytes, - bool should_report_corb_blocking) { +void ResourceFetcher::HandleLoaderFinish( + Resource* resource, + TimeTicks finish_time, + LoaderFinishType type, + uint32_t inflight_keepalive_bytes, + bool should_report_corb_blocking, + const std::vector<network::cors::PreflightTimingInfo>& + cors_preflight_timing_info) { DCHECK(resource); DCHECK_LE(inflight_keepalive_bytes, inflight_keepalive_bytes_); @@ -1615,6 +1618,31 @@ Context().AddResourceTiming(*info); resource->ReportResourceTimingToClients(*info); } + + // Store additional timing info if CORS preflights are performed. + for (const auto& timing_info : cors_preflight_timing_info) { + // InitiatorType and InitialURL should be the same with each of the + // original request. + scoped_refptr<ResourceTimingInfo> preflight_info = + ResourceTimingInfo::Create(info->InitiatorType(), + timing_info.start_time, false); + preflight_info->SetInitialURL(info->InitialURL()); + preflight_info->SetLoadFinishTime(timing_info.finish_time); + preflight_info->AddFinalTransferSize(timing_info.transfer_size); + + // Set a provisional response to provide possible other information. + ResourceResponse response(info->InitialURL()); + response.SetAlpnNegotiatedProtocol( + WebString::FromUTF8(timing_info.alpn_negotiated_protocol)); + response.SetConnectionInfo(timing_info.connection_info); + response.SetHTTPHeaderField( + HTTPNames::Timing_Allow_Origin, + WebString::FromUTF8(timing_info.timing_allow_origin)); + response.SetEncodedDataLength(timing_info.transfer_size); + preflight_info->SetFinalResponse(response); + + Context().AddResourceTiming(*preflight_info); + } } resource->VirtualTimePauser().UnpauseVirtualTime();
diff --git a/third_party/blink/renderer/platform/loader/fetch/resource_fetcher.h b/third_party/blink/renderer/platform/loader/fetch/resource_fetcher.h index bf5a162e..1bb482a3 100644 --- a/third_party/blink/renderer/platform/loader/fetch/resource_fetcher.h +++ b/third_party/blink/renderer/platform/loader/fetch/resource_fetcher.h
@@ -28,6 +28,8 @@ #define THIRD_PARTY_BLINK_RENDERER_PLATFORM_LOADER_FETCH_RESOURCE_FETCHER_H_ #include <memory> + +#include "services/network/public/cpp/cors/preflight_timing_info.h" #include "third_party/blink/public/mojom/service_worker/service_worker_object.mojom-blink.h" #include "third_party/blink/renderer/platform/heap/persistent.h" #include "third_party/blink/renderer/platform/loader/fetch/fetch_context.h" @@ -141,7 +143,9 @@ TimeTicks finish_time, LoaderFinishType, uint32_t inflight_keepalive_bytes, - bool should_report_corb_blocking); + bool should_report_corb_blocking, + const std::vector<network::cors::PreflightTimingInfo>& + cors_preflight_timing_info); void HandleLoaderError(Resource*, const ResourceError&, uint32_t inflight_keepalive_bytes);
diff --git a/third_party/blink/renderer/platform/loader/fetch/resource_fetcher_test.cc b/third_party/blink/renderer/platform/loader/fetch/resource_fetcher_test.cc index 36b8959..5ec4206 100644 --- a/third_party/blink/renderer/platform/loader/fetch/resource_fetcher_test.cc +++ b/third_party/blink/renderer/platform/loader/fetch/resource_fetcher_test.cc
@@ -237,8 +237,9 @@ fetcher->GetNavigationTimingInfo(); ASSERT_TRUE(navigation_timing_info); long long encoded_data_length = 123; - resource->Loader()->DidFinishLoading(TimeTicks(), encoded_data_length, 0, 0, - false); + resource->Loader()->DidFinishLoading( + TimeTicks(), encoded_data_length, 0, 0, false, + std::vector<network::cors::PreflightTimingInfo>()); EXPECT_EQ(navigation_timing_info->TransferSize(), encoded_data_length); // When there are redirects.
diff --git a/third_party/blink/renderer/platform/loader/fetch/resource_loader.cc b/third_party/blink/renderer/platform/loader/fetch/resource_loader.cc index 7c26a50..7e7ee3d 100644 --- a/third_party/blink/renderer/platform/loader/fetch/resource_loader.cc +++ b/third_party/blink/renderer/platform/loader/fetch/resource_loader.cc
@@ -887,16 +887,20 @@ resource_->Identifier(), network_instrumentation::RequestOutcome::kSuccess); - fetcher_->HandleLoaderFinish(resource_.Get(), TimeTicks(), - ResourceFetcher::kDidFinishFirstPartInMultipart, - 0, false); + fetcher_->HandleLoaderFinish( + resource_.Get(), TimeTicks(), + ResourceFetcher::kDidFinishFirstPartInMultipart, 0, false, + std::vector<network::cors::PreflightTimingInfo>()); } -void ResourceLoader::DidFinishLoading(TimeTicks finish_time, - int64_t encoded_data_length, - int64_t encoded_body_length, - int64_t decoded_body_length, - bool should_report_corb_blocking) { +void ResourceLoader::DidFinishLoading( + TimeTicks finish_time, + int64_t encoded_data_length, + int64_t encoded_body_length, + int64_t decoded_body_length, + bool should_report_corb_blocking, + const std::vector<network::cors::PreflightTimingInfo>& + cors_preflight_timing_info) { resource_->SetEncodedDataLength(encoded_data_length); resource_->SetEncodedBodyLength(encoded_body_length); resource_->SetDecodedBodyLength(decoded_body_length); @@ -919,7 +923,8 @@ fetcher_->HandleLoaderFinish( resource_.Get(), finish_time, ResourceFetcher::kDidFinishLoading, - inflight_keepalive_bytes_, should_report_corb_blocking); + inflight_keepalive_bytes_, should_report_corb_blocking, + cors_preflight_timing_info); } void ResourceLoader::DidFail(const WebURLError& error, @@ -1014,7 +1019,8 @@ FinishedCreatingBlob(blob); } DidFinishLoading(CurrentTimeTicks(), encoded_data_length, encoded_body_length, - decoded_body_length, false); + decoded_body_length, false, + std::vector<network::cors::PreflightTimingInfo>()); } void ResourceLoader::Dispose() { @@ -1097,7 +1103,8 @@ DidFinishLoading(load_did_finish_before_blob_->finish_time, response.EncodedDataLength(), response.EncodedBodyLength(), response.DecodedBodyLength(), - load_did_finish_before_blob_->should_report_corb_blocking); + load_did_finish_before_blob_->should_report_corb_blocking, + std::vector<network::cors::PreflightTimingInfo>()); } }
diff --git a/third_party/blink/renderer/platform/loader/fetch/resource_loader.h b/third_party/blink/renderer/platform/loader/fetch/resource_loader.h index 6011ec2d..ed7a4a5 100644 --- a/third_party/blink/renderer/platform/loader/fetch/resource_loader.h +++ b/third_party/blink/renderer/platform/loader/fetch/resource_loader.h
@@ -120,11 +120,13 @@ void DidReceiveTransferSizeUpdate(int transfer_size_diff) override; void DidStartLoadingResponseBody( mojo::ScopedDataPipeConsumerHandle body) override; - void DidFinishLoading(TimeTicks finish_time, - int64_t encoded_data_length, - int64_t encoded_body_length, - int64_t decoded_body_length, - bool should_report_corb_blocking) override; + void DidFinishLoading( + TimeTicks finish_time, + int64_t encoded_data_length, + int64_t encoded_body_length, + int64_t decoded_body_length, + bool should_report_corb_blocking, + const std::vector<network::cors::PreflightTimingInfo>&) override; void DidFail(const WebURLError&, int64_t encoded_data_length, int64_t encoded_body_length,
diff --git a/third_party/blink/renderer/platform/runtime_enabled_features.json5 b/third_party/blink/renderer/platform/runtime_enabled_features.json5 index 3fceef2..7a31007 100644 --- a/third_party/blink/renderer/platform/runtime_enabled_features.json5 +++ b/third_party/blink/renderer/platform/runtime_enabled_features.json5
@@ -114,6 +114,7 @@ }, { name: "BackgroundFetch", + origin_trial_feature_name: "BackgroundFetch", status: "experimental", }, {
diff --git a/third_party/blink/renderer/platform/text/text_break_iterator.cc b/third_party/blink/renderer/platform/text/text_break_iterator.cc index d9cd41f..e39e8df0 100644 --- a/third_party/blink/renderer/platform/text/text_break_iterator.cc +++ b/third_party/blink/renderer/platform/text/text_break_iterator.cc
@@ -298,8 +298,8 @@ BreakSpaceType break_space> inline int LazyLineBreakIterator::NextBreakablePosition( int pos, - const CharacterType* str) const { - int len = static_cast<int>(string_.length()); + const CharacterType* str, + int len) const { DCHECK_GE(pos, 0); DCHECK_GE(static_cast<unsigned>(pos), start_offset_); int next_break = -1; @@ -379,30 +379,35 @@ template <typename CharacterType, LineBreakType lineBreakType> inline int LazyLineBreakIterator::NextBreakablePosition( int pos, - const CharacterType* str) const { + const CharacterType* str, + int len) const { switch (break_space_) { case BreakSpaceType::kBeforeEverySpace: return NextBreakablePosition<CharacterType, lineBreakType, - BreakSpaceType::kBeforeEverySpace>(pos, str); + BreakSpaceType::kBeforeEverySpace>(pos, str, + len); case BreakSpaceType::kBeforeSpaceRun: return NextBreakablePosition<CharacterType, lineBreakType, - BreakSpaceType::kBeforeSpaceRun>(pos, str); + BreakSpaceType::kBeforeSpaceRun>(pos, str, + len); } NOTREACHED(); return NextBreakablePosition<CharacterType, lineBreakType, - BreakSpaceType::kBeforeEverySpace>(pos, str); + BreakSpaceType::kBeforeEverySpace>(pos, str, + len); } template <LineBreakType lineBreakType> -inline int LazyLineBreakIterator::NextBreakablePosition(int pos) const { +inline int LazyLineBreakIterator::NextBreakablePosition(int pos, + int len) const { if (UNLIKELY(string_.IsNull())) return 0; if (string_.Is8Bit()) { - return NextBreakablePosition<LChar, lineBreakType>(pos, - string_.Characters8()); + return NextBreakablePosition<LChar, lineBreakType>( + pos, string_.Characters8(), len); } - return NextBreakablePosition<UChar, lineBreakType>(pos, - string_.Characters16()); + return NextBreakablePosition<UChar, lineBreakType>( + pos, string_.Characters16(), len); } int LazyLineBreakIterator::NextBreakablePositionBreakCharacter(int pos) const { @@ -415,16 +420,16 @@ return next != kTextBreakDone ? next + start_offset_ : string_.length(); } -int LazyLineBreakIterator::NextBreakablePosition( - int pos, - LineBreakType line_break_type) const { +int LazyLineBreakIterator::NextBreakablePosition(int pos, + LineBreakType line_break_type, + int len) const { switch (line_break_type) { case LineBreakType::kNormal: - return NextBreakablePosition<LineBreakType::kNormal>(pos); + return NextBreakablePosition<LineBreakType::kNormal>(pos, len); case LineBreakType::kBreakAll: - return NextBreakablePosition<LineBreakType::kBreakAll>(pos); + return NextBreakablePosition<LineBreakType::kBreakAll>(pos, len); case LineBreakType::kKeepAll: - return NextBreakablePosition<LineBreakType::kKeepAll>(pos); + return NextBreakablePosition<LineBreakType::kKeepAll>(pos, len); case LineBreakType::kBreakCharacter: return NextBreakablePositionBreakCharacter(pos); } @@ -432,9 +437,15 @@ return NextBreakablePosition(pos, LineBreakType::kNormal); } +int LazyLineBreakIterator::NextBreakablePosition( + int pos, + LineBreakType line_break_type) const { + return NextBreakablePosition(pos, line_break_type, + static_cast<int>(string_.length())); +} + unsigned LazyLineBreakIterator::NextBreakOpportunity(unsigned offset) const { - int next_break = -1; - IsBreakable(offset, next_break); + int next_break = NextBreakablePosition(offset, break_type_); DCHECK_GE(next_break, 0); return next_break; } @@ -442,10 +453,7 @@ unsigned LazyLineBreakIterator::NextBreakOpportunity(unsigned offset, unsigned len) const { DCHECK_LE(len, string_.length()); - // TODO(kojii): |len| is not utilized for perf benefit as - // |NextBreakablePosition| does not accept it due to a revert in - // crbug.com/883963. - int next_break = NextBreakablePosition(offset, break_type_); + int next_break = NextBreakablePosition(offset, break_type_, len); DCHECK_GE(next_break, 0); return next_break; } @@ -453,9 +461,20 @@ unsigned LazyLineBreakIterator::PreviousBreakOpportunity(unsigned offset, unsigned min) const { unsigned pos = std::min(offset, string_.length()); - for (; pos > min; pos--) { - if (IsBreakable(pos)) - return pos; + // +2 to ensure at least one code point is included. + unsigned end = std::min(pos + 2, string_.length()); + while (pos > min) { + int next_break = NextBreakablePosition(pos, break_type_, end); + DCHECK_GE(next_break, 0); + if (static_cast<unsigned>(next_break) == pos) + return next_break; + + // There's no break opportunities at |pos| or after. + end = pos; + if (string_.Is8Bit()) + --pos; + else + U16_BACK_1(string_.Characters16(), 0, pos); } return min; }
diff --git a/third_party/blink/renderer/platform/text/text_break_iterator.h b/third_party/blink/renderer/platform/text/text_break_iterator.h index e2ce60c0..f7f02eb 100644 --- a/third_party/blink/renderer/platform/text/text_break_iterator.h +++ b/third_party/blink/renderer/platform/text/text_break_iterator.h
@@ -242,7 +242,8 @@ // Limit length to pos + 1. // TODO(layout-dev): We should probably try to break out an actual // IsBreakable method from NextBreakablePosition and get rid of this hack. - int next_breakable = NextBreakablePosition(pos, break_type_); + int len = std::min(pos + 1, static_cast<int>(string_.length())); + int next_breakable = NextBreakablePosition(pos, break_type_, len); return pos == next_breakable; } @@ -305,12 +306,13 @@ } template <typename CharacterType, LineBreakType, BreakSpaceType> - int NextBreakablePosition(int pos, const CharacterType* str) const; + int NextBreakablePosition(int pos, const CharacterType* str, int len) const; template <typename CharacterType, LineBreakType> - int NextBreakablePosition(int pos, const CharacterType* str) const; + int NextBreakablePosition(int pos, const CharacterType* str, int len) const; template <LineBreakType> - int NextBreakablePosition(int pos) const; + int NextBreakablePosition(int pos, int len) const; int NextBreakablePositionBreakCharacter(int pos) const; + int NextBreakablePosition(int pos, LineBreakType, int len) const; int NextBreakablePosition(int pos, LineBreakType) const; static const unsigned kPriorContextCapacity = 2;
diff --git a/third_party/blink/tools/blinkpy/common/net/buildbot.py b/third_party/blink/tools/blinkpy/common/net/buildbot.py index cb8159bb..b218456 100644 --- a/third_party/blink/tools/blinkpy/common/net/buildbot.py +++ b/third_party/blink/tools/blinkpy/common/net/buildbot.py
@@ -72,6 +72,8 @@ if build_number: assert str(build_number).isdigit(), 'expected numeric build number, got %s' % build_number url_base = self.builder_results_url_base(builder_name) + if step_name is None: + step_name = self.get_layout_test_step_name(Build(builder_name, build_number)) if step_name: return '%s/%s/%s/layout-test-results' % ( url_base, build_number, urllib.quote(step_name)) @@ -120,7 +122,7 @@ 'buildnumber': build.build_number, 'name': 'full_results.json', # This forces the server to gives us JSON rather than an HTML page. - 'callback': 'ADD_RESULTS', + 'callback': json_results_generator.JSON_CALLBACK, })) data = NetworkTransaction(return_none_on_404=True).run( lambda: self.fetch_file(url))
diff --git a/third_party/blink/tools/blinkpy/tool/commands/rebaseline.py b/third_party/blink/tools/blinkpy/tool/commands/rebaseline.py index 3d18489..8e3a820f 100644 --- a/third_party/blink/tools/blinkpy/tool/commands/rebaseline.py +++ b/third_party/blink/tools/blinkpy/tool/commands/rebaseline.py
@@ -76,6 +76,10 @@ build_number_option = optparse.make_option( '--build-number', default=None, type='int', help='Optional build number; if not given, the latest build is used.') + step_name_option = optparse.make_option( + '--step-name', + help=('Name of the step which ran the actual tests, and which ' + 'should be used to retrieve results from.')) def __init__(self, options=None): super(AbstractRebaseliningCommand, self).__init__(options=options) @@ -296,7 +300,6 @@ '--port-name', port_name, ]) - copy_command = [self._tool.executable, path_to_blink_tool, 'copy-existing-baselines-internal'] + args copy_baseline_commands.append(tuple([copy_command, cwd]))
diff --git a/third_party/blink/tools/blinkpy/tool/commands/rebaseline_cl_unittest.py b/third_party/blink/tools/blinkpy/tool/commands/rebaseline_cl_unittest.py index 6b7c098..a920cd9e 100644 --- a/third_party/blink/tools/blinkpy/tool/commands/rebaseline_cl_unittest.py +++ b/third_party/blink/tools/blinkpy/tool/commands/rebaseline_cl_unittest.py
@@ -412,8 +412,8 @@ self.assertLog([ 'INFO: Finished try jobs found for all try bots.\n', 'INFO: Failed to fetch results for "MOCK Try Win".\n', - ('INFO: Results URL: https://test-results.appspot.com/data/layout_results' - '/MOCK_Try_Win/5000/layout-test-results/results.html\n'), + ('INFO: Results URL: https://test-results.appspot.com/data/layout_results/' + 'MOCK_Try_Win/5000/webkit_layout_tests%20%28with%20patch%29/layout-test-results/results.html\n'), 'INFO: There are some builders with no results:\n', 'INFO: MOCK Try Win\n', 'INFO: Would you like to continue?\n', @@ -429,8 +429,8 @@ self.assertLog([ 'INFO: Finished try jobs found for all try bots.\n', 'INFO: Failed to fetch results for "MOCK Try Win".\n', - ('INFO: Results URL: https://test-results.appspot.com/data/layout_results' - '/MOCK_Try_Win/5000/layout-test-results/results.html\n'), + ('INFO: Results URL: https://test-results.appspot.com/data/layout_results/' + 'MOCK_Try_Win/5000/webkit_layout_tests%20%28with%20patch%29/layout-test-results/results.html\n'), 'INFO: There are some builders with no results:\n', 'INFO: MOCK Try Win\n', 'INFO: For one/flaky-fail.html:\n',
diff --git a/third_party/blink/tools/blinkpy/tool/commands/rebaseline_test.py b/third_party/blink/tools/blinkpy/tool/commands/rebaseline_test.py index 665c81d..7640cd7 100644 --- a/third_party/blink/tools/blinkpy/tool/commands/rebaseline_test.py +++ b/third_party/blink/tools/blinkpy/tool/commands/rebaseline_test.py
@@ -4,7 +4,6 @@ import json import logging -import optparse from blinkpy.tool.commands.rebaseline import AbstractRebaseliningCommand @@ -22,11 +21,8 @@ self.port_name_option, self.builder_option, self.build_number_option, + self.step_name_option, self.results_directory_option, - optparse.make_option( - '--step-name', - help=('Name of the step which ran the actual tests, and which ' - 'should be used to retrieve results from.')) ]) def execute(self, options, args, tool):
diff --git a/third_party/blink/tools/blinkpy/web_tests/layout_package/json_results_generator.py b/third_party/blink/tools/blinkpy/web_tests/layout_package/json_results_generator.py index c09ad21..2549b49 100644 --- a/third_party/blink/tools/blinkpy/web_tests/layout_package/json_results_generator.py +++ b/third_party/blink/tools/blinkpy/web_tests/layout_package/json_results_generator.py
@@ -31,7 +31,8 @@ _log = logging.getLogger(__name__) -_JSON_PREFIX = "ADD_RESULTS(" +JSON_CALLBACK = "ADD_RESULTS" +_JSON_PREFIX = JSON_CALLBACK + "(" _JSON_SUFFIX = ");"
diff --git a/third_party/blink/tools/blinkpy/web_tests/run_webkit_tests.py b/third_party/blink/tools/blinkpy/web_tests/run_webkit_tests.py index 791c8adb..2e81b05 100644 --- a/third_party/blink/tools/blinkpy/web_tests/run_webkit_tests.py +++ b/third_party/blink/tools/blinkpy/web_tests/run_webkit_tests.py
@@ -318,6 +318,8 @@ "'unexpected' == Ignore any tests that had unexpected results on the bot.")), optparse.make_option( '--iterations', + '--isolated-script-test-repeat', + # TODO(crbug.com/893235): Remove the gtest alias when FindIt no longer uses it. '--gtest_repeat', type='int', default=1, @@ -361,6 +363,7 @@ optparse.make_option( '--num-retries', '--test-launcher-retry-limit', + '--isolated-script-test-launcher-retry-limit', type='int', default=None, help=('Number of times to retry failures. Default (when this ' @@ -401,11 +404,13 @@ '"only" == only run the SKIP tests, ' '"always" == always skip, even if listed on the command line.')), optparse.make_option( + '--isolated-script-test-also-run-disabled-tests', + # TODO(crbug.com/893235): Remove the gtest alias when FindIt no longer uses it. '--gtest_also_run_disabled_tests', - action='store_true', - default=False, # Consistent with the default value of --skipped - help=('Equivalent to --skipped=ignore. This option overrides ' - '--skipped if both are given.')), + action='store_const', + const='ignore', + dest='skipped', + help=('Equivalent to --skipped=ignore.')), optparse.make_option( '--skip-failing-tests', action='store_true', @@ -429,6 +434,12 @@ metavar='FILE', help='read list of tests to run from file'), optparse.make_option( + '--isolated-script-test-filter', + type='string', + help='A list of tests to run separated by TWO colons, e.g. fast::css/test.html, ' + 'same as listing them as positional arguments'), + # TODO(crbug.com/893235): Remove gtest_filter when FindIt no longer uses it. + optparse.make_option( '--gtest_filter', type='string', help='A colon-separated list of tests to run. Wildcards are ' @@ -553,11 +564,12 @@ if not options.skipped: options.skipped = 'always' - if options.gtest_also_run_disabled_tests: - options.skipped = 'ignore' - elif not options.skipped: + if not options.skipped: options.skipped = 'default' + if options.isolated_script_test_filter: + args.extend(options.isolated_script_test_filter.split('::')) + if options.gtest_filter: args.extend(options.gtest_filter.split(':'))
diff --git a/third_party/blink/tools/blinkpy/web_tests/run_webkit_tests_unittest.py b/third_party/blink/tools/blinkpy/web_tests/run_webkit_tests_unittest.py index e248e27d..153ffa83 100644 --- a/third_party/blink/tools/blinkpy/web_tests/run_webkit_tests_unittest.py +++ b/third_party/blink/tools/blinkpy/web_tests/run_webkit_tests_unittest.py
@@ -443,15 +443,15 @@ # Now check that we don't run anything. self.assertEqual(get_tests_run(['--skipped=always', 'passes/skipped/skip.html']), []) - def test_gtest_also_run_disabled_tests(self): + def test_isolated_script_test_also_run_disabled_tests(self): self.assertEqual( - sorted(get_tests_run(['--gtest_also_run_disabled_tests', 'passes'])), + sorted(get_tests_run(['--isolated-script-test-also-run-disabled-tests', 'passes'])), sorted(get_tests_run(['--skipped=ignore', 'passes'])) ) - def test_gtest_also_run_disabled_tests_overrides_skipped(self): + def test_gtest_also_run_disabled_tests(self): self.assertEqual( - sorted(get_tests_run(['--gtest_also_run_disabled_tests', '--skipped=always', 'passes'])), + sorted(get_tests_run(['--gtest_also_run_disabled_tests', 'passes'])), sorted(get_tests_run(['--skipped=ignore', 'passes'])) ) @@ -522,6 +522,14 @@ tests_run = get_tests_run(['--test-list=%s' % filename], host=host) self.assertEqual(['passes/text.html'], tests_run) + def test_isolated_script_test_filter(self): + host = MockHost() + tests_run = get_tests_run( + ['--isolated-script-test-filter=passes/text.html::passes/image.html', 'passes/error.html'], + host=host + ) + self.assertEqual(sorted(tests_run), ['passes/error.html', 'passes/image.html', 'passes/text.html']) + def test_gtest_filter(self): host = MockHost() tests_run = get_tests_run(['--gtest_filter=passes/text.html:passes/image.html', 'passes/error.html'], host=host)
diff --git a/third_party/blink/tools/blinkpy/web_tests/try_flag_unittest.py b/third_party/blink/tools/blinkpy/web_tests/try_flag_unittest.py index 27c1f85..2283d8d 100644 --- a/third_party/blink/tools/blinkpy/web_tests/try_flag_unittest.py +++ b/third_party/blink/tools/blinkpy/web_tests/try_flag_unittest.py
@@ -134,10 +134,11 @@ TryFlag(cmd, host, MockGitCL(host, self.mock_try_results)).run() def results_url(build): - return '%s/%s/%s/layout-test-results/results.html' % ( + return '%s/%s/%s/%s/layout-test-results/results.html' % ( 'https://test-results.appspot.com/data/layout_results', build.builder_name, - build.build_number + build.build_number, + 'webkit_layout_tests%20%28with%20patch%29' ) self.assertEqual(host.stdout.getvalue(), '\n'.join([ 'Fetching results...',
diff --git a/third_party/boringssl/ios-aarch64/crypto/fipsmodule/sha1-armv8.S b/third_party/boringssl/ios-aarch64/crypto/fipsmodule/sha1-armv8.S index 61a5a80..17e1a56 100644 --- a/third_party/boringssl/ios-aarch64/crypto/fipsmodule/sha1-armv8.S +++ b/third_party/boringssl/ios-aarch64/crypto/fipsmodule/sha1-armv8.S
@@ -1230,4 +1230,5 @@ .align 2 .align 2 .comm _OPENSSL_armcap_P,4,4 +.private_extern _OPENSSL_armcap_P #endif // !OPENSSL_NO_ASM
diff --git a/third_party/boringssl/ios-aarch64/crypto/fipsmodule/sha256-armv8.S b/third_party/boringssl/ios-aarch64/crypto/fipsmodule/sha256-armv8.S index 08c8ea2c..9076eeb 100644 --- a/third_party/boringssl/ios-aarch64/crypto/fipsmodule/sha256-armv8.S +++ b/third_party/boringssl/ios-aarch64/crypto/fipsmodule/sha256-armv8.S
@@ -1208,5 +1208,6 @@ #endif #ifndef __KERNEL__ .comm _OPENSSL_armcap_P,4,4 +.private_extern _OPENSSL_armcap_P #endif #endif // !OPENSSL_NO_ASM
diff --git a/third_party/boringssl/ios-aarch64/crypto/fipsmodule/sha512-armv8.S b/third_party/boringssl/ios-aarch64/crypto/fipsmodule/sha512-armv8.S index 0343672..d4fd317 100644 --- a/third_party/boringssl/ios-aarch64/crypto/fipsmodule/sha512-armv8.S +++ b/third_party/boringssl/ios-aarch64/crypto/fipsmodule/sha512-armv8.S
@@ -1080,5 +1080,6 @@ .align 2 #ifndef __KERNEL__ .comm _OPENSSL_armcap_P,4,4 +.private_extern _OPENSSL_armcap_P #endif #endif // !OPENSSL_NO_ASM
diff --git a/third_party/boringssl/linux-aarch64/crypto/fipsmodule/sha1-armv8.S b/third_party/boringssl/linux-aarch64/crypto/fipsmodule/sha1-armv8.S index 5cd02b7..3b6cf6a 100644 --- a/third_party/boringssl/linux-aarch64/crypto/fipsmodule/sha1-armv8.S +++ b/third_party/boringssl/linux-aarch64/crypto/fipsmodule/sha1-armv8.S
@@ -1231,5 +1231,6 @@ .align 2 .align 2 .comm OPENSSL_armcap_P,4,4 +.hidden OPENSSL_armcap_P #endif #endif // !OPENSSL_NO_ASM
diff --git a/third_party/boringssl/linux-aarch64/crypto/fipsmodule/sha256-armv8.S b/third_party/boringssl/linux-aarch64/crypto/fipsmodule/sha256-armv8.S index aefcc88..8bb535c 100644 --- a/third_party/boringssl/linux-aarch64/crypto/fipsmodule/sha256-armv8.S +++ b/third_party/boringssl/linux-aarch64/crypto/fipsmodule/sha256-armv8.S
@@ -1209,6 +1209,7 @@ #endif #ifndef __KERNEL__ .comm OPENSSL_armcap_P,4,4 +.hidden OPENSSL_armcap_P #endif #endif #endif // !OPENSSL_NO_ASM
diff --git a/third_party/boringssl/linux-aarch64/crypto/fipsmodule/sha512-armv8.S b/third_party/boringssl/linux-aarch64/crypto/fipsmodule/sha512-armv8.S index 18f909a..ac9d5f0 100644 --- a/third_party/boringssl/linux-aarch64/crypto/fipsmodule/sha512-armv8.S +++ b/third_party/boringssl/linux-aarch64/crypto/fipsmodule/sha512-armv8.S
@@ -1081,6 +1081,7 @@ .align 2 #ifndef __KERNEL__ .comm OPENSSL_armcap_P,4,4 +.hidden OPENSSL_armcap_P #endif #endif #endif // !OPENSSL_NO_ASM
diff --git a/tools/metrics/actions/actions.xml b/tools/metrics/actions/actions.xml index 9c28d79..532fa1b 100644 --- a/tools/metrics/actions/actions.xml +++ b/tools/metrics/actions/actions.xml
@@ -5728,6 +5728,11 @@ <description>User saw the UwS (harmful) interstitial.</description> </action> +<action name="HatsBubble.Show"> + <owner>jeffreycohen@chromium.org</owner> + <description>User saw a Happiness Tracking Survey.</description> +</action> + <action name="HiliteColor"> <owner>Please list the metric's owners. Add more owner tags as needed.</owner> <description>Please enter the description of this user action.</description>
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml index ff1f339..235b634 100644 --- a/tools/metrics/histograms/enums.xml +++ b/tools/metrics/histograms/enums.xml
@@ -9536,6 +9536,13 @@ <int value="3" label="Connected to service with KeepAlive connection"/> </enum> +<enum name="CustomTabsDynamicModuleDestructionReason"> + <int value="0" label="No caching enabled and the module is unused"/> + <int value="1" label="Cached and severe memory pressure"/> + <int value="2" label="Cached and mild memory pressure and time exceeded"/> + <int value="3" label="Cached and app hidden and time exceeded"/> +</enum> + <enum name="CustomTabsDynamicModuleLoadResult"> <int value="0" label="Loaded new instance successfully"/> <int value="1" label="Used cached instance"/> @@ -14665,6 +14672,7 @@ <int value="486" label="WebUsbAllowDevicesForUrls"/> <int value="487" label="BrowserSignin"/> <int value="488" label="SmartLockSigninAllowed"/> + <int value="489" label="NTLMShareAuthenticationEnabled"/> </enum> <enum name="EnterprisePolicyInvalidations"> @@ -20399,6 +20407,8 @@ <int value="2588" label="GetComputedStyleForWebkitAppearance"/> <int value="2589" label="CursorImageLE32x32"/> <int value="2590" label="CursorImageGT32x32"/> + <int value="2591" + label="RTCPeerConnectionComplexPlanBSdpUsingDefaultSdpSemantics"/> </enum> <enum name="FeaturePolicyFeature"> @@ -29022,6 +29032,8 @@ <int value="-1426150007" label="ignore-previews-blacklist"/> <int value="-1426034869" label="NoCreditCardAbort:enabled"/> <int value="-1423348289" label="NupPrinting:disabled"/> + <int value="-1423193305" + label="AutofillRationalizeRepeatedServerPredictions:enabled"/> <int value="-1420542268" label="AutofillEnableAccountWalletStorage:disabled"/> <int value="-1419788257" label="enable-experimental-hotwording"/> <int value="-1417122729" @@ -29057,6 +29069,7 @@ label="ServiceWorkerImportedScriptUpdateCheck:disabled"/> <int value="-1365503870" label="enable-simplified-fullscreen-ui"/> <int value="-1363709707" label="MaterialDesignHistory:disabled"/> + <int value="-1361493814" label="FCMInvalidations:disabled"/> <int value="-1358669137" label="enable-supervised-user-blacklist"/> <int value="-1357778876" label="ExplicitLanguageAsk:enabled"/> <int value="-1357655121" label="enable-iframe-based-signin"/> @@ -29291,6 +29304,8 @@ <int value="-933377608" label="OmniboxUIExperimentHideSteadyStateUrlScheme:enabled"/> <int value="-933316841" label="enable-permissions-blacklist"/> + <int value="-929944930" + label="AutofillRationalizeRepeatedServerPredictions:disabled"/> <int value="-928138978" label="IPH_DemoMode:disabled"/> <int value="-926422468" label="disable-embedded-shared-worker"/> <int value="-920204598" label="ScrollAnchorSerialization:enabled"/> @@ -29882,6 +29897,7 @@ <int value="292560715" label="ViewsCastDialog:disabled"/> <int value="293134455" label="AutofillSendBillingCustomerNumber:disabled"/> <int value="293996306" label="ArrayPrototypeValues:disabled"/> + <int value="300095239" label="FCMInvalidations:enabled"/> <int value="301869874" label="NTPPhysicalWebPageSuggestions:disabled"/> <int value="303058039" label="AccountConsistency:disabled"/> <int value="303252119" label="AutofillExpandedPopupViews:disabled"/>
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml index b4e3efc..9a6638ce 100644 --- a/tools/metrics/histograms/histograms.xml +++ b/tools/metrics/histograms/histograms.xml
@@ -654,8 +654,25 @@ </summary> </histogram> +<histogram name="Ads.ResourceUsage.Size.Cache" units="KB" + expires_after="2019-10-02"> + <owner>johnidel@chromium.org</owner> + <owner>jkarlin@chromium.org</owner> + <summary> + For a given resource fetched from the disk cache, logs the encoded body + length of the resource, even if the resource request was canceled or + incomplete. Recorded when the resource request is complete, or when the page + is destroyed/navigated for incomplete resources. + </summary> +</histogram> + <histogram name="Ads.ResourceUsage.Size.Mainframe.AdResource" units="KB" expires_after="2019-09-05"> + <obsolete> + Deprecated 10/2018. Replaced with + Ads.ResourceUsage.Size.Network.Mainframe.AdResource and + Ads.ResourceUsage.Size.Cache.Mainframe.AdResource. + </obsolete> <owner>jkarlin@chromium.org</owner> <owner>johnidel@chromium.org</owner> <summary> @@ -666,6 +683,11 @@ <histogram name="Ads.ResourceUsage.Size.Mainframe.VanillaResource" units="KB" expires_after="2019-09-05"> + <obsolete> + Deprecated 10/2018. Replaced with + Ads.ResourceUsage.Size.Network.Mainframe.VanillaResource and + Ads.ResourceUsage.Size.Cache.Mainframe.VanillaResource. + </obsolete> <owner>jkarlin@chromium.org</owner> <owner>johnidel@chromium.org</owner> <summary> @@ -677,6 +699,10 @@ <histogram base="true" name="Ads.ResourceUsage.Size.Mime" units="KB" expires_after="2019-09-10"> + <obsolete> + Deprecated 10/2018. Replaced with Ads.ResourceUsage.Size.Cache.Mime and + Ads.ResourceUsage.Size.Network.Mime. + </obsolete> <owner>johnidel@chromium.org</owner> <owner>jkarlin@chromium.org</owner> <summary> @@ -687,8 +713,25 @@ </summary> </histogram> +<histogram name="Ads.ResourceUsage.Size.Network" units="KB" + expires_after="2019-10-02"> + <owner>johnidel@chromium.org</owner> + <owner>jkarlin@chromium.org</owner> + <summary> + For a given resource fetched from the network, logs the network bytes used + to load the resource (including headers), even if the resource request was + canceled or incomplete. Recorded when the resource request is complete, or + when the page is destroyed/navigated for incomplete resources. + </summary> +</histogram> + <histogram name="Ads.ResourceUsage.Size.Subframe.AdResource" units="KB" expires_after="2019-09-05"> + <obsolete> + Deprecated 10/2018. Replaced with + Ads.ResourceUsage.Size.Network.Subframe.AdResource and + Ads.ResourceUsage.Size.Cache.Subframe.AdResource. + </obsolete> <owner>jkarlin@chromium.org</owner> <owner>johnidel@chromium.org</owner> <summary> @@ -699,6 +742,11 @@ <histogram name="Ads.ResourceUsage.Size.Subframe.VanillaResource" units="KB" expires_after="2019-09-05"> + <obsolete> + Deprecated 10/2018. Replaced with + Ads.ResourceUsage.Size.Network.Subframe.VanillaResource and + Ads.ResourceUsage.Size.Cache.Subframe.VanillaResource. + </obsolete> <owner>jkarlin@chromium.org</owner> <owner>johnidel@chromium.org</owner> <summary> @@ -16658,6 +16706,14 @@ </summary> </histogram> +<histogram name="CustomTabs.DynamicModule.DestructionReason" + enum="CustomTabsDynamicModuleDestructionReason" expires_after="2019-07-01"> + <owner>mvanouwerkerk@chromium.org</owner> + <summary> + Possible reasons for destroying a custom tabs dynamic module. Android only. + </summary> +</histogram> + <histogram name="CustomTabs.DynamicModule.EntryPointLoadClassTime" units="ms"> <owner>mvanouwerkerk@chromium.org</owner> <summary> @@ -74077,6 +74133,56 @@ </summary> </histogram> +<histogram name="PasswordManager.StorePerformance.AddLogin" + expires_after="2019-03-01"> + <owner>cfroussios@chromium.org</owner> + <owner>dvadym@chromium.org</owner> + <summary> + The time (ms) it takes for the synchronous part of the AddLogin on the + PasswordStore to complete. + </summary> +</histogram> + +<histogram name="PasswordManager.StorePerformance.GetLogin" + expires_after="2019-03-01"> + <owner>cfroussios@chromium.org</owner> + <owner>dvadym@chromium.org</owner> + <summary> + The time (ms) it takes for the synchronous part of the GetLogin on the + PasswordStore to complete. + </summary> +</histogram> + +<histogram name="PasswordManager.StorePerformance.GetLogins" + expires_after="2019-03-01"> + <owner>cfroussios@chromium.org</owner> + <owner>dvadym@chromium.org</owner> + <summary> + The time (ms) it takes for the synchronous part of the GetLogins on the + PasswordStore to complete. + </summary> +</histogram> + +<histogram name="PasswordManager.StorePerformance.RemoveLogin" + expires_after="2019-03-01"> + <owner>cfroussios@chromium.org</owner> + <owner>dvadym@chromium.org</owner> + <summary> + The time (ms) it takes for the synchronous part of the RemoveLogin on the + PasswordStore to complete. + </summary> +</histogram> + +<histogram name="PasswordManager.StorePerformance.UpdateLogin" + expires_after="2019-03-01"> + <owner>cfroussios@chromium.org</owner> + <owner>dvadym@chromium.org</owner> + <summary> + The time (ms) it takes for the synchronous part of the UpdateLogin on the + PasswordStore to complete. + </summary> +</histogram> + <histogram name="PasswordManager.StoreReadyWhenWiping" enum="Boolean"> <obsolete> Deprecated since August 28, 2018, due to removing the corresponding feature. @@ -81633,6 +81739,50 @@ </summary> </histogram> +<histogram name="Previews.OptimizationGuide.HintCache.HasHint.AtCommit" + enum="NQEEffectiveConnectionType"> + <owner>dougarnett@chromium.org</owner> + <summary> + Records the effective connection type when the optimization guide hint cache + has a hint entry for a URL's host at commit time. + </summary> +</histogram> + +<histogram name="Previews.OptimizationGuide.HintCache.HasHint.BeforeCommit" + enum="NQEEffectiveConnectionType"> + <owner>dougarnett@chromium.org</owner> + <summary> + Records the effective connection type when the optimization guide hint cache + has a hint entry for a URL's host before commit time (e.g., at original + navigation time or redirected navigation time). + </summary> +</histogram> + +<histogram name="Previews.OptimizationGuide.HintCache.HostMatch.AtCommit" + enum="NQEEffectiveConnectionType"> + <owner>dougarnett@chromium.org</owner> + <summary> + Records the effective connection type when the optimization guide hint cache + has a loaded hint entry matching a URL's host at commit time. This is + recorded regardless of whether an associated preview type is allowed for the + navigation or not. If no associated preview type is allowed, the hint will + not be loaded from a backing store, so this will only capture matches for + in-memory hints. + </summary> +</histogram> + +<histogram name="Previews.OptimizationGuide.HintCache.PageMatch.AtCommit" + enum="NQEEffectiveConnectionType"> + <owner>dougarnett@chromium.org</owner> + <summary> + Records the effective connection type when the optimization guide hint cache + has a loaded page hint for a URL at commit time. This is recorded regardless + of whether an associated preview type is allowed for the navigation or not. + If no associated preview type is allowed, the hint will not be loaded from a + backing store, so this will only capture matches for in-memory hints. + </summary> +</histogram> + <histogram name="Previews.OptOut.DBRowCount" units="rows"> <obsolete> No longer used as of 06/2018. @@ -121610,7 +121760,24 @@ label="Resources identified by any mime type that did match any supported css, html, image, javascript, or video mime types."/> <suffix name="Video" label="Resources identified by video/*."/> + <affected-histogram name="Ads.ResourceUsage.Size.Cache.Mime"/> <affected-histogram name="Ads.ResourceUsage.Size.Mime"/> + <affected-histogram name="Ads.ResourceUsage.Size.Network.Mime"/> +</histogram_suffixes> + +<histogram_suffixes name="AdResourceSizes" separator="."> + <suffix name="Mainframe.AdResource" + label="Mainframe resources tagged as ads."/> + <suffix name="Mainframe.VanillaResource" + label="Mainframe resources not tagged as ads."/> + <suffix base="true" name="Mime" + label="Size of ad resources identified by the response header mime + type."/> + <suffix name="Subframe.AdResource" label="Subframe resources tagged as ads."/> + <suffix name="Subframe.VanillaResource" + label="Subframe resources not tagged as ads."/> + <affected-histogram name="Ads.ResourceUsage.Size.Cache"/> + <affected-histogram name="Ads.ResourceUsage.Size.Network"/> </histogram_suffixes> <histogram_suffixes name="AdsPageLoadMetrics" separator="." ordering="prefix">
diff --git a/tools/perf/page_sets/data/credentials.json.sha1 b/tools/perf/page_sets/data/credentials.json.sha1 index f4677d0..177cf291 100644 --- a/tools/perf/page_sets/data/credentials.json.sha1 +++ b/tools/perf/page_sets/data/credentials.json.sha1
@@ -1 +1 @@ -62bb07f739452c44b3618b9b3f3de6251bf73322 \ No newline at end of file +38f6afad3baf96684730bf307244fc7fa6bd6f7d \ No newline at end of file
diff --git a/tools/perf/page_sets/data/system_health_desktop.json b/tools/perf/page_sets/data/system_health_desktop.json index dfa2eff9..5849d951 100644 --- a/tools/perf/page_sets/data/system_health_desktop.json +++ b/tools/perf/page_sets/data/system_health_desktop.json
@@ -12,6 +12,9 @@ "browse:media:tumblr": { "DEFAULT": "system_health_desktop_036.wprgo" }, + "browse:media:tumblr:2018": { + "DEFAULT": "system_health_desktop_55cb9dd713.wprgo" + }, "browse:media:youtube": { "DEFAULT": "system_health_desktop_026.wprgo", "linux": "system_health_desktop_026.wprgo",
diff --git a/tools/perf/page_sets/data/system_health_desktop_55cb9dd713.wprgo.sha1 b/tools/perf/page_sets/data/system_health_desktop_55cb9dd713.wprgo.sha1 new file mode 100644 index 0000000..7be67b22 --- /dev/null +++ b/tools/perf/page_sets/data/system_health_desktop_55cb9dd713.wprgo.sha1
@@ -0,0 +1 @@ +55cb9dd71364f014e51f4ed50207ac91820a555d \ No newline at end of file
diff --git a/tools/perf/page_sets/login_helpers/tumblr_login.py b/tools/perf/page_sets/login_helpers/tumblr_login.py new file mode 100644 index 0000000..5eff8533 --- /dev/null +++ b/tools/perf/page_sets/login_helpers/tumblr_login.py
@@ -0,0 +1,31 @@ +# 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. + +from page_sets.login_helpers import login_utils + + +def LoginDesktopAccount(action_runner, credential, + credentials_path=login_utils.DEFAULT_CREDENTIAL_PATH): + """Logs in into a Tumblr account.""" + + account_name, password = login_utils.GetAccountNameAndPassword( + credential, credentials_path=credentials_path) + + action_runner.Navigate('https://www.tumblr.com/login') + login_utils.InputWithSelector( + action_runner, account_name, 'input[type=email]') + + next_button = '.signup_determine_btn' + enter_password_button = '.forgot_password_link' + action_runner.WaitForElement(selector=next_button) + action_runner.ClickElement(selector=next_button) + action_runner.Wait(1) + action_runner.WaitForElement(selector=enter_password_button) + action_runner.ClickElement(selector=enter_password_button) + action_runner.Wait(1) + login_utils.InputWithSelector( + action_runner, password, 'input[type=password]') + action_runner.Wait(1) + action_runner.WaitForElement(selector=next_button) + action_runner.ClickElement(selector=next_button)
diff --git a/tools/perf/page_sets/system_health/browsing_stories.py b/tools/perf/page_sets/system_health/browsing_stories.py index b5886e05..7838b30 100644 --- a/tools/perf/page_sets/system_health/browsing_stories.py +++ b/tools/perf/page_sets/system_health/browsing_stories.py
@@ -15,6 +15,7 @@ from page_sets.login_helpers import facebook_login from page_sets.login_helpers import pinterest_login +from page_sets.login_helpers import tumblr_login from telemetry.util import js_template @@ -592,6 +593,28 @@ action_runner.MouseClick(selector='#tumblr_lightbox_center_image') action_runner.Wait(1) # To make browsing more realistic. + +class TumblrDesktopStory2018(_MediaBrowsingStory): + NAME = 'browse:media:tumblr:2018' + URL = 'https://tumblr.com/search/gifs' + ITEM_SELECTOR = '.post_media' + IS_SINGLE_PAGE_APP = True + ITEMS_TO_VISIT = 8 + INCREMENT_INDEX_AFTER_EACH_ITEM = True + SUPPORTED_PLATFORMS = platforms.DESKTOP_ONLY + TAGS = [story_tags.YEAR_2018] + + def _Login(self, action_runner): + tumblr_login.LoginDesktopAccount(action_runner, 'tumblr') + action_runner.Wait(3) + + def _ViewMediaItem(self, action_runner, index): + super(TumblrDesktopStory2018, self)._ViewMediaItem(action_runner, index) + action_runner.WaitForElement(selector='#tumblr_lightbox') + action_runner.MouseClick(selector='#tumblr_lightbox') + action_runner.Wait(1) # To make browsing more realistic. + + class PinterestDesktopStory(_MediaBrowsingStory): NAME = 'browse:media:pinterest' URL = 'https://pinterest.com'
diff --git a/ui/android/java/res/drawable-hdpi/dropdown_popup_background_down.9.png b/ui/android/java/res/drawable-hdpi/dropdown_popup_background_down.9.png deleted file mode 100644 index acaa8a76..0000000 --- a/ui/android/java/res/drawable-hdpi/dropdown_popup_background_down.9.png +++ /dev/null Binary files differ
diff --git a/ui/android/java/res/drawable-hdpi/dropdown_popup_background_up.9.png b/ui/android/java/res/drawable-hdpi/dropdown_popup_background_up.9.png deleted file mode 100644 index 6d78622..0000000 --- a/ui/android/java/res/drawable-hdpi/dropdown_popup_background_up.9.png +++ /dev/null Binary files differ
diff --git a/chrome/android/java/res/drawable-hdpi/popup_bg.9.png b/ui/android/java/res/drawable-hdpi/popup_bg.9.png similarity index 100% rename from chrome/android/java/res/drawable-hdpi/popup_bg.9.png rename to ui/android/java/res/drawable-hdpi/popup_bg.9.png Binary files differ
diff --git a/ui/android/java/res/drawable-mdpi/dropdown_popup_background_down.9.png b/ui/android/java/res/drawable-mdpi/dropdown_popup_background_down.9.png deleted file mode 100644 index 761e9042..0000000 --- a/ui/android/java/res/drawable-mdpi/dropdown_popup_background_down.9.png +++ /dev/null Binary files differ
diff --git a/ui/android/java/res/drawable-mdpi/dropdown_popup_background_up.9.png b/ui/android/java/res/drawable-mdpi/dropdown_popup_background_up.9.png deleted file mode 100644 index 9c16993b..0000000 --- a/ui/android/java/res/drawable-mdpi/dropdown_popup_background_up.9.png +++ /dev/null Binary files differ
diff --git a/chrome/android/java/res/drawable-mdpi/popup_bg.9.png b/ui/android/java/res/drawable-mdpi/popup_bg.9.png similarity index 100% rename from chrome/android/java/res/drawable-mdpi/popup_bg.9.png rename to ui/android/java/res/drawable-mdpi/popup_bg.9.png Binary files differ
diff --git a/ui/android/java/res/drawable-xhdpi/dropdown_popup_background_down.9.png b/ui/android/java/res/drawable-xhdpi/dropdown_popup_background_down.9.png deleted file mode 100644 index ac01821e..0000000 --- a/ui/android/java/res/drawable-xhdpi/dropdown_popup_background_down.9.png +++ /dev/null Binary files differ
diff --git a/ui/android/java/res/drawable-xhdpi/dropdown_popup_background_up.9.png b/ui/android/java/res/drawable-xhdpi/dropdown_popup_background_up.9.png deleted file mode 100644 index 22a58985..0000000 --- a/ui/android/java/res/drawable-xhdpi/dropdown_popup_background_up.9.png +++ /dev/null Binary files differ
diff --git a/chrome/android/java/res/drawable-xhdpi/popup_bg.9.png b/ui/android/java/res/drawable-xhdpi/popup_bg.9.png similarity index 100% rename from chrome/android/java/res/drawable-xhdpi/popup_bg.9.png rename to ui/android/java/res/drawable-xhdpi/popup_bg.9.png Binary files differ
diff --git a/chrome/android/java/res/drawable-xxhdpi/popup_bg.9.png b/ui/android/java/res/drawable-xxhdpi/popup_bg.9.png similarity index 100% rename from chrome/android/java/res/drawable-xxhdpi/popup_bg.9.png rename to ui/android/java/res/drawable-xxhdpi/popup_bg.9.png Binary files differ
diff --git a/chrome/android/java/res/drawable-xxxhdpi/popup_bg.9.png b/ui/android/java/res/drawable-xxxhdpi/popup_bg.9.png similarity index 100% rename from chrome/android/java/res/drawable-xxxhdpi/popup_bg.9.png rename to ui/android/java/res/drawable-xxxhdpi/popup_bg.9.png Binary files differ
diff --git a/ui/android/java/res/drawable/dropdown_popup_background.xml b/ui/android/java/res/drawable/dropdown_popup_background.xml deleted file mode 100644 index 71b5271..0000000 --- a/ui/android/java/res/drawable/dropdown_popup_background.xml +++ /dev/null
@@ -1,13 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> - -<!-- Copyright 2014 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. ---> - -<selector xmlns:android="http://schemas.android.com/apk/res/android"> - <item android:state_above_anchor="true" - android:drawable="@drawable/dropdown_popup_background_up" /> - <item android:drawable="@drawable/dropdown_popup_background_down" /> -</selector> \ No newline at end of file
diff --git a/ui/android/java/res/values-v17/styles.xml b/ui/android/java/res/values-v17/styles.xml index a6cf073..2b9701f 100644 --- a/ui/android/java/res/values-v17/styles.xml +++ b/ui/android/java/res/values-v17/styles.xml
@@ -8,7 +8,7 @@ <resources xmlns:tools="http://schemas.android.com/tools"> <style name="DropdownPopupWindow" parent="@android:style/Widget.ListPopupWindow"> - <item name="android:popupBackground">@drawable/dropdown_popup_background</item> + <item name="android:popupBackground">@drawable/popup_bg</item> </style> <!-- Buttons -->
diff --git a/ui/android/java/res/values/dimens.xml b/ui/android/java/res/values/dimens.xml index 7df5398..e1768773 100644 --- a/ui/android/java/res/values/dimens.xml +++ b/ui/android/java/res/values/dimens.xml
@@ -19,6 +19,8 @@ <dimen name="dropdown_item_label_margin">10dp</dimen> <dimen name="dropdown_icon_margin">8dp</dimen> <dimen name="dropdown_vertical_margin">4dp</dimen> + <dimen name="dropdown_elevation">2dp</dimen> + <dimen name="button_compat_corner_radius">4dp</dimen> <!-- Divider Dimensions -->
diff --git a/ui/android/java/src/org/chromium/ui/ContactsPickerListener.java b/ui/android/java/src/org/chromium/ui/ContactsPickerListener.java index ed573c5..4b98a38 100644 --- a/ui/android/java/src/org/chromium/ui/ContactsPickerListener.java +++ b/ui/android/java/src/org/chromium/ui/ContactsPickerListener.java
@@ -4,6 +4,11 @@ package org.chromium.ui; +import android.support.annotation.IntDef; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + /** * The callback used to indicate what action the user took in the picker. */ @@ -11,11 +16,15 @@ /** * The action the user took in the picker. */ - enum ContactsPickerAction { - CANCEL, - CONTACTS_SELECTED, - SELECT_ALL, - UNDO_SELECT_ALL, + @IntDef({ContactsPickerAction.CANCEL, ContactsPickerAction.CONTACTS_SELECTED, + ContactsPickerAction.SELECT_ALL, ContactsPickerAction.UNDO_SELECT_ALL}) + @Retention(RetentionPolicy.SOURCE) + public @interface ContactsPickerAction { + int CANCEL = 0; + int CONTACTS_SELECTED = 1; + int SELECT_ALL = 2; + int UNDO_SELECT_ALL = 3; + int NUM_ENTRIES = 4; } /** @@ -23,5 +32,5 @@ * * @param contacts The contacts that were selected (string contains json format). */ - void onContactsPickerUserAction(ContactsPickerAction action, String contacts); + void onContactsPickerUserAction(@ContactsPickerAction int action, String contacts); }
diff --git a/ui/android/java/src/org/chromium/ui/DropdownPopupWindowImpl.java b/ui/android/java/src/org/chromium/ui/DropdownPopupWindowImpl.java index 2f0465f..b24a8b57 100644 --- a/ui/android/java/src/org/chromium/ui/DropdownPopupWindowImpl.java +++ b/ui/android/java/src/org/chromium/ui/DropdownPopupWindowImpl.java
@@ -82,12 +82,14 @@ ViewRectProvider rectProvider = new ViewRectProvider(mAnchorView); rectProvider.setIncludePadding(true); - mBackground = ApiCompatibilityUtils.getDrawable( - context.getResources(), R.drawable.dropdown_popup_background); + mBackground = + ApiCompatibilityUtils.getDrawable(context.getResources(), R.drawable.popup_bg); mAnchoredPopupWindow = new AnchoredPopupWindow( context, mAnchorView, mBackground, mContentView, rectProvider); mAnchoredPopupWindow.addOnDismissListener(onDismissLitener); mAnchoredPopupWindow.setLayoutObserver(this); + mAnchoredPopupWindow.setElevation( + context.getResources().getDimensionPixelSize(R.dimen.dropdown_elevation)); Rect paddingRect = new Rect(); mBackground.getPadding(paddingRect); rectProvider.setInsetPx(0, /* top= */ paddingRect.bottom, 0, /* bottom= */ paddingRect.top); @@ -115,11 +117,8 @@ public void onPreLayoutChange( boolean positionBelow, int x, int y, int width, int height, Rect anchorRect) { mBackground.setBounds(anchorRect); - mAnchoredPopupWindow.setBackgroundDrawable(positionBelow - ? ApiCompatibilityUtils.getDrawable(mContext.getResources(), - R.drawable.dropdown_popup_background_down) - : ApiCompatibilityUtils.getDrawable(mContext.getResources(), - R.drawable.dropdown_popup_background_up)); + mAnchoredPopupWindow.setBackgroundDrawable( + ApiCompatibilityUtils.getDrawable(mContext.getResources(), R.drawable.popup_bg)); } /**
diff --git a/ui/android/java/src/org/chromium/ui/PhotoPickerListener.java b/ui/android/java/src/org/chromium/ui/PhotoPickerListener.java index 1bc82eb..7dbc7d849 100644 --- a/ui/android/java/src/org/chromium/ui/PhotoPickerListener.java +++ b/ui/android/java/src/org/chromium/ui/PhotoPickerListener.java
@@ -4,6 +4,11 @@ package org.chromium.ui; +import android.support.annotation.IntDef; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + /** * The callback used to indicate what action the user took in the picker. */ @@ -11,11 +16,15 @@ /** * The action the user took in the picker. */ - enum Action { - CANCEL, - PHOTOS_SELECTED, - LAUNCH_CAMERA, - LAUNCH_GALLERY, + @IntDef({PhotoPickerAction.CANCEL, PhotoPickerAction.PHOTOS_SELECTED, + PhotoPickerAction.LAUNCH_CAMERA, PhotoPickerAction.LAUNCH_GALLERY}) + @Retention(RetentionPolicy.SOURCE) + public @interface PhotoPickerAction { + int CANCEL = 0; + int PHOTOS_SELECTED = 1; + int LAUNCH_CAMERA = 2; + int LAUNCH_GALLERY = 3; + int NUM_ENTRIES = 4; } /** @@ -29,5 +38,5 @@ * * @param photos The photos that were selected. */ - void onPhotoPickerUserAction(Action action, String[] photos); + void onPhotoPickerUserAction(@PhotoPickerAction int action, String[] photos); }
diff --git a/ui/android/java/src/org/chromium/ui/base/SelectFileDialog.java b/ui/android/java/src/org/chromium/ui/base/SelectFileDialog.java index bbce4492..4ae79ed 100644 --- a/ui/android/java/src/org/chromium/ui/base/SelectFileDialog.java +++ b/ui/android/java/src/org/chromium/ui/base/SelectFileDialog.java
@@ -373,13 +373,13 @@ } @Override - public void onPhotoPickerUserAction(Action action, String[] photos) { + public void onPhotoPickerUserAction(@PhotoPickerAction int action, String[] photos) { switch (action) { - case CANCEL: + case PhotoPickerAction.CANCEL: onFileNotSelected(); break; - case PHOTOS_SELECTED: + case PhotoPickerAction.PHOTOS_SELECTED: if (photos.length == 0) { onFileNotSelected(); return; @@ -402,7 +402,7 @@ } break; - case LAUNCH_GALLERY: + case PhotoPickerAction.LAUNCH_GALLERY: Intent intent = new Intent(); intent.setType("image/*"); if (mAllowMultiple) intent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true); @@ -410,7 +410,7 @@ mWindowAndroid.showCancelableIntent(intent, this, R.string.low_memory_error); break; - case LAUNCH_CAMERA: + case PhotoPickerAction.LAUNCH_CAMERA: if (!mWindowAndroid.hasPermission(Manifest.permission.CAMERA)) { mWindowAndroid.requestPermissions(new String[] {Manifest.permission.CAMERA}, (permissions, grantResults) -> { @@ -431,18 +431,18 @@ } @Override - public void onContactsPickerUserAction(ContactsPickerAction action, String contacts) { + public void onContactsPickerUserAction(@ContactsPickerAction int action, String contacts) { switch (action) { - case CANCEL: + case ContactsPickerAction.CANCEL: onFileNotSelected(); break; - case CONTACTS_SELECTED: + case ContactsPickerAction.CONTACTS_SELECTED: nativeOnContactsSelected(mNativeSelectFileDialog, contacts); break; - case SELECT_ALL: - case UNDO_SELECT_ALL: + case ContactsPickerAction.SELECT_ALL: + case ContactsPickerAction.UNDO_SELECT_ALL: break; } }
diff --git a/ui/android/java/src/org/chromium/ui/widget/AnchoredPopupWindow.java b/ui/android/java/src/org/chromium/ui/widget/AnchoredPopupWindow.java index 14d2a38..bad9968 100644 --- a/ui/android/java/src/org/chromium/ui/widget/AnchoredPopupWindow.java +++ b/ui/android/java/src/org/chromium/ui/widget/AnchoredPopupWindow.java
@@ -20,6 +20,7 @@ import android.widget.PopupWindow; import android.widget.PopupWindow.OnDismissListener; +import org.chromium.base.ApiCompatibilityUtils; import org.chromium.base.ObserverList; import org.chromium.base.VisibleForTesting; @@ -344,6 +345,13 @@ mPopupWindow.setBackgroundDrawable(background); } + /** + * Sets the elevation of the popup, if elevation is supported. + */ + public void setElevation(float elevation) { + ApiCompatibilityUtils.setElevation(mPopupWindow, elevation); + } + // RectProvider.Observer implementation. @Override public void onRectChanged() {
diff --git a/ui/base/BUILD.gn b/ui/base/BUILD.gn index b7d2daf..1e2170e 100644 --- a/ui/base/BUILD.gn +++ b/ui/base/BUILD.gn
@@ -28,7 +28,7 @@ # # Introduce a standalone target that can build on both 'host' and 'target' # toolchains that just builds the support to load datapacks. The dependencies -# should be kept minimal to have to build too many targets with multiple +# should be kept minimal to not have to build too many targets with multiple # toolchains. component("ui_data_pack") { sources = [ @@ -46,8 +46,11 @@ defines = [ "UI_DATA_PACK_IMPLEMENTATION" ] - # TODO(jschuh): crbug.com/167187 fix size_t to int truncations. - configs += [ "//build/config/compiler:no_size_t_to_int_warning" ] + configs += [ + # TODO(jschuh): crbug.com/167187 fix size_t to int truncations. + "//build/config/compiler:no_size_t_to_int_warning", + "//build/config/compiler:wexit_time_destructors", + ] } buildflag_header("ui_features") { @@ -399,8 +402,11 @@ ] } - # TODO(jschuh): crbug.com/167187 fix size_t to int truncations. - configs += [ "//build/config/compiler:no_size_t_to_int_warning" ] + configs += [ + # TODO(jschuh): crbug.com/167187 fix size_t to int truncations. + "//build/config/compiler:no_size_t_to_int_warning", + "//build/config/compiler:wexit_time_destructors", + ] defines = [ "UI_BASE_IMPLEMENTATION" ]
diff --git a/ui/base/resource/resource_bundle.cc b/ui/base/resource/resource_bundle.cc index 2a00d4e8..71a367e0 100644 --- a/ui/base/resource/resource_bundle.cc +++ b/ui/base/resource/resource_bundle.cc
@@ -750,7 +750,7 @@ void ResourceBundle::InitSharedInstance(Delegate* delegate) { DCHECK(g_shared_instance_ == NULL) << "ResourceBundle initialized twice"; g_shared_instance_ = new ResourceBundle(delegate); - static std::vector<ScaleFactor> supported_scale_factors; + std::vector<ScaleFactor> supported_scale_factors; #if defined(OS_IOS) display::Display display = display::Screen::GetScreen()->GetPrimaryDisplay(); if (display.device_scale_factor() > 2.0) {
diff --git a/ui/gfx/codec/chromeos/jpeg_codec_robust_slow.cc b/ui/gfx/codec/chromeos/jpeg_codec_robust_slow.cc index 9ffc036..e029cafe 100644 --- a/ui/gfx/codec/chromeos/jpeg_codec_robust_slow.cc +++ b/ui/gfx/codec/chromeos/jpeg_codec_robust_slow.cc
@@ -140,7 +140,7 @@ #endif // !defined(JCS_EXTENSIONS) // jpeg_decompress_struct Deleter. -struct JpegDecompressStructDeleter { +struct JpegRobustDecompressStructDeleter { void operator()(jpeg_decompress_struct* ptr) { jpeg_destroy_decompress(ptr); delete ptr; @@ -155,8 +155,8 @@ std::vector<unsigned char>* output, int* w, int* h) { - std::unique_ptr<jpeg_decompress_struct, JpegDecompressStructDeleter> cinfo( - new jpeg_decompress_struct); + std::unique_ptr<jpeg_decompress_struct, JpegRobustDecompressStructDeleter> + cinfo(new jpeg_decompress_struct); output->clear(); // We set up the normal JPEG error routines, then override error_exit.
diff --git a/ui/gl/gl_context.cc b/ui/gl/gl_context.cc index fed57e1..b268e3d 100644 --- a/ui/gl/gl_context.cc +++ b/ui/gl/gl_context.cc
@@ -194,6 +194,8 @@ } void GLContext::BackpressureFenceWait(uint64_t fence) {} + +void GLContext::FlushForDriverCrashWorkaround() {} #endif bool GLContext::HasExtension(const char* name) {
diff --git a/ui/gl/gl_context.h b/ui/gl/gl_context.h index 9224532..9e38ea80 100644 --- a/ui/gl/gl_context.h +++ b/ui/gl/gl_context.h
@@ -202,6 +202,9 @@ virtual uint64_t BackpressureFenceCreate(); // Perform a client-side wait on a previously-created fence. virtual void BackpressureFenceWait(uint64_t fence); + // Flush the underlying context to avoid crashes due to driver bugs on macOS. + // https://crbug.com/863817 + virtual void FlushForDriverCrashWorkaround(); #endif protected:
diff --git a/ui/gl/gl_context_cgl.cc b/ui/gl/gl_context_cgl.cc index fd9d85f..a563920e 100644 --- a/ui/gl/gl_context_cgl.cc +++ b/ui/gl/gl_context_cgl.cc
@@ -229,8 +229,8 @@ uint64_t GLContextCGL::BackpressureFenceCreate() { TRACE_EVENT0("gpu", "GLContextCGL::BackpressureFenceCreate"); - // This flush may trigger a crash due to driver instability. - // https://crbug.com/863817 + // This flush will trigger a crash if FlushForDriverCrashWorkaround is not + // called sufficiently frequently. glFlush(); if (gl::GLFence::IsSupported()) { @@ -287,6 +287,12 @@ backpressure_fences_.erase(backpressure_fences_.begin()); } +void GLContextCGL::FlushForDriverCrashWorkaround() { + if (!context_ || CGLGetCurrentContext() != context_) + return; + glFlush(); +} + bool GLContextCGL::MakeCurrent(GLSurface* surface) { DCHECK(context_);
diff --git a/ui/gl/gl_context_cgl.h b/ui/gl/gl_context_cgl.h index 6e3c4b1..c0aa656a 100644 --- a/ui/gl/gl_context_cgl.h +++ b/ui/gl/gl_context_cgl.h
@@ -38,6 +38,7 @@ const gfx::ColorSpace& color_space) override; uint64_t BackpressureFenceCreate() override; void BackpressureFenceWait(uint64_t fence) override; + void FlushForDriverCrashWorkaround() override; protected: ~GLContextCGL() override;
diff --git a/ui/views/controls/textfield/textfield.cc b/ui/views/controls/textfield/textfield.cc index 3a9ab8c9..2ff6033 100644 --- a/ui/views/controls/textfield/textfield.cc +++ b/ui/views/controls/textfield/textfield.cc
@@ -151,6 +151,14 @@ return shift ? ui::TextEditCommand::MOVE_TO_END_OF_LINE_AND_MODIFY_SELECTION : ui::TextEditCommand::MOVE_TO_END_OF_LINE; + case ui::VKEY_UP: + return shift ? ui::TextEditCommand:: + MOVE_TO_BEGINNING_OF_LINE_AND_MODIFY_SELECTION + : ui::TextEditCommand::INVALID_COMMAND; + case ui::VKEY_DOWN: + return shift + ? ui::TextEditCommand::MOVE_TO_END_OF_LINE_AND_MODIFY_SELECTION + : ui::TextEditCommand::INVALID_COMMAND; case ui::VKEY_BACK: if (!control) return ui::TextEditCommand::DELETE_BACKWARD;
diff --git a/ui/views/controls/textfield/textfield_unittest.cc b/ui/views/controls/textfield/textfield_unittest.cc index 65f47759..be57d65 100644 --- a/ui/views/controls/textfield/textfield_unittest.cc +++ b/ui/views/controls/textfield/textfield_unittest.cc
@@ -1067,27 +1067,18 @@ textfield_->SetSelectionRange(gfx::Range(6)); - // Shift+[Up/Down] on Mac should execute the command - // MOVE_[UP/DOWN]_AND_MODIFY_SELECTION. On other platforms, textfield won't - // handle these events. + // Shift+[Up/Down] should select the text to the beginning and end of the + // line, respectively. SendKeyEvent(ui::VKEY_UP, true /* shift */, false /* command */); EXPECT_TRUE(textfield_->key_received()); -#if defined(OS_MACOSX) EXPECT_TRUE(textfield_->key_handled()); EXPECT_EQ(gfx::Range(6, 0), textfield_->GetSelectedRange()); -#else - EXPECT_FALSE(textfield_->key_handled()); -#endif textfield_->clear(); SendKeyEvent(ui::VKEY_DOWN, true /* shift */, false /* command */); EXPECT_TRUE(textfield_->key_received()); -#if defined(OS_MACOSX) EXPECT_TRUE(textfield_->key_handled()); EXPECT_EQ(gfx::Range(6, 11), textfield_->GetSelectedRange()); -#else - EXPECT_FALSE(textfield_->key_handled()); -#endif textfield_->clear(); }